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