[BUGFIX] EXT:form - catch exceptions within page module and form engine 01/52701/5
authorRalf Zimmermann <ralf.zimmermann@tritum.de>
Thu, 4 May 2017 10:58:06 +0000 (12:58 +0200)
committerFrans Saris <franssaris@gmail.com>
Thu, 7 Sep 2017 09:37:32 +0000 (11:37 +0200)
* Show messages within page module and form engine if the backend user
  does not have access to the selected form definition.
* Show flash messages within page module and form engine if the
  ext:form configuration is invalid.

Resolves: #80678
Resolves: #81113
Releases: master, 8.7
Change-Id: I9646b31ac44752b8871635c8f1a04547872e715d
Reviewed-on: https://review.typo3.org/52701
Reviewed-by: Bjoern Jacob <bjoern.jacob@tritum.de>
Tested-by: Bjoern Jacob <bjoern.jacob@tritum.de>
Reviewed-by: Daniel Lorenz <daniel.lorenz@extco.de>
Reviewed-by: Frans Saris <franssaris@gmail.com>
Tested-by: Frans Saris <franssaris@gmail.com>
typo3/sysext/form/Classes/Hooks/DataStructureIdentifierHook.php
typo3/sysext/form/Classes/Hooks/FormPagePreviewRenderer.php
typo3/sysext/form/Classes/Mvc/Configuration/YamlSource.php
typo3/sysext/form/Resources/Private/Language/Database.xlf

index 743e333..13436ba 100644 (file)
@@ -15,12 +15,18 @@ namespace TYPO3\CMS\Form\Hooks;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Messaging\AbstractMessage;
+use TYPO3\CMS\Core\Messaging\FlashMessage;
+use TYPO3\CMS\Core\Messaging\FlashMessageService;
 use TYPO3\CMS\Core\Utility\ArrayUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Object\ObjectManager;
 use TYPO3\CMS\Form\Domain\Configuration\ConfigurationService;
+use TYPO3\CMS\Form\Mvc\Configuration\Exception\NoSuchFileException;
+use TYPO3\CMS\Form\Mvc\Configuration\Exception\ParseErrorException;
 use TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManagerInterface;
 use TYPO3\CMS\Form\Service\TranslationService;
