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