‪TYPO3CMS  11.5
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 
34 
41 abstract class ‪AbstractFinisher implements ‪FinisherInterface
42 {
47  protected ‪$objectManager;
48 
52  protected ‪$finisherIdentifier = '';
53 
57  protected ‪$shortFinisherIdentifier = '';
58 
65  protected ‪$options = [];
66 
74  protected ‪$defaultOptions = [];
75 
79  protected ‪$finisherContext;
80 
87  {
88  $this->objectManager = ‪$objectManager;
89  }
90 
94  public function ‪__construct()
95  {
96  // no-op so parent::construct() calls don't fail in v11.
97  }
98 
102  public function ‪setFinisherIdentifier(string ‪$finisherIdentifier): void
103  {
104  if (empty($this->finisherIdentifier)) {
105  // @deprecated since v11, will be removed in v12. Do not override finisher in case
106  // some class implemented setting something in initializeObject() or constructor.
107  // In v12, drop the if condition, but keep the body and enable setFinisherIdentifier()
108  // in FinisherInterface.
109  $this->finisherIdentifier = ‪$finisherIdentifier;
110  $this->shortFinisherIdentifier = preg_replace('/Finisher$/', '', $this->finisherIdentifier) ?? '';
111  }
112  }
113 
117  public function ‪getFinisherIdentifier(): string
118  {
120  }
121 
125  public function ‪setOptions(array ‪$options)
126  {
127  $this->options = ‪$options;
128  }
129 
136  public function ‪setOption(string $optionName, $optionValue)
137  {
138  $this->options[$optionName] = $optionValue;
139  }
140 
147  final public function ‪execute(FinisherContext ‪$finisherContext)
148  {
149  $this->finisherContext = ‪$finisherContext;
150 
151  if (!$this->‪isEnabled()) {
152  return null;
153  }
154 
155  return $this->‪executeInternal();
156  }
157 
165  abstract protected function ‪executeInternal();
166 
178  protected function ‪parseOption(string $optionName)
179  {
180  if ($optionName === 'translation') {
181  return null;
182  }
183 
184  try {
185  $optionValue = ‪ArrayUtility::getValueByPath($this->options, $optionName, '.');
186  } catch (MissingArrayPathException $exception) {
187  $optionValue = null;
188  }
189  try {
190  $defaultValue = ‪ArrayUtility::getValueByPath($this->defaultOptions, $optionName, '.');
191  } catch (MissingArrayPathException $exception) {
192  $defaultValue = null;
193  }
194 
195  if ($optionValue === null && $defaultValue !== null) {
196  $optionValue = $defaultValue;
197  }
198 
199  if ($optionValue === null) {
200  return null;
201  }
202 
203  if (!is_string($optionValue) && !is_array($optionValue)) {
204  return $optionValue;
205  }
206 
207  $formRuntime = $this->finisherContext->getFormRuntime();
208  $optionValue = $this->‪substituteRuntimeReferences($optionValue, $formRuntime);
209 
210  if (is_string($optionValue)) {
211  $translationOptions = isset($this->options['translation']) && \is_array($this->options['translation'])
212  ? $this->options['translation']
213  : [];
214 
215  $optionValue = $this->‪translateFinisherOption(
216  $optionValue,
217  $formRuntime,
218  $optionName,
219  $optionValue,
220  $translationOptions
221  );
222 
223  $optionValue = $this->‪substituteRuntimeReferences($optionValue, $formRuntime);
224  }
225 
226  if (empty($optionValue)) {
227  if ($defaultValue !== null) {
228  $optionValue = $defaultValue;
229  }
230  }
231  return $optionValue;
232  }
233 
246  protected function ‪translateFinisherOption(
247  $subject,
248  FormRuntime $formRuntime,
249  string $optionName,
250  $optionValue,
251  array $translationOptions
252  ) {
253  if (is_array($subject)) {
254  foreach ($subject as $key => $value) {
255  $subject[$key] = $this->‪translateFinisherOption(
256  $value,
257  $formRuntime,
258  $optionName . '.' . $value,
259  $value,
260  $translationOptions
261  );
262  }
263  return $subject;
264  }
265 
266  return GeneralUtility::makeInstance(TranslationService::class)->translateFinisherOption(
267  $formRuntime,
268  $this->finisherIdentifier,
269  $optionName,
270  $optionValue,
271  $translationOptions
272  );
273  }
274 
291  protected function ‪substituteRuntimeReferences($needle, FormRuntime $formRuntime)
292  {
293  // neither array nor string, directly return
294  if (!is_array($needle) && !is_string($needle)) {
295  return $needle;
296  }
297 
298  // resolve (recursively) all array items
299  if (is_array($needle)) {
300  $substitutedNeedle = [];
301  foreach ($needle as $key => $item) {
302  $key = $this->‪substituteRuntimeReferences($key, $formRuntime);
303  $item = $this->‪substituteRuntimeReferences($item, $formRuntime);
304  $substitutedNeedle[$key] = $item;
305  }
306  return $substitutedNeedle;
307  }
308 
309  // substitute one(!) variable in string which either could result
310  // again in a string or an array representing multiple values
311  if (preg_match('/^{([^}]+)}$/', $needle, $matches)) {
312  return $this->‪resolveRuntimeReference(
313  $matches[1],
314  $formRuntime
315  );
316  }
317 
318  // in case string contains more than just one variable or just a static
319  // value that does not need to be substituted at all, candidates are:
320  // * "prefix{variable}suffix
321  // * "{variable-1},{variable-2}"
322  // * "some static value"
323  // * mixed cases of the above
324  return preg_replace_callback(
325  '/{([^}]+)}/',
326  function ($matches) use ($formRuntime) {
327  $value = $this->‪resolveRuntimeReference(
328  $matches[1],
329  $formRuntime
330  );
331 
332  // substitute each match by returning the resolved value
333  if (!is_array($value)) {
334  return $value;
335  }
336 
337  // now the resolve value is an array that shall substitute
338  // a variable in a string that probably is not the only one
339  // or is wrapped with other static string content (see above)
340  // ... which is just not possible
341  throw new FinisherException(
342  'Cannot convert array to string',
343  1519239265
344  );
345  },
346  $needle
347  );
348  }
349 
357  protected function ‪resolveRuntimeReference(string $property, FormRuntime $formRuntime)
358  {
359  if ($property === '__currentTimestamp') {
360  return time();
361  }
362 
363  // try to resolve the path '{...}' within the FormRuntime
364  $value = ‪ObjectAccess::getPropertyPath($formRuntime, $property);
365 
366  if (is_object($value)) {
367  $element = $formRuntime->getFormDefinition()->getElementByIdentifier($property);
368 
369  if (!$element instanceof StringableFormElementInterface) {
370  throw new FinisherException(
371  sprintf('Cannot convert object value of "%s" to string', $property),
372  1574362327
373  );
374  }
375 
376  $value = $element->valueToString($value);
377  }
378 
379  if ($value === null) {
380  // try to resolve the path '{...}' within the FinisherVariableProvider
382  $this->finisherContext->getFinisherVariableProvider(),
383  $property
384  );
385  }
386 
387  if ($value !== null) {
388  return $value;
389  }
390 
391  // in case no value could be resolved
392  return '{' . $property . '}';
393  }
394 
400  public function ‪isEnabled(): bool
401  {
402  return !isset($this->options['renderingOptions']['enabled']) || (bool)$this->‪parseOption('renderingOptions.enabled') === true;
403  }
404 
408  protected function ‪getTypoScriptFrontendController()
409  {
410  return ‪$GLOBALS['TSFE'];
411  }
412 }
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\$finisherIdentifier
‪string $finisherIdentifier
Definition: AbstractFinisher.php:50
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime
Definition: FormRuntime.php:109
‪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\getFinisherIdentifier
‪string getFinisherIdentifier()
Definition: AbstractFinisher.php:111
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\translateFinisherOption
‪array string translateFinisherOption( $subject, FormRuntime $formRuntime, string $optionName, $optionValue, array $translationOptions)
Definition: AbstractFinisher.php:240
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\substituteRuntimeReferences
‪mixed substituteRuntimeReferences($needle, FormRuntime $formRuntime)
Definition: AbstractFinisher.php:285
‪TYPO3\CMS\Core\Utility\Exception\MissingArrayPathException
Definition: MissingArrayPathException.php:27
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\setFinisherIdentifier
‪setFinisherIdentifier(string $finisherIdentifier)
Definition: AbstractFinisher.php:96
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\$objectManager
‪TYPO3 CMS Extbase Object ObjectManagerInterface $objectManager
Definition: AbstractFinisher.php:46
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\injectObjectManager
‪injectObjectManager(ObjectManagerInterface $objectManager)
Definition: AbstractFinisher.php:80
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\isEnabled
‪bool isEnabled()
Definition: AbstractFinisher.php:394
‪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:73
‪TYPO3\CMS\Extbase\Reflection\ObjectAccess
Definition: ObjectAccess.php:39
‪TYPO3\CMS\Extbase\Object\ObjectManagerInterface
Definition: ObjectManagerInterface.php:29
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\setOptions
‪setOptions(array $options)
Definition: AbstractFinisher.php:119
‪TYPO3\CMS\Core\Utility\ArrayUtility\getValueByPath
‪static mixed getValueByPath(array $array, $path, $delimiter='/')
Definition: ArrayUtility.php:180
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher
Definition: AbstractFinisher.php:42
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\getElementByIdentifier
‪FormElementInterface null getElementByIdentifier(string $elementIdentifier)
Definition: FormDefinition.php:604
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\$shortFinisherIdentifier
‪string $shortFinisherIdentifier
Definition: AbstractFinisher.php:54
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\resolveRuntimeReference
‪int string array resolveRuntimeReference(string $property, FormRuntime $formRuntime)
Definition: AbstractFinisher.php:351
‪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:61
‪TYPO3\CMS\Form\Domain\Finishers\FinisherContext
Definition: FinisherContext.php:38
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
Definition: TypoScriptFrontendController.php:104
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime
Definition: FormSession.php:18
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:24
‪$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:141
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime\getFormDefinition
‪FormDefinition getFormDefinition()
Definition: FormRuntime.php:1065
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\__construct
‪__construct()
Definition: AbstractFinisher.php:88
‪TYPO3\CMS\Extbase\Reflection\ObjectAccess\getPropertyPath
‪static mixed getPropertyPath($subject, string $propertyPath)
Definition: ObjectAccess.php:140
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\setOption
‪setOption(string $optionName, $optionValue)
Definition: AbstractFinisher.php:130
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\parseOption
‪string array null parseOption(string $optionName)
Definition: AbstractFinisher.php:172
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\$defaultOptions
‪array $defaultOptions
Definition: AbstractFinisher.php:69
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\executeInternal
‪string null executeInternal()
‪TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher\getTypoScriptFrontendController
‪TypoScriptFrontendController getTypoScriptFrontendController()
Definition: AbstractFinisher.php:402