+use TYPO3\CMS\Lang\LanguageService;
 
 /**
  * Hooks into flex form handling of backend for tt_content form elements:
@@ -35,6 +41,11 @@ class DataStructureIdentifierHook
 {
 
     /**
+     * Localisation prefix
+     */
+    const L10N_PREFIX = 'LLL:EXT:form/Resources/Private/Language/Database.xlf:';
+
+    /**
      * The data structure depends on a current form selection (persistenceIdentifier)
      * and if the field "overrideFinishers" is active. Add both to the identifier to
      * hand these information over to parseDataStructureByIdentifierPostProcess() hook.
@@ -90,27 +101,51 @@ class DataStructureIdentifierHook
     public function parseDataStructureByIdentifierPostProcess(array $dataStructure, array $identifier): array
     {
         if (isset($identifier['ext-form-persistenceIdentifier'])) {
-            // Add list of existing forms to drop down if we find our key in the identifier
-            $formPersistenceManager = GeneralUtility::makeInstance(ObjectManager::class)->get(FormPersistenceManagerInterface::class);
-            foreach ($formPersistenceManager->listForms() as $form) {
-                $dataStructure['sheets']['sDEF']['ROOT']['el']['settings.persistenceIdentifier']['TCEforms']['config']['items'][] = [
-                    $form['name'] . ' (' . $form['persistenceIdentifier'] . ')',
-                    $form['persistenceIdentifier'],
-                ];
-            }
+            try {
+                // Add list of existing forms to drop down if we find our key in the identifier
+                $formPersistenceManager = GeneralUtility::makeInstance(ObjectManager::class)->get(FormPersistenceManagerInterface::class);
+                $formIsAccessible = false;
+                foreach ($formPersistenceManager->listForms() as $form) {
+                    if ($form['persistenceIdentifier'] === $identifier['ext-form-persistenceIdentifier']) {
+                        $formIsAccessible = true;
+                    }
 
-            // If a specific form is selected and if finisher override is active, add finisher sheets
-            if (!empty($identifier['ext-form-persistenceIdentifier'])
-                && isset($identifier['ext-form-overrideFinishers'])
-                && $identifier['ext-form-overrideFinishers'] === true
-            ) {
-                $persistenceIdentifier = $identifier['ext-form-persistenceIdentifier'];
-                $formDefinition = $formPersistenceManager->load($persistenceIdentifier);
-                $newSheets = $this->getAdditionalFinisherSheets($persistenceIdentifier, $formDefinition);
-                ArrayUtility::mergeRecursiveWithOverrule(
-                    $dataStructure,
-                    $newSheets
-                );
+                    $dataStructure['sheets']['sDEF']['ROOT']['el']['settings.persistenceIdentifier']['TCEforms']['config']['items'][] = [
+                        $form['name'] . ' (' . $form['persistenceIdentifier'] . ')',
+                        $form['persistenceIdentifier'],
+                    ];
+                }
+
+                if (!empty($identifier['ext-form-persistenceIdentifier']) && !$formIsAccessible) {
+                    $dataStructure['sheets']['sDEF']['ROOT']['el']['settings.persistenceIdentifier']['TCEforms']['config']['items'][] = [
+                        sprintf(
+                            $this->getLanguageService()->sL(self::L10N_PREFIX . 'tt_content.preview.inaccessiblePersistenceIdentifier'),
+                            $identifier['ext-form-persistenceIdentifier']
+                        ),
+                        $identifier['ext-form-persistenceIdentifier'],
+                    ];
+                }
+
+                // If a specific form is selected and if finisher override is active, add finisher sheets
+                if (!empty($identifier['ext-form-persistenceIdentifier'])
+                    && $formIsAccessible
+                    && isset($identifier['ext-form-overrideFinishers'])
+                    && $identifier['ext-form-overrideFinishers'] === true
+                ) {
+                    $persistenceIdentifier = $identifier['ext-form-persistenceIdentifier'];
+                    $formDefinition = $formPersistenceManager->load($persistenceIdentifier);
+                    $newSheets = $this->getAdditionalFinisherSheets($persistenceIdentifier, $formDefinition);
+                    ArrayUtility::mergeRecursiveWithOverrule(
+                        $dataStructure,
+                        $newSheets
+                    );
+                }
+            } catch (NoSuchFileException $e) {
+                $dataStructure = $this->addSelectedPersistenceIdentifier($identifier['ext-form-persistenceIdentifier'], $dataStructure);
+                $this->addInvalidFrameworkConfigurationFlashMessage($e);
+            } catch (ParseErrorException $e) {
+                $dataStructure = $this->addSelectedPersistenceIdentifier($identifier['ext-form-persistenceIdentifier'], $dataStructure);
+                $this->addInvalidFrameworkConfigurationFlashMessage($e);
             }
         }
         return $dataStructure;
@@ -262,4 +297,56 @@ class DataStructureIdentifierHook
         }
         return $dottedPath;
     }
+
+    /**
+     * @param string $persistenceIdentifier
+     * @param array $dataStructure
+     * @return array
+     */
+    protected function addSelectedPersistenceIdentifier(string $persistenceIdentifier, array $dataStructure): array
+    {
+        if (!empty($persistenceIdentifier)) {
+            $dataStructure['sheets']['sDEF']['ROOT']['el']['settings.persistenceIdentifier']['TCEforms']['config']['items'][] = [
+                sprintf(
+                    $this->getLanguageService()->sL(self::L10N_PREFIX . 'tt_content.preview.inaccessiblePersistenceIdentifier'),
+                    $persistenceIdentifier
+                ),
+                $persistenceIdentifier,
+            ];
+        }
+
+        return $dataStructure;
+    }
+
+    /**
+     * @param \Exception $e
+     */
+    protected function addInvalidFrameworkConfigurationFlashMessage(\Exception $e)
+    {
+        $messageText = sprintf(
+            $this->getLanguageService()->sL(self::L10N_PREFIX . 'tt_content.preview.invalidFrameworkConfiguration.text'),
+            $e->getMessage()
+        );
+
+        GeneralUtility::makeInstance(ObjectManager::class)
+            ->get(FlashMessageService::class)
+            ->getMessageQueueByIdentifier('core.template.flashMessages')
+            ->enqueue(
+                GeneralUtility::makeInstance(
+                    FlashMessage::class,
+                    $messageText,
+                    $this->getLanguageService()->sL(self::L10N_PREFIX . 'tt_content.preview.invalidFrameworkConfiguration.title'),
+                    AbstractMessage::ERROR,
+                    true
+                )
+            );
+    }
+
+    /**
+     * @return LanguageService
+     */
+    protected function getLanguageService(): LanguageService
+    {
+        return $GLOBALS['LANG'];
+    }
 }
