TYPO3 CMS  TYPO3_8-7
ConfigurationService.php
Go to the documentation of this file.
1 <?php
2 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 
41 
47 {
48 
52  protected $formSettings;
53 
57  protected $firstLevelCache = [];
58 
63 
67  public function initializeObject()
68  {
69  $this->formSettings = GeneralUtility::makeInstance(ObjectManager::class)
70  ->get(ConfigurationManagerInterface::class)
72  }
73 
82  public function getPrototypeConfiguration(string $prototypeName): array
83  {
84  if (!isset($this->formSettings['prototypes'][$prototypeName])) {
86  sprintf('The Prototype "%s" was not found.', $prototypeName),
87  1475924277
88  );
89  }
90  return $this->formSettings['prototypes'][$prototypeName];
91  }
92 
100  {
101  $returnValue = GeneralUtility::makeInstance(
102  ArrayProcessor::class,
103  $this->formSettings['formManager']['selectablePrototypesConfiguration'] ?? []
104  )->forEach(
106  ArrayProcessing::class,
107  'selectablePrototypeNames',
108  '^([\d]+)\.identifier$',
109  function ($_, $value) {
110  return $value;
111  }
112  )
113  );
114 
115  return array_values($returnValue['selectablePrototypeNames'] ?? []);
116  }
117 
146  {
147  $formDefinitionValidationConfiguration = $this->buildFormDefinitionValidationConfigurationFromFormEditorSetup(
148  $dto->getPrototypeName()
149  );
150 
151  $subConfig = $formDefinitionValidationConfiguration['formElements'][$dto->getFormElementType()] ?? [];
152  return $this->isPropertyDefinedInFormEditorSetup($dto->getPropertyPath(), $subConfig);
153  }
154 
181  {
182  $formDefinitionValidationConfiguration = $this->buildFormDefinitionValidationConfigurationFromFormEditorSetup(
183  $dto->getPrototypeName()
184  );
185  $subConfig = $formDefinitionValidationConfiguration['formElements'][$dto->getFormElementType()]['collections'][$dto->getPropertyCollectionName()][$dto->getPropertyCollectionElementIdentifier()] ?? [];
186 
187  return $this->isPropertyDefinedInFormEditorSetup($dto->getPropertyPath(), $subConfig);
188  }
189 
202  ValidationDto $dto
203  ): bool {
204  $formDefinitionValidationConfiguration = $this->buildFormDefinitionValidationConfigurationFromFormEditorSetup(
205  $dto->getPrototypeName()
206  );
207  return isset(
208  $formDefinitionValidationConfiguration['formElements'][$dto->getFormElementType()]['predefinedDefaults'][$dto->getPropertyPath()]
209  );
210  }
211 
223  {
225  throw new PropertyException(
226  sprintf(
227  'No predefinedDefaults found for form element type "%s" and property path "%s"',
228  $dto->getFormElementType(),
229  $dto->getPropertyPath()
230  ),
231  1528578401
232  );
233  }
234 
235  $formDefinitionValidationConfiguration = $this->buildFormDefinitionValidationConfigurationFromFormEditorSetup(
236  $dto->getPrototypeName()
237  );
238  return $formDefinitionValidationConfiguration['formElements'][$dto->getFormElementType()]['predefinedDefaults'][$dto->getPropertyPath()];
239  }
240 
253  ValidationDto $dto
254  ): bool {
255  $formDefinitionValidationConfiguration = $this->buildFormDefinitionValidationConfigurationFromFormEditorSetup(
256  $dto->getPrototypeName()
257  );
258  return isset(
259  $formDefinitionValidationConfiguration['collections'][$dto->getPropertyCollectionName()][$dto->getPropertyCollectionElementIdentifier()]['predefinedDefaults'][$dto->getPropertyPath()]
260  );
261  }
262 
274  {
276  throw new PropertyException(
277  sprintf(
278  'No predefinedDefaults found for property collection "%s" and identifier "%s" and property path "%s"',
281  $dto->getPropertyPath()
282  ),
283  1528578402
284  );
285  }
286 
287  $formDefinitionValidationConfiguration = $this->buildFormDefinitionValidationConfigurationFromFormEditorSetup(
288  $dto->getPrototypeName()
289  );
290  return $formDefinitionValidationConfiguration['collections'][$dto->getPropertyCollectionName()][$dto->getPropertyCollectionElementIdentifier()]['predefinedDefaults'][$dto->getPropertyPath()];
291  }
292 
306  {
307  if ($dto->getFormElementType() === 'Form') {
308  return true;
309  }
310  $formDefinitionValidationConfiguration = $this->buildFormDefinitionValidationConfigurationFromFormEditorSetup(
311  $dto->getPrototypeName()
312  );
313  return $formDefinitionValidationConfiguration['formElements'][$dto->getFormElementType()]['creatable'] ?? false;
314  }
315 
330  {
331  $formDefinitionValidationConfiguration = $this->buildFormDefinitionValidationConfigurationFromFormEditorSetup(
332  $dto->getPrototypeName()
333  );
334  return $formDefinitionValidationConfiguration['formElements'][$dto->getFormElementType()]['collections'][$dto->getPropertyCollectionName()][$dto->getPropertyCollectionElementIdentifier()]['creatable'] ?? false;
335  }
336 
345  {
346  $prototypeConfiguration = $this->getPrototypeConfiguration($dto->getPrototypeName());
348  $prototypeConfiguration,
349  'formElementsDefinition.' . $dto->getFormElementType(),
350  '.'
351  );
352  }
353 
361  protected function buildFormDefinitionValidationConfigurationFromFormEditorSetup(string $prototypeName): array
362  {
363  $cacheKey = implode('_', ['buildFormDefinitionValidationConfigurationFromFormEditorSetup', $prototypeName]);
364  $configuration = $this->getCacheEntry($cacheKey);
365 
366  if ($configuration === null) {
367  $prototypeConfiguration = $this->getPrototypeConfiguration($prototypeName);
368  $extractorDto = GeneralUtility::makeInstance(ExtractorDto::class, $prototypeConfiguration);
369 
370  GeneralUtility::makeInstance(ArrayProcessor::class, $prototypeConfiguration)->forEach(
372  ArrayProcessing::class,
373  'formElementPropertyPaths',
374  '^formElementsDefinition\.(.*)\.formEditor\.editors\.([\d]+)\.(propertyPath|.*\.propertyPath)$',
375  GeneralUtility::makeInstance(PropertyPathsExtractor::class, $extractorDto)
376  ),
378  ArrayProcessing::class,
379  'formElementAdditionalElementPropertyPaths',
380  '^formElementsDefinition\.(.*)\.formEditor\.editors\.([\d]+)\.additionalElementPropertyPaths\.([\d]+)',
381  GeneralUtility::makeInstance(AdditionalElementPropertyPathsExtractor::class, $extractorDto)
382  ),
384  ArrayProcessing::class,
385  'formElementRelativeMultiValueProperties',
386  '^formElementsDefinition\.(.*)\.formEditor\.editors\.([\d]+)\.templateName$',
387  GeneralUtility::makeInstance(MultiValuePropertiesExtractor::class, $extractorDto)
388  ),
390  ArrayProcessing::class,
391  'formElementPredefinedDefaults',
392  '^formElementsDefinition\.(.*)\.formEditor\.predefinedDefaults\.(.+)$',
393  GeneralUtility::makeInstance(PredefinedDefaultsExtractor::class, $extractorDto)
394  ),
396  ArrayProcessing::class,
397  'formElementCreatable',
398  '^formElementsDefinition\.(.*)\.formEditor.group$',
399  GeneralUtility::makeInstance(IsCreatableFormElementExtractor::class, $extractorDto)
400  ),
402  ArrayProcessing::class,
403  'propertyCollectionCreatable',
404  '^formElementsDefinition\.(.*)\.formEditor\.editors\.([\d]+)\.templateName$',
405  GeneralUtility::makeInstance(IsCreatablePropertyCollectionElementExtractor::class, $extractorDto)
406  ),
408  ArrayProcessing::class,
409  'propertyCollectionPropertyPaths',
410  '^formElementsDefinition\.(.*)\.formEditor\.propertyCollections\.(finishers|validators)\.([\d]+)\.editors\.([\d]+)\.(propertyPath|.*\.propertyPath)$',
411  GeneralUtility::makeInstance(CollectionPropertyPathsExtractor::class, $extractorDto)
412  ),
414  ArrayProcessing::class,
415  'propertyCollectionAdditionalElementPropertyPaths',
416  '^formElementsDefinition\.(.*)\.formEditor\.propertyCollections\.(finishers|validators)\.([\d]+)\.editors\.([\d]+)\.additionalElementPropertyPaths\.([\d]+)',
417  GeneralUtility::makeInstance(AdditionalElementPropertyPathsExtractor::class, $extractorDto)
418  ),
420  ArrayProcessing::class,
421  'propertyCollectionRelativeMultiValueProperties',
422  '^formElementsDefinition\.(.*)\.formEditor\.propertyCollections\.(finishers|validators)\.([\d]+)\.editors\.([\d]+)\.templateName$',
423  GeneralUtility::makeInstance(CollectionMultiValuePropertiesExtractor::class, $extractorDto)
424  ),
426  ArrayProcessing::class,
427  'propertyCollectionPredefinedDefaults',
428  '^(validatorsDefinition|finishersDefinition)\.(.*)\.formEditor\.predefinedDefaults\.(.+)$',
429  GeneralUtility::makeInstance(CollectionPredefinedDefaultsExtractor::class, $extractorDto)
430  )
431  );
432  $configuration = $extractorDto->getResult();
433 
434  $configuration = $this->translateValues($prototypeConfiguration, $configuration);
435 
437  $prototypeName,
438  $configuration
439  );
440 
441  $this->setCacheEntry($cacheKey, $configuration);
442  }
443 
444  return $configuration;
445  }
446 
478  string $prototypeName,
479  array $configuration
480  ): array {
481  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/form']['buildFormDefinitionValidationConfiguration'] ?? [] as $className) {
482  $hookObj = GeneralUtility::makeInstance($className);
483  if (method_exists($hookObj, 'addAdditionalPropertyPaths')) {
484  $validationDto = GeneralUtility::makeInstance(ValidationDto::class, $prototypeName);
485  $propertyPathsFromHook = $hookObj->addAdditionalPropertyPaths($validationDto);
486  if (!is_array($propertyPathsFromHook)) {
487  $message = 'Return value of "%s->addAdditionalPropertyPaths() must be type "array"';
488  throw new PropertyException(sprintf($message, $className), 1528633965);
489  }
490  $configuration = $this->addAdditionalPropertyPathsFromHook(
491  $className,
492  $prototypeName,
493  $propertyPathsFromHook,
494  $configuration
495  );
496  }
497  }
498 
499  return $configuration;
500  }
501 
511  string $hookClassName,
512  string $prototypeName,
513  array $propertyPathsFromHook,
514  array $configuration
515  ): array {
516  foreach ($propertyPathsFromHook as $index => $validationDto) {
517  if (!($validationDto instanceof ValidationDto)) {
518  $message = 'Return value of "%s->addAdditionalPropertyPaths()[%s] must be an instance of "%s"';
519  throw new PropertyException(
520  sprintf($message, $hookClassName, $index, ValidationDto::class),
521  1528633966
522  );
523  }
524 
525  if ($validationDto->getPrototypeName() !== $prototypeName) {
526  $message = 'The prototype name "%s" does not match "%s" on "%s->addAdditionalPropertyPaths()[%s]';
527  throw new PropertyException(
528  sprintf(
529  $message,
530  $validationDto->getPrototypeName(),
531  $prototypeName,
532  $hookClassName,
533  $index,
534  ValidationDto::class
535  ),
536  1528634966
537  );
538  }
539 
540  $formElementType = $validationDto->getFormElementType();
541  if (!$this->isFormElementTypeDefinedInFormSetup($validationDto)) {
542  $message = 'Form element type "%s" does not exists in prototype configuration "%s"';
543  throw new PropertyException(
544  sprintf($message, $formElementType, $validationDto->getPrototypeName()),
545  1528633967
546  );
547  }
548 
549  if ($validationDto->hasPropertyCollectionName() &&
550  $validationDto->hasPropertyCollectionElementIdentifier()) {
551  $propertyCollectionName = $validationDto->getPropertyCollectionName();
552  $propertyCollectionElementIdentifier = $validationDto->getPropertyCollectionElementIdentifier();
553 
554  if ($propertyCollectionName !== 'finishers' && $propertyCollectionName !== 'validators') {
555  $message = 'The property collection name "%s" for form element "%s" must be "finishers" or "validators"';
556  throw new PropertyException(
557  sprintf($message, $propertyCollectionName, $formElementType),
558  1528636941
559  );
560  }
561 
562  $configuration['formElements'][$formElementType]['collections'][$propertyCollectionName][$propertyCollectionElementIdentifier]['additionalPropertyPaths'][]
563  = $validationDto->getPropertyPath();
564  } else {
565  $configuration['formElements'][$formElementType]['additionalPropertyPaths'][]
566  = $validationDto->getPropertyPath();
567  }
568  }
569 
570  return $configuration;
571  }
572 
578  protected function isPropertyDefinedInFormEditorSetup(string $propertyPath, array $subConfig): bool
579  {
580  if (empty($subConfig)) {
581  return false;
582  }
583  if (
584  in_array($propertyPath, $subConfig['propertyPaths'] ?? [], true)
585  || in_array($propertyPath, $subConfig['additionalElementPropertyPaths'] ?? [], true)
586  || in_array($propertyPath, $subConfig['additionalPropertyPaths'] ?? [], true)
587  ) {
588  return true;
589  }
590  foreach ($subConfig['multiValueProperties'] ?? [] as $relativeMultiValueProperty) {
591  if (strpos($propertyPath, $relativeMultiValueProperty) === 0) {
592  return true;
593  }
594  }
595 
596  return false;
597  }
598 
604  protected function translateValues(array $prototypeConfiguration, array $configuration): array
605  {
606  if (isset($configuration['formElements'])) {
607  $configuration['formElements'] = $this->translatePredefinedDefaults(
608  $prototypeConfiguration,
609  $configuration['formElements']
610  );
611  }
612 
613  foreach ($configuration['collections'] ?? [] as $name => $collections) {
614  $configuration['collections'][$name] = $this->translatePredefinedDefaults($prototypeConfiguration, $collections);
615  }
616  return $configuration;
617  }
618 
624  protected function translatePredefinedDefaults(array $prototypeConfiguration, array $formElements): array
625  {
626  foreach ($formElements ?? [] as $name => $formElement) {
627  if (!isset($formElement['predefinedDefaults'])) {
628  continue;
629  }
630  $formElement['predefinedDefaults'] = $this->getTranslationService()->translateValuesRecursive(
631  $formElement['predefinedDefaults'],
632  $prototypeConfiguration['formEditor']['translationFile'] ?? null
633  );
634  $formElements[$name] = $formElement;
635  }
636  return $formElements;
637  }
638 
643  protected function getCacheEntry(string $cacheKey)
644  {
645  if (isset($this->firstLevelCache[$cacheKey])) {
646  return $this->firstLevelCache[$cacheKey];
647  }
648  return $this->getCacheFrontend()->has('form_' . $cacheKey)
649  ? $this->getCacheFrontend()->get('form_' . $cacheKey)
650  : null;
651  }
652 
657  protected function setCacheEntry(string $cacheKey, $value)
658  {
659  $this->getCacheFrontend()->set('form_' . $cacheKey, $value);
660  $this->firstLevelCache[$cacheKey] = $value;
661  }
662 
667  {
668  return $this->translationService instanceof TranslationService
669  ? $this->translationService
671  }
672 
676  protected function getCacheFrontend(): FrontendInterface
677  {
678  return GeneralUtility::makeInstance(CacheManager::class)->getCache('assets');
679  }
680 }
addAdditionalPropertyPathsFromHook(string $hookClassName, string $prototypeName, array $propertyPathsFromHook, array $configuration)
executeBuildFormDefinitionValidationConfigurationHooks(string $prototypeName, array $configuration)
static makeInstance($className,... $constructorArguments)
static isValidPath(array $array, $path, $delimiter='/')
isPropertyDefinedInFormEditorSetup(string $propertyPath, array $subConfig)
translatePredefinedDefaults(array $prototypeConfiguration, array $formElements)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
translateValues(array $prototypeConfiguration, array $configuration)