‪TYPO3CMS  10.4
DataStructureIdentifierHook.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 
36 
47 {
48 
52  const ‪L10N_PREFIX = 'LLL:EXT:form/Resources/Private/Language/Database.xlf:';
53 
67  array $fieldTca,
68  string $tableName,
69  string $fieldName,
70  array $row,
71  array $identifier
72  ): array {
73  if ($tableName === 'tt_content' && $fieldName === 'pi_flexform' && $row['CType'] === 'form_formframework') {
74  $currentFlexData = [];
75  if (!empty($row['pi_flexform']) && !\is_array($row['pi_flexform'])) {
76  $currentFlexData = ‪GeneralUtility::xml2array($row['pi_flexform']);
77  }
78 
79  // Add selected form value
80  $identifier['ext-form-persistenceIdentifier'] = '';
81  if (!empty($currentFlexData['data']['sDEF']['lDEF']['settings.persistenceIdentifier']['vDEF'])) {
82  $identifier['ext-form-persistenceIdentifier'] = $currentFlexData['data']['sDEF']['lDEF']['settings.persistenceIdentifier']['vDEF'];
83  }
84 
85  // Add bool - finisher override active or not
86  $identifier['ext-form-overrideFinishers'] = '';
87  if (
88  isset($currentFlexData['data']['sDEF']['lDEF']['settings.overrideFinishers']['vDEF'])
89  && (int)$currentFlexData['data']['sDEF']['lDEF']['settings.overrideFinishers']['vDEF'] === 1
90  ) {
91  $identifier['ext-form-overrideFinishers'] = 'enabled';
92  }
93  }
94  return $identifier;
95  }
96 
107  public function ‪parseDataStructureByIdentifierPostProcess(array $dataStructure, array $identifier): array
108  {
109  if (isset($identifier['ext-form-persistenceIdentifier'])) {
110  try {
111  // Add list of existing forms to drop down if we find our key in the identifier
112  $formPersistenceManager = GeneralUtility::makeInstance(ObjectManager::class)->get(FormPersistenceManagerInterface::class);
113  $formIsAccessible = false;
114  foreach ($formPersistenceManager->listForms() as $form) {
115  $invalidFormDefinition = $form['invalid'] ?? false;
116 
117  if ($form['persistenceIdentifier'] === $identifier['ext-form-persistenceIdentifier']) {
118  $formIsAccessible = true;
119  }
120 
121  if ($invalidFormDefinition) {
122  $dataStructure['sheets']['sDEF']['ROOT']['el']['settings.persistenceIdentifier']['TCEforms']['config']['items'][] = [
123  $form['name'] . ' (' . $form['persistenceIdentifier'] . ')',
124  $form['persistenceIdentifier'],
125  'overlay-missing'
126  ];
127  } else {
128  $dataStructure['sheets']['sDEF']['ROOT']['el']['settings.persistenceIdentifier']['TCEforms']['config']['items'][] = [
129  $form['name'] . ' (' . $form['persistenceIdentifier'] . ')',
130  $form['persistenceIdentifier'],
131  'content-form'
132  ];
133  }
134  }
135 
136  if (!empty($identifier['ext-form-persistenceIdentifier']) && !$formIsAccessible) {
137  $dataStructure['sheets']['sDEF']['ROOT']['el']['settings.persistenceIdentifier']['TCEforms']['config']['items'][] = [
138  sprintf(
139  $this->‪getLanguageService()->sL(self::L10N_PREFIX . 'tt_content.preview.inaccessiblePersistenceIdentifier'),
140  $identifier['ext-form-persistenceIdentifier']
141  ),
142  $identifier['ext-form-persistenceIdentifier'],
143  ];
144  }
145 
146  // If a specific form is selected and if finisher override is active, add finisher sheets
147  if (!empty($identifier['ext-form-persistenceIdentifier']) && $formIsAccessible) {
148  $persistenceIdentifier = $identifier['ext-form-persistenceIdentifier'];
149  $formDefinition = $formPersistenceManager->load($persistenceIdentifier);
150 
151  $translationFile = 'LLL:EXT:form/Resources/Private/Language/Database.xlf';
152  $dataStructure['sheets']['sDEF']['ROOT']['el']['settings.overrideFinishers'] = [
153  'TCEforms' => [
154  'label' => $translationFile . ':tt_content.pi_flexform.formframework.overrideFinishers',
155  'onChange' => 'reload',
156  'config' => [
157  'type' => 'check',
158  ],
159  ],
160  ];
161 
162  $newSheets = [];
163 
164  if (isset($formDefinition['finishers']) && !empty($formDefinition['finishers'])) {
165  $newSheets = $this->‪getAdditionalFinisherSheets($persistenceIdentifier, $formDefinition);
166  }
167 
168  if (empty($newSheets)) {
170  $dataStructure['sheets']['sDEF']['ROOT']['el']['settings.overrideFinishers'],
171  [
172  'TCEforms' => [
173  'description' => $translationFile . ':tt_content.pi_flexform.formframework.overrideFinishers.empty',
174  'config' => [
175  'readOnly' => true,
176  ],
177  ],
178  ]
179  );
180  }
181 
182  if ($identifier['ext-form-overrideFinishers'] === 'enabled') {
184  $dataStructure,
185  $newSheets
186  );
187  }
188  }
190  $dataStructure = $this->‪addSelectedPersistenceIdentifier($identifier['ext-form-persistenceIdentifier'], $dataStructure);
192  }
193  }
194 
195  return $dataStructure;
196  }
197 
205  protected function ‪getAdditionalFinisherSheets(string $persistenceIdentifier, array $formDefinition): array
206  {
207  if (!isset($formDefinition['finishers']) || empty($formDefinition['finishers'])) {
208  return [];
209  }
210 
211  $prototypeName = $formDefinition['prototypeName'] ?? 'standard';
212  $prototypeConfiguration = GeneralUtility::makeInstance(ObjectManager::class)
213  ->get(ConfigurationService::class)
214  ->getPrototypeConfiguration($prototypeName);
215 
216  if (!isset($prototypeConfiguration['finishersDefinition']) || empty($prototypeConfiguration['finishersDefinition'])) {
217  return [];
218  }
219 
220  $formIdentifier = $formDefinition['identifier'];
221  $finishersDefinition = $prototypeConfiguration['finishersDefinition'];
222 
223  $sheets = ['sheets' => []];
224  foreach ($formDefinition['finishers'] as $formFinisherDefinition) {
225  $finisherIdentifier = $formFinisherDefinition['identifier'];
226  if (!isset($finishersDefinition[$finisherIdentifier]['FormEngine']['elements'])) {
227  continue;
228  }
229  $sheetIdentifier = $this->‪buildFlexformSheetIdentifier(
230  $persistenceIdentifier,
231  $prototypeName,
232  $formIdentifier,
233  $finisherIdentifier
234  );
235 
236  $finishersDefinition = $this->‪translateFinisherDefinitionByIdentifier(
237  $finisherIdentifier,
238  $finishersDefinition,
239  $prototypeConfiguration
240  );
241 
242  $prototypeFinisherDefinition = $finishersDefinition[$finisherIdentifier];
243  $finisherLabel = $prototypeFinisherDefinition['FormEngine']['label'] ?? '';
244  $sheet = $this->‪initializeNewSheetArray($sheetIdentifier, $finisherLabel);
245 
246  $converterDto = GeneralUtility::makeInstance(
247  ProcessorDto::class,
248  $finisherIdentifier,
249  $prototypeFinisherDefinition,
250  $formFinisherDefinition
251  );
252 
253  // Iterate over all `TYPO3.CMS.Form.prototypes.<prototypeName>.finishersDefinition.<finisherIdentifier>.FormEngine.elements` values
254  // and convert them to FlexForm elements
255  GeneralUtility::makeInstance(ArrayProcessor::class, $prototypeFinisherDefinition['FormEngine']['elements'])->forEach(
256  GeneralUtility::makeInstance(
257  ArrayProcessing::class,
258  'convertToFlexFormSheets',
259  // Either process leaf form field configuration not within a FlexForm section or FlexForm section
260  '^(.*)(?:(?<!\.TCEforms)\.config\.type|\.section)$',
261  GeneralUtility::makeInstance(FinisherOptionGenerator::class, $converterDto)
262  )
263  );
264 
265  $sheet[$sheetIdentifier]['ROOT']['el'] = $converterDto->getResult();
266  ‪ArrayUtility::mergeRecursiveWithOverrule($sheets['sheets'], $sheet);
267  }
268  if (empty($sheets['sheets'])) {
269  return [];
270  }
271 
272  return $sheets;
273  }
274 
283  protected function ‪initializeNewSheetArray(string $sheetIdentifier, string $finisherName): array
284  {
285  if (empty($sheetIdentifier)) {
286  throw new \InvalidArgumentException('$sheetIdentifier must not be empty.', 1472060918);
287  }
288  if (empty($finisherName)) {
289  throw new \InvalidArgumentException('$finisherName must not be empty.', 1472060919);
290  }
291 
292  return [
293  $sheetIdentifier => [
294  'ROOT' => [
295  'TCEforms' => [
296  'sheetTitle' => $finisherName,
297  ],
298  'type' => 'array',
299  'el' => [],
300  ],
301  ],
302  ];
303  }
304 
310  protected function ‪addSelectedPersistenceIdentifier(string $persistenceIdentifier, array $dataStructure): array
311  {
312  if (!empty($persistenceIdentifier)) {
313  $dataStructure['sheets']['sDEF']['ROOT']['el']['settings.persistenceIdentifier']['TCEforms']['config']['items'][] = [
314  sprintf(
315  $this->‪getLanguageService()->sL(self::L10N_PREFIX . 'tt_content.preview.inaccessiblePersistenceIdentifier'),
316  $persistenceIdentifier
317  ),
318  $persistenceIdentifier,
319  ];
320  }
321 
322  return $dataStructure;
323  }
324 
329  {
330  $messageText = sprintf(
331  $this->‪getLanguageService()->sL(self::L10N_PREFIX . 'tt_content.preview.invalidFrameworkConfiguration.text'),
332  $e->getMessage()
333  );
334 
335  GeneralUtility::makeInstance(FlashMessageService::class)
336  ->getMessageQueueByIdentifier('core.template.flashMessages')
337  ->enqueue(
338  GeneralUtility::makeInstance(
339  FlashMessage::class,
340  $messageText,
341  $this->‪getLanguageService()->sL(self::L10N_PREFIX . 'tt_content.preview.invalidFrameworkConfiguration.title'),
343  true
344  )
345  );
346  }
347 
356  string $persistenceIdentifier,
357  string $prototypeName,
358  string $formIdentifier,
359  string $finisherIdentifier
360  ): string {
361  return md5(
362  implode('', [
363  $persistenceIdentifier,
364  $prototypeName,
365  $formIdentifier,
366  $finisherIdentifier
367  ])
368  );
369  }
370 
378  string $finisherIdentifier,
379  array $finishersDefinition,
380  array $prototypeConfiguration
381  ): array {
382  if (isset($finishersDefinition[$finisherIdentifier]['FormEngine']['translationFiles'])) {
383  $translationFiles = $finishersDefinition[$finisherIdentifier]['FormEngine']['translationFiles'];
384  } else {
385  $translationFiles = $prototypeConfiguration['formEngine']['translationFiles'];
386  }
387 
388  $finishersDefinition[$finisherIdentifier]['FormEngine'] = ‪TranslationService::getInstance()->‪translateValuesRecursive(
389  $finishersDefinition[$finisherIdentifier]['FormEngine'],
390  $translationFiles
391  );
392 
393  return $finishersDefinition;
394  }
395 
400  {
401  return ‪$GLOBALS['LANG'];
402  }
403 }
‪TYPO3\CMS\Form\Hooks\DataStructureIdentifierHook\initializeNewSheetArray
‪array initializeNewSheetArray(string $sheetIdentifier, string $finisherName)
Definition: DataStructureIdentifierHook.php:283
‪TYPO3\CMS\Core\Utility\GeneralUtility\xml2array
‪static mixed xml2array($string, $NSprefix='', $reportDocTag=false)
Definition: GeneralUtility.php:1531
‪TYPO3\CMS\Form\Hooks\DataStructureIdentifierHook
Definition: DataStructureIdentifierHook.php:47
‪TYPO3\CMS\Form\Service\TranslationService\getInstance
‪static TranslationService getInstance()
Definition: TranslationService.php:83
‪TYPO3\CMS\Core\Messaging\AbstractMessage
Definition: AbstractMessage.php:26
‪TYPO3\CMS\Form\Service\TranslationService
Definition: TranslationService.php:44
‪TYPO3\CMS\Form\Domain\Configuration\FlexformConfiguration\Processors\ProcessorDto
Definition: ProcessorDto.php:26
‪TYPO3\CMS\Form\Hooks\DataStructureIdentifierHook\translateFinisherDefinitionByIdentifier
‪array translateFinisherDefinitionByIdentifier(string $finisherIdentifier, array $finishersDefinition, array $prototypeConfiguration)
Definition: DataStructureIdentifierHook.php:377
‪TYPO3\CMS\Form\Hooks\DataStructureIdentifierHook\buildFlexformSheetIdentifier
‪string buildFlexformSheetIdentifier(string $persistenceIdentifier, string $prototypeName, string $formIdentifier, string $finisherIdentifier)
Definition: DataStructureIdentifierHook.php:355
‪TYPO3\CMS\Core\Utility\ArrayUtility\mergeRecursiveWithOverrule
‪static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=true, $includeEmptyValues=true, $enableUnsetFeature=true)
Definition: ArrayUtility.php:654
‪TYPO3\CMS\Form\Service\TranslationService\translateValuesRecursive
‪array translateValuesRecursive(array $array, array $translationFiles=[])
Definition: TranslationService.php:179
‪TYPO3\CMS\Form\Domain\Configuration\ArrayProcessing\ArrayProcessing
Definition: ArrayProcessing.php:27
‪TYPO3\CMS\Form\Hooks\DataStructureIdentifierHook\parseDataStructureByIdentifierPostProcess
‪array parseDataStructureByIdentifierPostProcess(array $dataStructure, array $identifier)
Definition: DataStructureIdentifierHook.php:107
‪TYPO3\CMS\Form\Hooks
Definition: DataStructureIdentifierHook.php:18
‪TYPO3\CMS\Form\Hooks\DataStructureIdentifierHook\addSelectedPersistenceIdentifier
‪array addSelectedPersistenceIdentifier(string $persistenceIdentifier, array $dataStructure)
Definition: DataStructureIdentifierHook.php:310
‪TYPO3\CMS\Form\Domain\Configuration\ArrayProcessing\ArrayProcessor
Definition: ArrayProcessor.php:30
‪TYPO3\CMS\Form\Hooks\DataStructureIdentifierHook\addInvalidFrameworkConfigurationFlashMessage
‪addInvalidFrameworkConfigurationFlashMessage(\Exception $e)
Definition: DataStructureIdentifierHook.php:328
‪TYPO3\CMS\Form\Domain\Configuration\FlexformConfiguration\Processors\FinisherOptionGenerator
Definition: FinisherOptionGenerator.php:31
‪TYPO3\CMS\Form\Hooks\DataStructureIdentifierHook\getAdditionalFinisherSheets
‪array getAdditionalFinisherSheets(string $persistenceIdentifier, array $formDefinition)
Definition: DataStructureIdentifierHook.php:205
‪TYPO3\CMS\Form\Hooks\DataStructureIdentifierHook\getLanguageService
‪LanguageService getLanguageService()
Definition: DataStructureIdentifierHook.php:399
‪TYPO3\CMS\Core\Error\Exception
Definition: Exception.php:22
‪TYPO3\CMS\Form\Hooks\DataStructureIdentifierHook\L10N_PREFIX
‪const L10N_PREFIX
Definition: DataStructureIdentifierHook.php:52
‪TYPO3\CMS\Form\Domain\Configuration\ConfigurationService
Definition: ConfigurationService.php:51
‪TYPO3\CMS\Form\Mvc\Configuration\Exception\ParseErrorException
Definition: ParseErrorException.php:25
‪TYPO3\CMS\Core\Messaging\FlashMessage
Definition: FlashMessage.php:24
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:24
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Form\Hooks\DataStructureIdentifierHook\getDataStructureIdentifierPostProcess
‪array getDataStructureIdentifierPostProcess(array $fieldTca, string $tableName, string $fieldName, array $row, array $identifier)
Definition: DataStructureIdentifierHook.php:66
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:42
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManagerInterface
Definition: FormPersistenceManagerInterface.php:32
‪TYPO3\CMS\Extbase\Object\ObjectManager
Definition: ObjectManager.php:28
‪TYPO3\CMS\Core\Messaging\FlashMessageService
Definition: FlashMessageService.php:27
‪TYPO3\CMS\Core\Messaging\AbstractMessage\ERROR
‪const ERROR
Definition: AbstractMessage.php:31
‪TYPO3\CMS\Form\Mvc\Configuration\Exception\NoSuchFileException
Definition: NoSuchFileException.php:25