index 2ad809d..b12da01 100644 (file)
@@ -18,10 +18,15 @@ namespace TYPO3\CMS\Form\Hooks;
 use TYPO3\CMS\Backend\View\PageLayoutViewDrawItemHookInterface;
 use TYPO3\CMS\Core\Error\Exception;
 use TYPO3\CMS\Core\Localization\LanguageService;
+use TYPO3\CMS\Core\Messaging\AbstractMessage;
+use TYPO3\CMS\Core\Messaging\FlashMessage;
+use TYPO3\CMS\Core\Messaging\FlashMessageService;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Object\ObjectManager;
 use TYPO3\CMS\Extbase\Service\FlexFormService;
+use TYPO3\CMS\Form\Mvc\Configuration\Exception\NoSuchFileException;
 use TYPO3\CMS\Form\Mvc\Configuration\Exception\ParseErrorException;
+use TYPO3\CMS\Form\Mvc\Persistence\Exception\PersistenceManagerException;
 use TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManagerInterface;
 
 /**
@@ -30,6 +35,11 @@ use TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManagerInterface;
 class FormPagePreviewRenderer implements PageLayoutViewDrawItemHookInterface
 {
     /**
+     * Localisation prefix
+     */
+    const L10N_PREFIX = 'LLL:EXT:form/Resources/Private/Language/Database.xlf:';
+
+    /**
      * Preprocesses the preview rendering of the content element "form_formframework".
      *
      * @param \TYPO3\CMS\Backend\View\PageLayoutView $parentObject Calling parent object
@@ -54,29 +64,40 @@ class FormPagePreviewRenderer implements PageLayoutViewDrawItemHookInterface
 
             $persistenceIdentifier = $flexFormData['settings']['persistenceIdentifier'];
             if (!empty($persistenceIdentifier)) {
-                $formPersistenceManager = GeneralUtility::makeInstance(ObjectManager::class)->get(FormPersistenceManagerInterface::class);
                 try {
-                    $formDefinition = $formPersistenceManager->load($persistenceIdentifier);
-                    $formLabel = $formDefinition['label'];
+                    $formPersistenceManager = GeneralUtility::makeInstance(ObjectManager::class)->get(FormPersistenceManagerInterface::class);
+
+                    try {
+                        $formDefinition = $formPersistenceManager->load($persistenceIdentifier);
+                        $formLabel = $formDefinition['label'];
+                    } catch (ParseErrorException $e) {
+                        $formLabel = sprintf(
+                            $this->getLanguageService()->sL(self::L10N_PREFIX . 'tt_content.preview.invalidPersistenceIdentifier'),
+                            $persistenceIdentifier
+                        );
+                    } catch (PersistenceManagerException $e) {
+                        $formLabel = sprintf(
+                            $this->getLanguageService()->sL(self::L10N_PREFIX . 'tt_content.preview.inaccessiblePersistenceIdentifier'),
+                            $persistenceIdentifier
+                        );
+                    } catch (Exception $e) {
+                        $formLabel = sprintf(
+                            $this->getLanguageService()->sL(self::L10N_PREFIX . 'tt_content.preview.notExistingdPersistenceIdentifier'),
+                            $persistenceIdentifier
+                        );
+                    }
+                } catch (NoSuchFileException $e) {
+                    $this->addInvalidFrameworkConfigurationFlashMessage($e);
+                    $formLabel = $messageText;
                 } catch (ParseErrorException $e) {
+                    $this->addInvalidFrameworkConfigurationFlashMessage($e);
                     $formLabel = sprintf(
-                        $this->getLanguageService()->sL(
-                            'LLL:EXT:form/Resources/Private/Language/Database.xlf:tt_content.preview.invalidPersistenceIdentifier'
-                        ),
-                        $persistenceIdentifier
-                    );
-                } catch (Exception $e) {
-                    $formLabel = sprintf(
-                        $this->getLanguageService()->sL(
-                            'LLL:EXT:form/Resources/Private/Language/Database.xlf:tt_content.preview.notExistingdPersistenceIdentifier'
-                        ),
+                        $this->getLanguageService()->sL(self::L10N_PREFIX . 'tt_content.preview.invalidFrameworkConfiguration'),
                         $persistenceIdentifier
                     );
                 }
             } else {
-                $formLabel = $this->getLanguageService()->sL(
-                    'LLL:EXT:form/Resources/Private/Language/Database.xlf:tt_content.preview.noPersistenceIdentifier'
-                );
+                $formLabel = $this->getLanguageService()->sL(self::L10N_PREFIX . 'tt_content.preview.noPersistenceIdentifier');
             }
 
             $itemContent .= $parentObject->linkEditContent(
@@ -89,6 +110,30 @@ class FormPagePreviewRenderer implements PageLayoutViewDrawItemHookInterface
     }
 
     /**
+     * @param \Exception $e
+     */
+    protected function addInvalidFrameworkConfigurationFlashMessage(\Exception $e)
+    {
+        $messageText = sprintf(
+            $this->getLanguageService()->sL(self::L10N_PREFIX . 'tt_content.preview.invalidFrameworkConfiguration.text'),
+            $e->getMessage()
+        );
+
+        GeneralUtility::makeInstance(ObjectManager::class)
+            ->get(FlashMessageService::class)
+            ->getMessageQueueByIdentifier('core.template.flashMessages')
+            ->enqueue(
+                GeneralUtility::makeInstance(
+                    FlashMessage::class,
+                    $messageText,
+                    $this->getLanguageService()->sL(self::L10N_PREFIX . 'tt_content.preview.invalidFrameworkConfiguration.title'),
+                    AbstractMessage::ERROR,
+                    true
+                )
+            );
+    }
+
+    /**
      * @return LanguageService
      */
     protected function getLanguageService(): LanguageService
