‪TYPO3CMS  9.5
PageTypeDecorator.php
Go to the documentation of this file.
1 <?php
2 declare(strict_types = 1);
3 
5 
6 /*
7  * This file is part of the TYPO3 CMS project.
8  *
9  * It is free software; you can redistribute it and/or modify it under
10  * the terms of the GNU General Public License, either version 2
11  * of the License, or any later version.
12  *
13  * For the full copyright and license information, please read the
14  * LICENSE.txt file that was distributed with this source code.
15  *
16  * The TYPO3 project - inspiring people to share!
17  */
18 
21 
38 {
39  protected const ‪ROUTE_PATH_DELIMITERS = ['.', '-', '_', '/'];
40 
44  protected $configuration;
45 
49  protected $default;
50 
54  protected ‪$index;
55 
59  protected ‪$map;
60 
64  public function __construct(array $configuration)
65  {
66  $default = $configuration['default'] ?? '';
67  ‪$index = $configuration['index'] ?? 'index';
68  ‪$map = $configuration['map'] ?? null;
69 
70  if (!is_string($default)) {
71  throw new \InvalidArgumentException('default must be string', 1538327508);
72  }
73  if (!is_string(‪$index)) {
74  throw new \InvalidArgumentException('index must be string', 1538327509);
75  }
76  if (!is_array(‪$map)) {
77  throw new \InvalidArgumentException('map must be array', 1538327510);
78  }
79 
80  $this->‪configuration = $configuration;
81  $this->default = $default;
82  $this->‪index = ‪$index;
83  $this->‪map = array_map('strval', ‪$map);
84  }
85 
89  public function ‪getRoutePathRedecorationPattern(): string
90  {
91  return $this->‪buildRegularExpressionPattern(false);
92  }
93 
97  public function ‪decorateForMatching(‪RouteCollection $collection, string $routePath): void
98  {
99  $decoratedRoutePath = null;
100  $decoratedParameters = null;
101 
102  $pattern = $this->‪buildRegularExpressionPattern();
103  if (preg_match('#(?P<decoration>(?:' . $pattern . '))#', $routePath, $matches, PREG_UNMATCHED_AS_NULL)) {
104  if (!isset($matches['decoration'])) {
105  throw new \UnexpectedValueException(
106  'Unexpected null value at end of URL',
107  1538335671
108  );
109  }
110 
111  $routePathValue = $matches['decoration'];
112  $parameterValue = $matches['indexItems'] ?? $matches['slashedItems'] ?? $matches['regularItems'];
113  $routePathValuePattern = $this->‪quoteForRegularExpressionPattern($routePathValue) . '$';
114  $decoratedRoutePath = preg_replace('#' . $routePathValuePattern . '#', '', $routePath);
115 
116  $mappedType = $this->‪map[$parameterValue];
117  if ($mappedType !== null) {
118  $decoratedParameters = ['type' => $mappedType];
119  } elseif ($this->default === $routePathValue) {
120  $decoratedParameters = ['type' => 0];
121  }
122  }
123 
124  foreach ($collection->all() as $route) {
125  if ($decoratedRoutePath !== null) {
126  $route->setOption(
127  '_decoratedRoutePath',
128  '/' . trim($decoratedRoutePath, '/')
129  );
130  }
131  if ($decoratedParameters !== null) {
132  $route->setOption(
133  '_decoratedParameters',
134  $decoratedParameters
135  );
136  }
137  }
138  }
139 
143  public function ‪decorateForGeneration(‪RouteCollection $collection, array $parameters): void
144  {
145  $type = isset($parameters['type']) ? (string)$parameters['type'] : null;
146  $value = $this->‪resolveValue($type);
147  // If the type is > 0 but the value could not be resolved,
148  // the type is appended as GET argument, which can be resolved already anyway.
149  // This happens when the PageTypeDecorator is used, but hasn't been configured for all available types.
150  if (!empty($type) && ($value === '' || $value === $this->default)) {
151  return;
152  }
153 
154  $considerIndex = $value !== '' && in_array($value[0], static::ROUTE_PATH_DELIMITERS);
155  if ($value !== '' && !in_array($value[0], static::ROUTE_PATH_DELIMITERS)) {
156  $value = '/' . $value;
157  }
158 
163  foreach ($collection->all() as $routeName => $existingRoute) {
164  $existingRoutePath = rtrim($existingRoute->getPath(), '/');
165  if ($considerIndex && $existingRoutePath === '') {
166  $existingRoutePath = ‪$this->index;
167  }
168  $existingRoute->setPath($existingRoutePath . $value);
169  $deflatedParameters = $existingRoute->getOption('deflatedParameters') ?? $parameters;
170  if (isset($deflatedParameters['type'])) {
171  unset($deflatedParameters['type']);
172  $existingRoute->setOption(
173  'deflatedParameters',
174  $deflatedParameters
175  );
176  }
177  }
178  }
179 
186  protected function ‪resolveValue(?string $type): string
187  {
188  ‪$index = array_search($type, $this->‪map, true);
189  if ($index !== false) {
190  return ‪$index;
191  }
192  return $this->default;
193  }
194 
201  protected function ‪buildRegularExpressionPattern(bool $useNames = true): string
202  {
203  $items = array_keys($this->‪map);
204  if ($this->default !== '' && !in_array($this->default, $items, true)) {
205  $items[] = $this->default;
206  }
207  $slashedItems = array_filter($items, [$this, 'needsSlashPrefix']);
208  $regularItems = array_diff($items, $slashedItems);
209 
210  $slashedItems = array_map([$this, 'quoteForRegularExpressionPattern'], $slashedItems);
211  $regularItems = array_map([$this, 'quoteForRegularExpressionPattern'], $regularItems);
212 
213  $patterns = [];
214  if (!empty($slashedItems)) {
215  $name = $useNames ? '?P<slashedItems>' : '';
216  $patterns[] = '(?:^|/)(' . $name . implode('|', $slashedItems) . ')';
217  }
218  if (!empty($regularItems) && !empty($this->‪index)) {
219  $name = $useNames ? '?P<indexItems>' : '';
220  $indexPattern = $this->‪quoteForRegularExpressionPattern($this->‪index);
221  $patterns[] = '^' . $indexPattern . '(' . $name . '(?:' . implode('|', $regularItems) . '))';
222  }
223  if (!empty($regularItems)) {
224  $name = $useNames ? '?P<regularItems>' : '';
225  $patterns[] = '(' . $name . implode('|', $regularItems) . ')';
226  }
227  return '(?:' . implode('|', $patterns) . ')$';
228  }
229 
236  protected function ‪quoteForRegularExpressionPattern(string $value): string
237  {
238  return preg_quote($value, '#');
239  }
240 
247  protected function ‪needsSlashPrefix(string $value): bool
248  {
249  return !in_array(
250  $value[0] ?? '',
251  static::ROUTE_PATH_DELIMITERS,
252  true
253  );
254  }
255 }
‪TYPO3\CMS\Core\Routing\Enhancer\PageTypeDecorator\$index
‪$index
Definition: PageTypeDecorator.php:63
‪TYPO3\CMS\Core\Routing\Enhancer\PageTypeDecorator\needsSlashPrefix
‪bool needsSlashPrefix(string $value)
Definition: PageTypeDecorator.php:243
‪TYPO3\CMS\Core\Routing\RouteCollection
Definition: RouteCollection.php:27
‪TYPO3\CMS\Core\Routing\Enhancer\PageTypeDecorator\map
‪$this map
Definition: PageTypeDecorator.php:79
‪TYPO3\CMS\Core\Routing\Enhancer\PageTypeDecorator\index
‪$this index
Definition: PageTypeDecorator.php:78
‪TYPO3\CMS\Core\Routing\Enhancer
Definition: AbstractEnhancer.php:4
‪TYPO3\CMS\Core\Routing\Enhancer\PageTypeDecorator\buildRegularExpressionPattern
‪string buildRegularExpressionPattern(bool $useNames=true)
Definition: PageTypeDecorator.php:197
‪TYPO3\CMS\Core\Routing\Enhancer\PageTypeDecorator\decorateForMatching
‪decorateForMatching(RouteCollection $collection, string $routePath)
Definition: PageTypeDecorator.php:93
‪TYPO3\CMS\Core\Routing\Enhancer\PageTypeDecorator\getRoutePathRedecorationPattern
‪string getRoutePathRedecorationPattern()
Definition: PageTypeDecorator.php:85
‪TYPO3\CMS\Core\Routing\Enhancer\PageTypeDecorator
Definition: PageTypeDecorator.php:38
‪TYPO3\CMS\Core\Routing\Enhancer\AbstractEnhancer
Definition: AbstractEnhancer.php:27
‪TYPO3\CMS\Core\Routing\Enhancer\PageTypeDecorator\resolveValue
‪string resolveValue(?string $type)
Definition: PageTypeDecorator.php:182
‪TYPO3\CMS\Core\Routing\Enhancer\PageTypeDecorator\$map
‪$map
Definition: PageTypeDecorator.php:64
‪TYPO3\CMS\Core\Routing\Enhancer\PageTypeDecorator\configuration
‪if(!is_string($default)) if(!is_string($index)) if(!is_array($map)) $this configuration
Definition: PageTypeDecorator.php:76
‪TYPO3\CMS\Core\Routing\Route
Definition: Route.php:31
‪TYPO3\CMS\Core\Routing\Enhancer\PageTypeDecorator\quoteForRegularExpressionPattern
‪string quoteForRegularExpressionPattern(string $value)
Definition: PageTypeDecorator.php:232
‪TYPO3\CMS\Core\Routing\Enhancer\DecoratingEnhancerInterface\decorateForGeneration
‪decorateForGeneration(RouteCollection $collection, array $parameters)
‪TYPO3\CMS\Core\Routing\Enhancer\PageTypeDecorator\ROUTE_PATH_DELIMITERS
‪const ROUTE_PATH_DELIMITERS
Definition: PageTypeDecorator.php:39
‪TYPO3\CMS\Core\Routing\Enhancer\DecoratingEnhancerInterface
Definition: DecoratingEnhancerInterface.php:25