TYPO3 CMS  TYPO3_8-7
FormManagerController.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 
35 
42 {
43 
47  protected $databaseService;
48 
53  public function injectDatabaseService(\TYPO3\CMS\Form\Service\DatabaseService $databaseService)
54  {
55  $this->databaseService = $databaseService;
56  }
57 
63  protected $defaultViewObjectName = BackendTemplateView::class;
64 
70  public function indexAction()
71  {
72  $this->registerDocheaderButtons();
73  $this->view->getModuleTemplate()->setModuleName($this->request->getPluginName() . '_' . $this->request->getControllerName());
74  $this->view->getModuleTemplate()->setFlashMessageQueue($this->controllerContext->getFlashMessageQueue());
75 
76  $this->view->assign('forms', $this->getAvailableFormDefinitions());
77  $this->view->assign('stylesheets', $this->resolveResourcePaths($this->formSettings['formManager']['stylesheets']));
78  $this->view->assign('dynamicRequireJsModules', $this->formSettings['formManager']['dynamicRequireJsModules']);
79  $this->view->assign('formManagerAppInitialData', $this->getFormManagerAppInitialData());
80  if (!empty($this->formSettings['formManager']['javaScriptTranslationFile'])) {
81  $this->getPageRenderer()->addInlineLanguageLabelFile($this->formSettings['formManager']['javaScriptTranslationFile']);
82  }
83  }
84 
91  public function initializeCreateAction()
92  {
93  $this->defaultViewObjectName = JsonView::class;
94  }
95 
106  public function createAction(string $formName, string $templatePath, string $prototypeName, string $savePath)
107  {
108  if (!$this->isValidTemplatePath($prototypeName, $templatePath)) {
109  throw new FormException(sprintf('The template path "%s" is not allowed', $templatePath), 1329233410);
110  }
111  if (empty($formName)) {
112  throw new FormException(sprintf('No form name', $templatePath), 1472312204);
113  }
114 
115  $templatePath = GeneralUtility::getFileAbsFileName($templatePath);
116  $form = Yaml::parse(file_get_contents($templatePath));
117  $form['label'] = $formName;
118  $form['identifier'] = $this->formPersistenceManager->getUniqueIdentifier($this->convertFormNameToIdentifier($formName));
119  $form['prototypeName'] = $prototypeName;
120 
121  $formPersistenceIdentifier = $this->formPersistenceManager->getUniquePersistenceIdentifier($form['identifier'], $savePath);
122 
123  if (
124  isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/form']['beforeFormCreate'])
125  && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/form']['beforeFormCreate'])
126  ) {
127  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/form']['beforeFormCreate'] as $className) {
128  $hookObj = GeneralUtility::makeInstance($className);
129  if (method_exists($hookObj, 'beforeFormCreate')) {
130  $form = $hookObj->beforeFormCreate(
131  $formPersistenceIdentifier,
132  $form
133  );
134  }
135  }
136  }
137 
138  $response = [
139  'status' => 'success',
140  'url' => $this->controllerContext->getUriBuilder()->uriFor('index', ['formPersistenceIdentifier' => $formPersistenceIdentifier], 'FormEditor')
141  ];
142 
143  try {
144  $this->formPersistenceManager->save($formPersistenceIdentifier, $form);
145  } catch (PersistenceManagerException $e) {
146  $response = [
147  'status' => 'error',
148  'message' => $e->getMessage(),
149  'code' => $e->getCode(),
150  ];
151  }
152 
153  $this->view->assign('response', $response);
154  // createAction uses the Extbase JsonView::class.
155  // That's why we have to set the view variables in this way.
156  $this->view->setVariablesToRender([
157  'response',
158  ]);
159  }
160 
167  public function initializeDuplicateAction()
168  {
169  $this->defaultViewObjectName = JsonView::class;
170  }
171 
180  public function duplicateAction(string $formName, string $formPersistenceIdentifier, string $savePath)
181  {
182  $formToDuplicate = $this->formPersistenceManager->load($formPersistenceIdentifier);
183  $formToDuplicate['label'] = $formName;
184  $formToDuplicate['identifier'] = $this->formPersistenceManager->getUniqueIdentifier($this->convertFormNameToIdentifier($formName));
185 
186  $formPersistenceIdentifier = $this->formPersistenceManager->getUniquePersistenceIdentifier($formToDuplicate['identifier'], $savePath);
187 
188  if (
189  isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/form']['beforeFormDuplicate'])
190  && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/form']['beforeFormDuplicate'])
191  ) {
192  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/form']['beforeFormDuplicate'] as $className) {
193  $hookObj = GeneralUtility::makeInstance($className);
194  if (method_exists($hookObj, 'beforeFormDuplicate')) {
195  $formToDuplicate = $hookObj->beforeFormDuplicate(
196  $formPersistenceIdentifier,
197  $formToDuplicate
198  );
199  }
200  }
201  }
202 
203  $response = [
204  'status' => 'success',
205  'url' => $this->controllerContext->getUriBuilder()->uriFor('index', ['formPersistenceIdentifier' => $formPersistenceIdentifier], 'FormEditor')
206  ];
207 
208  try {
209  $this->formPersistenceManager->save($formPersistenceIdentifier, $formToDuplicate);
210  } catch (PersistenceManagerException $e) {
211  $response = [
212  'status' => 'error',
213  'message' => $e->getMessage(),
214  'code' => $e->getCode(),
215  ];
216  }
217 
218  $this->view->assign('response', $response);
219  // createAction uses the Extbase JsonView::class.
220  // That's why we have to set the view variables in this way.
221  $this->view->setVariablesToRender([
222  'response',
223  ]);
224  }
225 
232  public function initializeReferencesAction()
233  {
234  $this->defaultViewObjectName = JsonView::class;
235  }
236 
243  public function referencesAction(string $formPersistenceIdentifier)
244  {
245  $this->view->assign('references', $this->getProcessedReferencesRows($formPersistenceIdentifier));
246  $this->view->assign('formPersistenceIdentifier', $formPersistenceIdentifier);
247  // referencesAction uses the extbase JsonView::class.
248  // That's why we have to set the view variables in this way.
249  $this->view->setVariablesToRender([
250  'references',
251  'formPersistenceIdentifier'
252  ]);
253  }
254 
261  public function deleteAction(string $formPersistenceIdentifier)
262  {
263  if (empty($this->databaseService->getReferencesByPersistenceIdentifier($formPersistenceIdentifier))) {
264  if (
265  isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/form']['beforeFormDelete'])
266  && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/form']['beforeFormDelete'])
267  ) {
268  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/form']['beforeFormDelete'] as $className) {
269  $hookObj = GeneralUtility::makeInstance($className);
270  if (method_exists($hookObj, 'beforeFormDelete')) {
271  $hookObj->beforeFormDelete(
272  $formPersistenceIdentifier
273  );
274  }
275  }
276  }
277 
278  $this->formPersistenceManager->delete($formPersistenceIdentifier);
279  } else {
280  $controllerConfiguration = TranslationService::getInstance()->translateValuesRecursive(
281  $this->formSettings['formManager']['controller'],
282  $this->formSettings['formManager']['translationFile']
283  );
284 
285  $this->addFlashMessage(
286  sprintf($controllerConfiguration['deleteAction']['errorMessage'], $formPersistenceIdentifier),
287  $controllerConfiguration['deleteAction']['errorTitle'],
289  true
290  );
291  }
292  $this->redirect('index');
293  }
294 
305  protected function getAccessibleFormStorageFolders(): array
306  {
307  $preparedAccessibleFormStorageFolders = [];
308  foreach ($this->formPersistenceManager->getAccessibleFormStorageFolders() as $identifier => $folder) {
309  $preparedAccessibleFormStorageFolders[] = [
310  'label' => $folder->getName(),
311  'value' => $identifier
312  ];
313  }
314 
315  if ($this->formSettings['persistenceManager']['allowSaveToExtensionPaths']) {
316  foreach ($this->formPersistenceManager->getAccessibleExtensionFolders() as $relativePath => $fullPath) {
317  $preparedAccessibleFormStorageFolders[] = [
318  'label' => $relativePath,
319  'value' => $relativePath
320  ];
321  }
322  }
323 
324  return $preparedAccessibleFormStorageFolders;
325  }
326 
333  protected function getFormManagerAppInitialData(): string
334  {
335  $formManagerAppInitialData = [
336  'selectablePrototypesConfiguration' => $this->formSettings['formManager']['selectablePrototypesConfiguration'],
337  'accessibleFormStorageFolders' => $this->getAccessibleFormStorageFolders(),
338  'endpoints' => [
339  'create' => $this->controllerContext->getUriBuilder()->uriFor('create'),
340  'duplicate' => $this->controllerContext->getUriBuilder()->uriFor('duplicate'),
341  'delete' => $this->controllerContext->getUriBuilder()->uriFor('delete'),
342  'references' => $this->controllerContext->getUriBuilder()->uriFor('references')
343  ],
344  ];
345 
346  $formManagerAppInitialData = ArrayUtility::reIndexNumericArrayKeysRecursive($formManagerAppInitialData);
347  $formManagerAppInitialData = TranslationService::getInstance()->translateValuesRecursive(
348  $formManagerAppInitialData,
349  $this->formSettings['formManager']['translationFile']
350  );
351  return json_encode($formManagerAppInitialData);
352  }
353 
359  protected function getAvailableFormDefinitions(): array
360  {
361  $allReferencesForFileUid = $this->databaseService->getAllReferencesForFileUid();
362  $allReferencesForPersistenceIdentifier = $this->databaseService->getAllReferencesForPersistenceIdentifier();
363 
364  $availableFormDefinitions = [];
365  foreach ($this->formPersistenceManager->listForms() as $formDefinition) {
366  $referenceCount = 0;
367  if (
368  isset($formDefinition['fileUid'])
369  && array_key_exists($formDefinition['fileUid'], $allReferencesForFileUid)
370  ) {
371  $referenceCount = $allReferencesForFileUid[$formDefinition['fileUid']];
372  } elseif (array_key_exists($formDefinition['persistenceIdentifier'], $allReferencesForPersistenceIdentifier)) {
373  $referenceCount = $allReferencesForPersistenceIdentifier[$formDefinition['persistenceIdentifier']];
374  }
375 
376  $formDefinition['referenceCount'] = $referenceCount;
377  $availableFormDefinitions[] = $formDefinition;
378  }
379 
380  return $availableFormDefinitions;
381  }
382 
391  protected function getProcessedReferencesRows(string $persistenceIdentifier): array
392  {
393  if (empty($persistenceIdentifier)) {
394  throw new \InvalidArgumentException('$persistenceIdentifier must not be empty.', 1477071939);
395  }
396 
397  $references = [];
398  $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
399 
400  $referenceRows = $this->databaseService->getReferencesByPersistenceIdentifier($persistenceIdentifier);
401  foreach ($referenceRows as &$referenceRow) {
402  $record = $this->getRecord($referenceRow['tablename'], $referenceRow['recuid']);
403  if (!$record) {
404  continue;
405  }
406  $pageRecord = $this->getRecord('pages', $record['pid']);
407  $urlParameters = [
408  'edit' => [
409  $referenceRow['tablename'] => [
410  $referenceRow['recuid'] => 'edit'
411  ]
412  ],
413  'returnUrl' => $this->getModuleUrl('web_FormFormbuilder')
414  ];
415 
416  $references[] = [
417  'recordPageTitle' => is_array($pageRecord) ? $this->getRecordTitle('pages', $pageRecord) : '',
418  'recordTitle' => $this->getRecordTitle($referenceRow['tablename'], $record, true),
419  'recordIcon' => $iconFactory->getIconForRecord($referenceRow['tablename'], $record, Icon::SIZE_SMALL)->render(),
420  'recordUid' => $referenceRow['recuid'],
421  'recordEditUrl' => $this->getModuleUrl('record_edit', $urlParameters),
422  ];
423  }
424  return $references;
425  }
426 
438  protected function isValidTemplatePath(string $prototypeName, string $templatePath): bool
439  {
440  $isValid = false;
441  foreach ($this->formSettings['formManager']['selectablePrototypesConfiguration'] as $prototypesConfiguration) {
442  if ($prototypesConfiguration['identifier'] !== $prototypeName) {
443  continue;
444  }
445  foreach ($prototypesConfiguration['newFormTemplates'] as $templatesConfiguration) {
446  if ($templatesConfiguration['templatePath'] !== $templatePath) {
447  continue;
448  }
449  $isValid = true;
450  break;
451  }
452  }
453 
454  $templatePath = GeneralUtility::getFileAbsFileName($templatePath);
455  if (!is_file($templatePath)) {
456  $isValid = false;
457  }
458 
459  return $isValid;
460  }
461 
467  protected function registerDocheaderButtons()
468  {
470  $buttonBar = $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar();
471  $currentRequest = $this->request;
472  $moduleName = $currentRequest->getPluginName();
473  $getVars = $this->request->getArguments();
474 
475  $mayMakeShortcut = $this->getBackendUser()->mayMakeShortcut();
476  if ($mayMakeShortcut) {
477  $extensionName = $currentRequest->getControllerExtensionName();
478  if (count($getVars) === 0) {
479  $modulePrefix = strtolower('tx_' . $extensionName . '_' . $moduleName);
480  $getVars = ['id', 'M', $modulePrefix];
481  }
482 
483  $shortcutButton = $buttonBar->makeShortcutButton()
484  ->setModuleName($moduleName)
485  ->setDisplayName($this->getLanguageService()->sL('LLL:EXT:form/Resources/Private/Language/Database.xlf:module.shortcut_name'))
486  ->setGetVariables($getVars);
487  $buttonBar->addButton($shortcutButton);
488  }
489 
490  if (isset($getVars['action']) && $getVars['action'] !== 'index') {
491  $backButton = $buttonBar->makeLinkButton()
492  ->setTitle($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_common.xlf:back'))
493  ->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-view-go-up', Icon::SIZE_SMALL))
494  ->setHref($this->getModuleUrl($moduleName));
495  $buttonBar->addButton($backButton);
496  } else {
497  $addFormButton = $buttonBar->makeLinkButton()
498  ->setDataAttributes(['identifier' => 'newForm'])
499  ->setHref('#')
500  ->setTitle($this->getLanguageService()->sL('LLL:EXT:form/Resources/Private/Language/Database.xlf:formManager.create_new_form'))
501  ->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-document-new', Icon::SIZE_SMALL));
502  $buttonBar->addButton($addFormButton, ButtonBar::BUTTON_POSITION_LEFT);
503  }
504  }
505 
512  protected function convertFormNameToIdentifier(string $formName): string
513  {
514  $formIdentifier = preg_replace('/[^a-zA-Z0-9-_]/', '', $formName);
515  $formIdentifier = lcfirst($formIdentifier);
516  return $formIdentifier;
517  }
518 
526  protected function getRecord(string $table, int $uid)
527  {
528  return BackendUtility::getRecord($table, $uid);
529  }
530 
539  protected function getRecordTitle(string $table, array $row, bool $prep = false): string
540  {
541  return BackendUtility::getRecordTitle($table, $row, $prep);
542  }
543 
551  protected function getModuleUrl(string $moduleName, array $urlParameters = []): string
552  {
553  return BackendUtility::getModuleUrl($moduleName, $urlParameters);
554  }
555 
562  {
563  return $GLOBALS['BE_USER'];
564  }
565 
571  protected function getLanguageService(): LanguageService
572  {
573  return $GLOBALS['LANG'];
574  }
575 
581  protected function getPageRenderer(): PageRenderer
582  {
583  return GeneralUtility::makeInstance(PageRenderer::class);
584  }
585 }
createAction(string $formName, string $templatePath, string $prototypeName, string $savePath)
isValidTemplatePath(string $prototypeName, string $templatePath)
duplicateAction(string $formName, string $formPersistenceIdentifier, string $savePath)
getProcessedReferencesRows(string $persistenceIdentifier)
getModuleUrl(string $moduleName, array $urlParameters=[])
static reIndexNumericArrayKeysRecursive(array $array)
static getFileAbsFileName($filename, $_=null, $_2=null)
redirect($actionName, $controllerName=null, $extensionName=null, array $arguments=null, $pageUid=null, $delay=0, $statusCode=303)
getRecordTitle(string $table, array $row, bool $prep=false)
static makeInstance($className,... $constructorArguments)
static getRecordTitle($table, $row, $prep=false, $forceResult=true)
referencesAction(string $formPersistenceIdentifier)
static getRecord($table, $uid, $fields=' *', $where='', $useDeleteClause=true)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
injectDatabaseService(\TYPO3\CMS\Form\Service\DatabaseService $databaseService)
addFlashMessage($messageBody, $messageTitle='', $severity=\TYPO3\CMS\Core\Messaging\AbstractMessage::OK, $storeInSession=true)