index 31afdd3..d342c54 100644 (file)
@@ -70,6 +70,12 @@ class YamlSource
             if ($fileToLoad instanceof File) {
                 $fileIdentifier = $fileToLoad->getIdentifier();
                 $rawYamlContent = $fileToLoad->getContents();
+                if ($rawYamlContent === false) {
+                    throw new NoSuchFileException(
+                        'The file "' . $fileToLoad . '" does not exist.',
+                        1498802253
+                    );
+                }
             } else {
                 $fileIdentifier = $fileToLoad;
                 $fileToLoad = GeneralUtility::getFileAbsFileName($fileToLoad);
index fcd8442..0246f89 100644 (file)
             <trans-unit id="tt_content.preview.invalidPersistenceIdentifier" xml:space="preserve">
                 <source>Invalid form "%s".</source>
             </trans-unit>
+            <trans-unit id="tt_content.preview.inaccessiblePersistenceIdentifier" xml:space="preserve">
+                <source>"%s" (no read access).</source>
+            </trans-unit>
             <trans-unit id="tt_content.preview.notExistingdPersistenceIdentifier" xml:space="preserve">
                 <source>The form "%s" does not exists.</source>
             </trans-unit>
+            <trans-unit id="tt_content.preview.invalidFrameworkConfiguration" xml:space="preserve">
+                <source>"%s" (Invalid ext:form configuration).</source>
+            </trans-unit>
+            <trans-unit id="tt_content.preview.invalidFrameworkConfiguration.text" xml:space="preserve">
+                <source>Invalid ext:form configuration. %s</source>
+            </trans-unit>
+            <trans-unit id="tt_content.preview.invalidFrameworkConfiguration.title" xml:space="preserve">
+                <source>Invalid configuration.</source>
+            </trans-unit>
 
             <trans-unit id="tt_content.finishersDefinition.EmailToSender.label" xml:space="preserve">
                 <source>Email to sender</source>