TYPO3CMS  8
 All Classes Namespaces Files Functions Variables Pages
FormEditorController.php
Go to the documentation of this file.
1 <?php
2 declare(strict_types=1);
3 namespace TYPO3\CMS\Form\Controller;
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 
32 
39 {
40 
46  protected $defaultViewObjectName = BackendTemplateView::class;
47 
52 
62  public function indexAction(string $formPersistenceIdentifier, string $prototypeName = null)
63  {
64  $this->registerDocheaderButtons();
65  $this->view->getModuleTemplate()->setModuleName($this->request->getPluginName() . '_' . $this->request->getControllerName());
66  $this->view->getModuleTemplate()->setFlashMessageQueue($this->controllerContext->getFlashMessageQueue());
67 
68  if (
69  strpos($formPersistenceIdentifier, 'EXT:') === 0
70  && !$this->formSettings['persistenceManager']['allowSaveToExtensionPaths']
71  ) {
72  throw new PersistenceManagerException('Edit a extension formDefinition is not allowed.', 1478265661);
73  }
74 
75  $formDefinition = $this->formPersistenceManager->load($formPersistenceIdentifier);
76  $formDefinition = ArrayUtility::stripTagsFromValuesRecursive($formDefinition);
77  if (empty($prototypeName)) {
78  $prototypeName = isset($formDefinition['prototypeName']) ? $formDefinition['prototypeName'] : 'standard';
79  }
80  $formDefinition['prototypeName'] = $prototypeName;
81 
82  $configurationService = $this->objectManager->get(ConfigurationService::class);
83  $this->prototypeConfiguration = $configurationService->getPrototypeConfiguration($prototypeName);
84 
85  $formEditorDefinitions = $this->getFormEditorDefinitions();
86 
87  $formEditorAppInitialData = [
88  'formEditorDefinitions' => $formEditorDefinitions,
89  'formDefinition' => $formDefinition,
90  'formPersistenceIdentifier' => $formPersistenceIdentifier,
91  'prototypeName' => $prototypeName,
92  'endpoints' => [
93  'formPageRenderer' => $this->controllerContext->getUriBuilder()->uriFor('renderFormPage'),
94  'saveForm' => $this->controllerContext->getUriBuilder()->uriFor('saveForm')
95  ],
96  'additionalViewModelModules' => $this->prototypeConfiguration['formEditor']['dynamicRequireJsModules']['additionalViewModelModules'],
97  'maximumUndoSteps' => $this->prototypeConfiguration['formEditor']['maximumUndoSteps'],
98  ];
99 
100  $this->view->assign('formEditorAppInitialData', json_encode($formEditorAppInitialData));
101  $this->view->assign('stylesheets', $this->resolveResourcePaths($this->prototypeConfiguration['formEditor']['stylesheets']));
102  $this->view->assign('formEditorTemplates', $this->renderFormEditorTemplates(
103  $this->prototypeConfiguration['formEditor']['formEditorTemplates'],
104  $formEditorDefinitions
105  ));
106  $this->view->assign('dynamicRequireJsModules', $this->prototypeConfiguration['formEditor']['dynamicRequireJsModules']);
107 
108  $popupWindowWidth = 700;
109  $popupWindowHeight = 750;
110  $popupWindowSize = ($this->getBackendUser()->getTSConfigVal('options.popupWindowSize'))
111  ? trim($this->getBackendUser()->getTSConfigVal('options.popupWindowSize'))
112  : null;
113  if (!empty($popupWindowSize)) {
114  list($popupWindowWidth, $popupWindowHeight) = GeneralUtility::intExplode('x', $popupWindowSize);
115  }
116 
117  $addInlineSettings = [
118  'FormEditor' => [
119  'typo3WinBrowserUrl' => BackendUtility::getModuleUrl('wizard_element_browser'),
120  ],
121  'Popup' => [
122  'PopupWindow' => [
123  'width' => $popupWindowWidth,
124  'height' => $popupWindowHeight
125  ],
126  ]
127  ];
128 
129  $addInlineSettings = array_replace_recursive(
130  $addInlineSettings,
131  $this->prototypeConfiguration['formEditor']['addInlineSettings']
132  );
133  $this->view->assign('addInlineSettings', $addInlineSettings);
134  }
135 
144  public function saveFormAction(string $formPersistenceIdentifier, array $formDefinition): string
145  {
146  $formDefinition = ArrayUtility::stripTagsFromValuesRecursive($formDefinition);
147  $formDefinition = $this->convertJsonArrayToAssociativeArray($formDefinition);
148  $this->formPersistenceManager->save($formPersistenceIdentifier, $formDefinition);
149  return '';
150  }
151 
162  public function renderFormPageAction(array $formDefinition, int $pageIndex, string $prototypeName = null): string
163  {
164  $formDefinition = ArrayUtility::stripTagsFromValuesRecursive($formDefinition);
165  $formDefinition = $this->convertJsonArrayToAssociativeArray($formDefinition);
166  if (empty($prototypeName)) {
167  $prototypeName = isset($formDefinition['prototypeName']) ? $formDefinition['prototypeName'] : 'standard';
168  }
169 
170  $formFactory = $this->objectManager->get(ArrayFormFactory::class);
171  $formDefinition = $formFactory->build($formDefinition, $prototypeName);
172  $formDefinition->setRenderingOption('previewMode', true);
173  $form = $formDefinition->bind($this->request, $this->response);
174  $form->overrideCurrentPage($pageIndex);
175  return $form->render();
176  }
177 
185  protected function getInsertRenderablesPanelConfiguration(array $formElementsDefinition): array
186  {
187  $formElementGroups = isset($this->prototypeConfiguration['formEditor']['formElementGroups']) ? $this->prototypeConfiguration['formEditor']['formElementGroups'] : [];
188  $formElementsByGroup = [];
189 
190  foreach ($formElementsDefinition as $formElementName => $formElementConfiguration) {
191  if (!isset($formElementConfiguration['group'])) {
192  continue;
193  }
194  if (!isset($formElementsByGroup[$formElementConfiguration['group']])) {
195  $formElementsByGroup[$formElementConfiguration['group']] = [];
196  }
197 
198  $formElementsByGroup[$formElementConfiguration['group']][] = [
199  'key' => $formElementName,
200  'cssKey' => preg_replace('/[^a-z0-9]/', '-', strtolower($formElementName)),
201  'label' => TranslationService::getInstance()->translate(
202  $formElementConfiguration['label'],
203  null,
204  $this->prototypeConfiguration['formEditor']['translationFile'],
205  null,
206  $formElementConfiguration['label']
207  ),
208  'sorting' => $formElementConfiguration['groupSorting'],
209  'iconIdentifier' => $formElementConfiguration['iconIdentifier'],
210  ];
211  }
212 
213  $formGroups = [];
214  foreach ($formElementGroups as $groupName => $groupConfiguration) {
215  if (!isset($formElementsByGroup[$groupName])) {
216  continue;
217  }
218 
219  usort($formElementsByGroup[$groupName], function ($a, $b) {
220  return $a['sorting'] - $b['sorting'];
221  });
222  unset($formElementsByGroup[$groupName]['sorting']);
223 
224  $formGroups[] = [
225  'key' => $groupName,
226  'elements' => $formElementsByGroup[$groupName],
227  'label' => TranslationService::getInstance()->translate(
228  $groupConfiguration['label'],
229  null,
230  $this->prototypeConfiguration['formEditor']['translationFile'],
231  null,
232  $groupConfiguration['label']
233  ),
234  ];
235  }
236 
237  return $formGroups;
238  }
239 
245  protected function getFormEditorDefinitions(): array
246  {
247  $formEditorDefinitions = [];
248  foreach ([$this->prototypeConfiguration, $this->prototypeConfiguration['formEditor']] as $configuration) {
249  foreach ($configuration as $firstLevelItemKey => $firstLevelItemValue) {
250  if (substr($firstLevelItemKey, -10) !== 'Definition') {
251  continue;
252  }
253  $reducedKey = substr($firstLevelItemKey, 0, -10);
254  foreach ($configuration[$firstLevelItemKey] as $formEditorDefinitionKey => $formEditorDefinitionValue) {
255  if (isset($formEditorDefinitionValue['formEditor'])) {
256  $formEditorDefinitionValue = array_intersect_key($formEditorDefinitionValue, array_flip(['formEditor']));
257  $formEditorDefinitions[$reducedKey][$formEditorDefinitionKey] = $formEditorDefinitionValue['formEditor'];
258  } else {
259  $formEditorDefinitions[$reducedKey][$formEditorDefinitionKey] = $formEditorDefinitionValue;
260  }
261  }
262  }
263  }
264  $formEditorDefinitions = ArrayUtility::reIndexNumericArrayKeysRecursive($formEditorDefinitions);
265  $formEditorDefinitions = TranslationService::getInstance()->translateValuesRecursive(
266  $formEditorDefinitions,
267  $this->prototypeConfiguration['formEditor']['translationFile']
268  );
269  return $formEditorDefinitions;
270  }
271 
277  protected function registerDocheaderButtons()
278  {
280  $buttonBar = $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar();
281  $getVars = $this->request->getArguments();
282 
283  if (isset($getVars['action']) && $getVars['action'] === 'index') {
284  $newPageButton = $buttonBar->makeInputButton()
285  ->setDataAttributes(['action' => 'formeditor-new-page', 'identifier' => 'headerNewPage'])
286  ->setTitle($this->getLanguageService()->sL('LLL:EXT:form/Resources/Private/Language/Database.xlf:formEditor.new_page_button'))
287  ->setName('formeditor-new-page')
288  ->setValue('new-page')
289  ->setClasses('t3-form-element-new-page-button hidden')
290  ->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-page-new', Icon::SIZE_SMALL));
291 
292  $closeButton = $buttonBar->makeLinkButton()
293  ->setDataAttributes(['identifier' => 'closeButton'])
294  ->setHref(BackendUtility::getModuleUrl('web_FormFormbuilder'))
295  ->setClasses('t3-form-element-close-form-button hidden')
296  ->setTitle($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:rm.closeDoc'))
297  ->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-document-close', Icon::SIZE_SMALL));
298 
299  $saveButton = $buttonBar->makeInputButton()
300  ->setDataAttributes(['identifier' => 'saveButton'])
301  ->setTitle($this->getLanguageService()->sL('LLL:EXT:form/Resources/Private/Language/Database.xlf:formEditor.save_button'))
302  ->setName('formeditor-save-form')
303  ->setValue('save')
304  ->setClasses('t3-form-element-save-form-button hidden')
305  ->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-document-save', Icon::SIZE_SMALL))
306  ->setShowLabelText(true);
307 
308  $undoButton = $buttonBar->makeInputButton()
309  ->setDataAttributes(['identifier' => 'undoButton'])
310  ->setTitle($this->getLanguageService()->sL('LLL:EXT:form/Resources/Private/Language/Database.xlf:formEditor.undo_button'))
311  ->setName('formeditor-undo-form')
312  ->setValue('undo')
313  ->setClasses('t3-form-element-undo-form-button hidden disabled')
314  ->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-view-go-back', Icon::SIZE_SMALL));
315 
316  $redoButton = $buttonBar->makeInputButton()
317  ->setDataAttributes(['identifier' => 'redoButton'])
318  ->setTitle($this->getLanguageService()->sL('LLL:EXT:form/Resources/Private/Language/Database.xlf:formEditor.redo_button'))
319  ->setName('formeditor-redo-form')
320  ->setValue('redo')
321  ->setClasses('t3-form-element-redo-form-button hidden disabled')
322  ->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-view-go-forward', Icon::SIZE_SMALL));
323 
324  $buttonBar->addButton($newPageButton, ButtonBar::BUTTON_POSITION_LEFT, 1);
325  $buttonBar->addButton($closeButton, ButtonBar::BUTTON_POSITION_LEFT, 2);
326  $buttonBar->addButton($saveButton, ButtonBar::BUTTON_POSITION_LEFT, 3);
327  $buttonBar->addButton($undoButton, ButtonBar::BUTTON_POSITION_LEFT, 4);
328  $buttonBar->addButton($redoButton, ButtonBar::BUTTON_POSITION_LEFT, 4);
329  }
330  }
331 
351  protected function convertJsonArrayToAssociativeArray(array $input): array
352  {
353  $output = [];
354  foreach ($input as $key => $value) {
355  if (is_integer($key) && is_array($value) && isset($value['_label']) && isset($value['_value'])) {
356  $key = $value['_value'];
357  $value = $value['_label'];
358  }
359  if (is_array($value)) {
360  $output[$key] = $this->convertJsonArrayToAssociativeArray($value);
361  } else {
362  $output[$key] = $value;
363  }
364  }
365  return $output;
366  }
367 
375  protected function renderFormEditorTemplates(array $formEditorTemplates, array $formEditorDefinitions): array
376  {
377  if (
378  !isset($formEditorTemplates['templateRootPaths'])
379  || !is_array($formEditorTemplates['templateRootPaths'])
380  ) {
381  throw new RenderingException(
382  'The option templateRootPaths must be set.',
383  1480294720
384  );
385  }
386  if (
387  !isset($formEditorTemplates['layoutRootPaths'])
388  || !is_array($formEditorTemplates['layoutRootPaths'])
389  ) {
390  throw new RenderingException(
391  'The option layoutRootPaths must be set.',
392  1480294721
393  );
394  }
395  if (
396  !isset($formEditorTemplates['partialRootPaths'])
397  || !is_array($formEditorTemplates['partialRootPaths'])
398  ) {
399  throw new RenderingException(
400  'The option partialRootPaths must be set.',
401  1480294722
402  );
403  }
404 
405  $standaloneView = $this->objectManager->get(StandaloneView::class);
406  $standaloneView->setTemplateRootPaths($formEditorTemplates['templateRootPaths']);
407  $standaloneView->setLayoutRootPaths($formEditorTemplates['layoutRootPaths']);
408  $standaloneView->setPartialRootPaths($formEditorTemplates['partialRootPaths']);
409  $standaloneView->assignMultiple([
410  'insertRenderablesPanelConfiguration' => $this->getInsertRenderablesPanelConfiguration($formEditorDefinitions['formElements'])
411  ]);
412 
413  unset($formEditorTemplates['templateRootPaths']);
414  unset($formEditorTemplates['layoutRootPaths']);
415  unset($formEditorTemplates['partialRootPaths']);
416 
417  $renderedFormEditorTemplates = [];
418  foreach ($formEditorTemplates as $formEditorTemplateName => $formEditorTemplateTemplate) {
419  $renderedFormEditorTemplates[$formEditorTemplateName] = $standaloneView->render($formEditorTemplateTemplate);
420  }
421 
422  return $renderedFormEditorTemplates;
423  }
424 
431  {
432  return $GLOBALS['BE_USER'];
433  }
434 
440  protected function getLanguageService(): LanguageService
441  {
442  return $GLOBALS['LANG'];
443  }
444 }
getInsertRenderablesPanelConfiguration(array $formElementsDefinition)
indexAction(string $formPersistenceIdentifier, string $prototypeName=null)
renderFormPageAction(array $formDefinition, int $pageIndex, string $prototypeName=null)
if(TYPO3_MODE=== 'BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
renderFormEditorTemplates(array $formEditorTemplates, array $formEditorDefinitions)
static intExplode($delimiter, $string, $removeEmptyValues=false, $limit=0)
saveFormAction(string $formPersistenceIdentifier, array $formDefinition)