‪TYPO3CMS  9.5
VariableProcessor.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 
23 {
24  protected const ‪LEVEL_DELIMITER = '__';
25  protected const ‪ARGUMENT_SEPARATOR = '/';
26  protected const ‪VARIABLE_PATTERN = '#\{(?P<modifier>!)?(?P<name>[^}]+)\}#';
27 
31  protected ‪$hashes = [];
32 
36  protected ‪$nestedValues = [];
37 
42  protected function ‪addHash(string $value): string
43  {
44  if (strlen($value) < 31 && !preg_match('#[^\w]#', $value)) {
45  return $value;
46  }
47  // removing one bit, e.g. for enforced route prefix `{!value}`
48  $hash = substr(md5($value), 0, -1);
49  // Symfony Route Compiler requires first literal to be non-integer
50  if ($hash[0] === (string)(int)$hash[0]) {
51  $hash[0] = str_replace(
52  range('0', '9'),
53  range('o', 'x'),
54  $hash[0]
55  );
56  }
57  $this->hashes[$hash] = $value;
58  return $hash;
59  }
60 
66  protected function ‪resolveHash(string $hash): string
67  {
68  if (strlen($hash) < 31) {
69  return $hash;
70  }
71  if (!isset($this->hashes[$hash])) {
72  throw new \OutOfRangeException(
73  'Hash not resolvable',
74  1537633463
75  );
76  }
77  return $this->hashes[$hash];
78  }
79 
84  protected function ‪addNestedValue(string $value): string
85  {
86  if (strpos($value, static::ARGUMENT_SEPARATOR) === false) {
87  return $value;
88  }
89  $nestedValue = str_replace(
90  static::ARGUMENT_SEPARATOR,
91  static::LEVEL_DELIMITER,
92  $value
93  );
94  $this->nestedValues[$nestedValue] = $value;
95  return $nestedValue;
96  }
97 
102  protected function ‪resolveNestedValue(string $value): string
103  {
104  if (strpos($value, static::LEVEL_DELIMITER) === false) {
105  return $value;
106  }
107  return $this->nestedValues[$value] ?? $value;
108  }
109 
116  public function ‪deflateRoutePath(string $routePath, string $namespace = null, array $arguments = []): string
117  {
118  if (!preg_match_all(static::VARIABLE_PATTERN, $routePath, $matches)) {
119  return $routePath;
120  }
121 
122  $replace = [];
123  $search = array_values($matches[0]);
124  $deflatedNames = $this->‪deflateValues($matches['name'], $namespace, $arguments);
125  foreach ($deflatedNames as $index => $deflatedName) {
126  $modifier = $matches['modifier'][$index] ?? '';
127  $replace[] = '{' . $modifier . $deflatedName . '}';
128  }
129  return str_replace($search, $replace, $routePath);
130  }
131 
138  public function ‪inflateRoutePath(string $routePath, string $namespace = null, array $arguments = []): string
139  {
140  if (!preg_match_all(static::VARIABLE_PATTERN, $routePath, $matches)) {
141  return $routePath;
142  }
143 
144  $replace = [];
145  $search = array_values($matches[0]);
146  $inflatedNames = $this->‪inflateValues($matches['name'], $namespace, $arguments);
147  foreach ($inflatedNames as $index => $inflatedName) {
148  $modifier = $matches['modifier'][$index] ?? '';
149  $replace[] = '{' . $modifier . $inflatedName . '}';
150  }
151  return str_replace($search, $replace, $routePath);
152  }
153 
162  public function ‪deflateNamespaceParameters(array $parameters, string $namespace, array $arguments = []): array
163  {
164  if (empty($namespace) || empty($parameters[$namespace])) {
165  return $parameters;
166  }
167  // prefix items of namespace parameters and apply argument mapping
168  $namespaceParameters = $this->‪deflateKeys($parameters[$namespace], $namespace, $arguments, false);
169  // deflate those array items
170  $namespaceParameters = $this->‪deflateArray($namespaceParameters);
171  unset($parameters[$namespace]);
172  // merge with remaining array items
173  return array_merge($parameters, $namespaceParameters);
174  }
175 
184  public function ‪inflateNamespaceParameters(array $parameters, string $namespace, array $arguments = []): array
185  {
186  if (empty($namespace) || empty($parameters)) {
187  return $parameters;
188  }
189 
190  $parameters = $this->‪inflateArray($parameters, $namespace, $arguments);
191  // apply argument mapping on items of inflated namespace parameters
192  if (!empty($parameters[$namespace]) && !empty($arguments)) {
193  $parameters[$namespace] = $this->‪inflateKeys($parameters[$namespace], null, $arguments, false);
194  }
195  return $parameters;
196  }
197 
205  public function ‪deflateParameters(array $parameters, array $arguments = []): array
206  {
207  $parameters = $this->‪deflateKeys($parameters, null, $arguments, false);
208  return $this->‪deflateArray($parameters);
209  }
210 
218  public function ‪inflateParameters(array $parameters, array $arguments = []): array
219  {
220  $parameters = $this->‪inflateArray($parameters, null, $arguments);
221  return $this->‪inflateKeys($parameters, null, $arguments, false);
222  }
223 
234  public function ‪deflateKeys(array $items, string $namespace = null, array $arguments = [], bool $hash = true): array
235  {
236  if (empty($items) || empty($arguments) && empty($namespace)) {
237  return $items;
238  }
239  $keys = $this->‪deflateValues(array_keys($items), $namespace, $arguments, $hash);
240  return array_combine(
241  $keys,
242  array_values($items)
243  );
244  }
245 
256  public function ‪inflateKeys(array $items, string $namespace = null, array $arguments = [], bool $hash = true): array
257  {
258  if (empty($items) || empty($arguments) && empty($namespace)) {
259  return $items;
260  }
261  $keys = $this->‪inflateValues(array_keys($items), $namespace, $arguments, $hash);
262  return array_combine(
263  $keys,
264  array_values($items)
265  );
266  }
267 
277  protected function ‪deflateValues(array $values, string $namespace = null, array $arguments = [], bool $hash = true): array
278  {
279  if (empty($values) || empty($arguments) && empty($namespace)) {
280  return $values;
281  }
282  $namespacePrefix = $namespace ? $namespace . static::LEVEL_DELIMITER : '';
283  $arguments = array_map('strval', $arguments);
284  return array_map(
285  function (string $value) use ($arguments, $namespacePrefix, $hash) {
286  $value = $arguments[$value] ?? $value;
287  $value = $this->‪addNestedValue($value);
288  $value = $namespacePrefix . $value;
289  if (!$hash) {
290  return $value;
291  }
292  return $this->‪addHash($value);
293  },
294  $values
295  );
296  }
297 
307  protected function ‪inflateValues(array $values, string $namespace = null, array $arguments = [], bool $hash = true): array
308  {
309  if (empty($values) || empty($arguments) && empty($namespace)) {
310  return $values;
311  }
312  $arguments = array_map('strval', $arguments);
313  $namespacePrefix = $namespace ? $namespace . static::LEVEL_DELIMITER : '';
314  return array_map(
315  function (string $value) use ($arguments, $namespacePrefix, $hash) {
316  if ($hash) {
317  $value = $this->‪resolveHash($value);
318  }
319  if (!empty($namespacePrefix) && strpos($value, $namespacePrefix) === 0) {
320  $value = substr($value, strlen($namespacePrefix));
321  }
322  $value = $this->‪resolveNestedValue($value);
323  $index = array_search($value, $arguments, true);
324  return $index !== false ? $index : $value;
325  },
326  $values
327  );
328  }
329 
337  protected function ‪deflateArray(array $array, string $prefix = ''): array
338  {
339  $delimiter = static::LEVEL_DELIMITER;
340  if ($prefix !== '' && substr($prefix, -strlen($delimiter)) !== $delimiter) {
341  $prefix .= static::LEVEL_DELIMITER;
342  }
343 
344  $result = [];
345  foreach ($array as $key => $value) {
346  if (is_array($value)) {
347  $result = array_replace(
348  $result,
349  $this->‪deflateArray(
350  $value,
351  $prefix . $key . static::LEVEL_DELIMITER
352  )
353  );
354  } else {
355  $deflatedKey = $this->‪addHash($prefix . $key);
356  $result[$deflatedKey] = $value;
357  }
358  }
359  return $result;
360  }
361 
370  protected function ‪inflateArray(array $array, ?string $namespace, array $arguments): array
371  {
372  $result = [];
373  foreach ($array as $key => $value) {
374  $inflatedKey = $this->‪resolveHash((string)$key);
375  // inflate nested values `namespace__any__nested` -> `namespace__any/nested`
376  $inflatedKey = $this->‪inflateNestedValue($inflatedKey, $namespace, $arguments);
377  $steps = explode(static::LEVEL_DELIMITER, $inflatedKey);
378  $pointer = &$result;
379  foreach ($steps as $step) {
380  $pointer = &$pointer[$step];
381  }
382  $pointer = $value;
383  unset($pointer);
384  }
385  return $result;
386  }
387 
394  protected function ‪inflateNestedValue(string $value, ?string $namespace, array $arguments): string
395  {
396  $namespacePrefix = $namespace ? $namespace . static::LEVEL_DELIMITER : '';
397  if (!empty($namespace) && strpos($value, $namespacePrefix) !== 0) {
398  return $value;
399  }
400  $arguments = array_map('strval', $arguments);
401  $possibleNestedValueKey = substr($value, strlen($namespacePrefix));
402  $possibleNestedValue = $this->nestedValues[$possibleNestedValueKey] ?? null;
403  if ($possibleNestedValue === null || !in_array($possibleNestedValue, $arguments, true)) {
404  return $value;
405  }
406  return $namespacePrefix . $possibleNestedValue;
407  }
408 }
‪TYPO3\CMS\Core\Routing\Enhancer\VariableProcessor\deflateRoutePath
‪string deflateRoutePath(string $routePath, string $namespace=null, array $arguments=[])
Definition: VariableProcessor.php:114
‪TYPO3\CMS\Core\Routing\Enhancer\VariableProcessor\$nestedValues
‪array $nestedValues
Definition: VariableProcessor.php:34
‪TYPO3\CMS\Core\Routing\Enhancer\VariableProcessor
Definition: VariableProcessor.php:23
‪TYPO3\CMS\Core\Routing\Enhancer\VariableProcessor\resolveNestedValue
‪string resolveNestedValue(string $value)
Definition: VariableProcessor.php:100
‪TYPO3\CMS\Core\Routing\Enhancer
Definition: AbstractEnhancer.php:4
‪TYPO3\CMS\Core\Routing\Enhancer\VariableProcessor\deflateNamespaceParameters
‪array deflateNamespaceParameters(array $parameters, string $namespace, array $arguments=[])
Definition: VariableProcessor.php:160
‪TYPO3\CMS\Core\Routing\Enhancer\VariableProcessor\LEVEL_DELIMITER
‪const LEVEL_DELIMITER
Definition: VariableProcessor.php:24
‪TYPO3\CMS\Core\Routing\Enhancer\VariableProcessor\deflateKeys
‪array deflateKeys(array $items, string $namespace=null, array $arguments=[], bool $hash=true)
Definition: VariableProcessor.php:232
‪TYPO3\CMS\Core\Routing\Enhancer\VariableProcessor\inflateValues
‪array inflateValues(array $values, string $namespace=null, array $arguments=[], bool $hash=true)
Definition: VariableProcessor.php:305
‪TYPO3\CMS\Core\Routing\Enhancer\VariableProcessor\VARIABLE_PATTERN
‪const VARIABLE_PATTERN
Definition: VariableProcessor.php:26
‪TYPO3\CMS\Core\Routing\Enhancer\VariableProcessor\inflateParameters
‪array inflateParameters(array $parameters, array $arguments=[])
Definition: VariableProcessor.php:216
‪TYPO3\CMS\Core\Routing\Enhancer\VariableProcessor\resolveHash
‪string resolveHash(string $hash)
Definition: VariableProcessor.php:64
‪TYPO3\CMS\Core\Routing\Enhancer\VariableProcessor\ARGUMENT_SEPARATOR
‪const ARGUMENT_SEPARATOR
Definition: VariableProcessor.php:25
‪TYPO3\CMS\Core\Routing\Enhancer\VariableProcessor\addHash
‪string addHash(string $value)
Definition: VariableProcessor.php:40
‪TYPO3\CMS\Core\Routing\Enhancer\VariableProcessor\inflateNestedValue
‪string inflateNestedValue(string $value, ?string $namespace, array $arguments)
Definition: VariableProcessor.php:392
‪TYPO3\CMS\Core\Routing\Enhancer\VariableProcessor\inflateArray
‪array inflateArray(array $array, ?string $namespace, array $arguments)
Definition: VariableProcessor.php:368
‪TYPO3\CMS\Core\Routing\Enhancer\VariableProcessor\deflateArray
‪array deflateArray(array $array, string $prefix='')
Definition: VariableProcessor.php:335
‪TYPO3\CMS\Core\Routing\Enhancer\VariableProcessor\deflateParameters
‪array deflateParameters(array $parameters, array $arguments=[])
Definition: VariableProcessor.php:203
‪TYPO3\CMS\Core\Routing\Enhancer\VariableProcessor\$hashes
‪array $hashes
Definition: VariableProcessor.php:30
‪TYPO3\CMS\Core\Routing\Enhancer\VariableProcessor\deflateValues
‪array deflateValues(array $values, string $namespace=null, array $arguments=[], bool $hash=true)
Definition: VariableProcessor.php:275
‪TYPO3\CMS\Core\Routing\Enhancer\VariableProcessor\addNestedValue
‪string addNestedValue(string $value)
Definition: VariableProcessor.php:82
‪TYPO3\CMS\Core\Routing\Enhancer\VariableProcessor\inflateKeys
‪array inflateKeys(array $items, string $namespace=null, array $arguments=[], bool $hash=true)
Definition: VariableProcessor.php:254
‪TYPO3\CMS\Core\Routing\Enhancer\VariableProcessor\inflateNamespaceParameters
‪array inflateNamespaceParameters(array $parameters, string $namespace, array $arguments=[])
Definition: VariableProcessor.php:182
‪TYPO3\CMS\Core\Routing\Enhancer\VariableProcessor\inflateRoutePath
‪string inflateRoutePath(string $routePath, string $namespace=null, array $arguments=[])
Definition: VariableProcessor.php:136