‪TYPO3CMS  ‪main
AbstractFinisher.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 
18 /*
19  * Inspired by and partially taken from the Neos.Form package (www.neos.io)
20  */
21 
23 
33 
40 abstract class ‪AbstractFinisher implements ‪FinisherInterface
41 {
45  protected ‪$finisherIdentifier = '';
46 
50  protected ‪$shortFinisherIdentifier = '';
51 
58  protected ‪$options = [];
59 
67  protected ‪$defaultOptions = [];
68 
73 
77  public function ‪setFinisherIdentifier(string ‪$finisherIdentifier): void
78  {
79  $this->finisherIdentifier = ‪$finisherIdentifier;
80  $this->shortFinisherIdentifier = preg_replace('/Finisher$/', '', $this->finisherIdentifier) ?? '';
81  }
82 
83  public function ‪getFinisherIdentifier(): string
84  {
86  }
87 
91  public function ‪setOptions(array ‪$options)
92  {
93  $this->options = ‪$options;
94  }
95 
102  public function ‪setOption(string $optionName, $optionValue)
103  {
104  $this->options[$optionName] = $optionValue;
105  }
106 
113  final public function ‪execute(FinisherContext ‪$finisherContext)
114  {
115  $this->finisherContext = ‪$finisherContext;
116 
117  if (!$this->‪isEnabled()) {
118  return null;
119  }
120 
121  return $this->‪executeInternal();
122  }
123 
131  abstract protected function ‪executeInternal();
132 
144  protected function ‪parseOption(string $optionName)
145  {
146  if ($optionName === 'translation') {
147  return null;
148  }
149 
150  try {
151  $optionValue = ‪ArrayUtility::getValueByPath($this->options, $optionName, '.');
152  } catch (MissingArrayPathException $exception) {
153  $optionValue = null;
154  }
155  try {
156  $defaultValue = ‪ArrayUtility::getValueByPath($this->defaultOptions, $optionName, '.');
157  } catch (MissingArrayPathException $exception) {
158  $defaultValue = null;
159  }
160 
161  if ($optionValue === null && $defaultValue !== null) {
162  $optionValue = $defaultValue;
163  }
164 
165  if ($optionValue === null) {
166  return null;
167  }
168 
169  if (!is_string($optionValue) && !is_array($optionValue)) {
170  return $optionValue;
171  }
172 
173  $formRuntime = $this->finisherContext->getFormRuntime();
174  $optionValue = $this->‪substituteRuntimeReferences($optionValue, $formRuntime);
175 
176  if (is_string($optionValue)) {
177  $translationOptions = isset($this->options['translation']) && \is_array($this->options['translation'])
178  ? $this->options['translation']
179  : [];
180 
181  $optionValue = $this->‪translateFinisherOption(
182  $optionValue,
183  $formRuntime,
184  $optionName,
185  $optionValue,
186  $translationOptions
187  );
188 
189  $optionValue = $this->‪substituteRuntimeReferences($optionValue, $formRuntime);
190  }
191 
192  if (empty($optionValue)) {
193  if ($defaultValue !== null) {
194  $optionValue = $defaultValue;
195  }
196  }
197  return $optionValue;
198  }
199 
210  protected function ‪translateFinisherOption(
211  $subject,
212  FormRuntime $formRuntime,
213  string $optionName,
214  $optionValue,
215  array $translationOptions
216  ) {
217  if (is_array($subject)) {
218  foreach ($subject as $key => $value) {
219  $subject[$key] = $this->‪translateFinisherOption(
220  $value,
221  $formRuntime,
222  $optionName . '.' . $value,
223  $value,
224  $translationOptions
225  );
226  }
227  return $subject;
228  }
229 
230  return GeneralUtility::makeInstance(TranslationService::class)->translateFinisherOption(
231  $formRuntime,
232  $this->finisherIdentifier,
233  $optionName,
234  $optionValue,
235  $translationOptions
236  );
237  }
238 
255  protected function ‪substituteRuntimeReferences($needle, FormRuntime $formRuntime)
256  {
257  // neither array nor string, directly return
258  if (!is_array($needle) && !is_string($needle)) {
259  return $needle;
260  }
261 
262  // resolve (recursively) all array items
263  if (is_array($needle)) {
264  $substitutedNeedle = [];
265  foreach ($needle as $key => $item) {
266  $key = $this->‪substituteRuntimeReferences($key, $formRuntime);
267  $item = $this->‪substituteRuntimeReferences($item, $formRuntime);
268  $substitutedNeedle[$key] = $item;
269  }
270  return $substitutedNeedle;
271  }
272 
273  // substitute one(!) variable in string which either could result
274  // again in a string or an array representing multiple values
275  if (preg_match('/^{([^}]+)}$/', $needle, $matches)) {
276  return $this->‪resolveRuntimeReference(
277  $matches[1],
278  $formRuntime
279  );
280  }
281 
282  // in case string contains more than just one variable or just a static
283  // value that does not need to be substituted at all, candidates are:
284  // * "prefix{variable}suffix
285  // * "{variable-1},{variable-2}"
286  // * "some static value"
287  // * mixed cases of the above
288  return preg_replace_callback(
289  '/{([^}]+)}/',
290  function ($matches) use ($formRuntime) {
291  $value = $this->‪resolveRuntimeReference(
292  $matches[1],
293  $formRuntime
294  );
295 
296  // substitute each match by returning the resolved value
297  if (!is_array($value)) {
298  return $value;
299  }
300 
301  // now the resolve value is an array that shall substitute
302  // a variable in a string that probably is not the only one
303  // or is wrapped with other static string content (see above)
304  // ... which is just not possible
305  throw new FinisherException(
306  'Cannot convert array to string',
307  1519239265
308  );
309  },
310  $needle
311  );
312  }
313 
319  protected function ‪resolveRuntimeReference(string $property, FormRuntime $formRuntime)
320  {
321  if ($property === '__currentTimestamp') {
322  return time();
323  }
324 
325  // try to resolve the path '{...}' within the FormRuntime
326  $value = ‪ObjectAccess::getPropertyPath($formRuntime, $property);
327 
328  if (is_object($value)) {
329  $element = $formRuntime->getFormDefinition()->getElementByIdentifier($property);
330 
331  if (!$element instanceof StringableFormElementInterface) {
332  throw new FinisherException(
333  sprintf('Cannot convert object value of "%s" to string', $property),
334  1574362327
335  );
336  }
337 
338  $value = $element->valueToString($value);
339  }
340 
341  if ($value === null) {
342  // try to resolve the path '{...}' within the FinisherVariableProvider
344  $this->finisherContext->getFinisherVariableProvider(),
345  $property
346  );
347  }
348 
349  if ($value !== null) {
350  return $value;
351  }
352 
353  // in case no value could be resolved
354  return '{' . $property . '}';
355  }
356 
360  public function ‪isEnabled(): bool
361  {
362  return !isset($this->options['renderingOptions']['enabled']) || (bool)$this->‪parseOption('renderingOptions.enabled') === true;
363  }
364 
366  {
367  return ‪$GLOBALS['TSFE'];
368  }
369 }
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\$finisherIdentifier
‪string $finisherIdentifier
Definition: AbstractFinisher.php:44
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime
Definition: FormRuntime.php:106
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\getFinisherIdentifier
‪getFinisherIdentifier()
Definition: AbstractFinisher.php:78
‪TYPO3\CMS\Extbase\Reflection\ObjectAccess\getPropertyPath
‪static mixed getPropertyPath(object|array $subject, string $propertyPath)
Definition: ObjectAccess.php:128
‪TYPO3\CMS\Form\Domain\Finishers\FinisherInterface
Definition: FinisherInterface.php:31
‪TYPO3\CMS\Form\Service\TranslationService
Definition: TranslationService.php:45
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\translateFinisherOption
‪array string translateFinisherOption( $subject, FormRuntime $formRuntime, string $optionName, $optionValue, array $translationOptions)
Definition: AbstractFinisher.php:205
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\substituteRuntimeReferences
‪mixed substituteRuntimeReferences($needle, FormRuntime $formRuntime)
Definition: AbstractFinisher.php:250
‪TYPO3\CMS\Core\Utility\Exception\MissingArrayPathException
Definition: MissingArrayPathException.php:27
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\setFinisherIdentifier
‪setFinisherIdentifier(string $finisherIdentifier)
Definition: AbstractFinisher.php:72
‪TYPO3\CMS\Form\Domain\Finishers
Definition: AbstractFinisher.php:22
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\$finisherContext
‪TYPO3 CMS Form Domain Finishers FinisherContext $finisherContext
Definition: AbstractFinisher.php:67
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\parseOption
‪string array int null parseOption(string $optionName)
Definition: AbstractFinisher.php:139
‪TYPO3\CMS\Extbase\Reflection\ObjectAccess
Definition: ObjectAccess.php:39
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\getTypoScriptFrontendController
‪getTypoScriptFrontendController()
Definition: AbstractFinisher.php:360
‪TYPO3\CMS\Core\Utility\ArrayUtility\getValueByPath
‪static getValueByPath(array $array, array|string $path, string $delimiter='/')
Definition: ArrayUtility.php:176
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\setOptions
‪setOptions(array $options)
Definition: AbstractFinisher.php:86
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher
Definition: AbstractFinisher.php:41
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\$shortFinisherIdentifier
‪string $shortFinisherIdentifier
Definition: AbstractFinisher.php:48
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\isEnabled
‪isEnabled()
Definition: AbstractFinisher.php:355
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\resolveRuntimeReference
‪int string array resolveRuntimeReference(string $property, FormRuntime $formRuntime)
Definition: AbstractFinisher.php:314
‪TYPO3\CMS\Form\Domain\Finishers\Exception\FinisherException
Definition: FinisherException.php:25
‪TYPO3\CMS\Form\Domain\Model\FormElements\StringableFormElementInterface
Definition: StringableFormElementInterface.php:30
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\$options
‪array $options
Definition: AbstractFinisher.php:55
‪TYPO3\CMS\Form\Domain\Finishers\FinisherContext
Definition: FinisherContext.php:37
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
Definition: TypoScriptFrontendController.php:58
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime
Definition: FormSession.php:18
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:26
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\execute
‪string null execute(FinisherContext $finisherContext)
Definition: AbstractFinisher.php:108
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\setOption
‪setOption(string $optionName, $optionValue)
Definition: AbstractFinisher.php:97
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\getFormDefinition
‪getFormDefinition()
Definition: FormRuntime.php:985
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\$defaultOptions
‪array $defaultOptions
Definition: AbstractFinisher.php:63
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\executeInternal
‪string void null executeInternal()