[!!!][TASK] Redesign FluidTemplateDataProcessorInterface 15/40915/6
authorBenjamin Mack <benni@typo3.org>
Fri, 3 Jul 2015 15:37:19 +0000 (17:37 +0200)
committerHelmut Hummel <helmut.hummel@typo3.org>
Mon, 6 Jul 2015 21:17:30 +0000 (23:17 +0200)
The FluidTemplateDataProcessorInterface introduced with #66907 has been
refactored to DataProcessorInterface.

This decouples it from the Fluid StandaloneView and makes the
ContentObjectRenderer available in the process method so the different
DataProcessor classes do no have to initiate it on their own.

Instead of manipulating the $data property of the ContentObjectRenderer
a new key/value store can be filled/manipulated by the different
dataProcessor classes.

Resolves: #67890
Releases: master
Change-Id: I461dbff039974715e2c8f916efd5d79c159cc8b5
Reviewed-on: http://review.typo3.org/40915
Reviewed-by: Benjamin Mack <benni@typo3.org>
Tested-by: Benjamin Mack <benni@typo3.org>
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Markus Klein <markus.klein@typo3.org>
Reviewed-by: Helmut Hummel <helmut.hummel@typo3.org>
Tested-by: Helmut Hummel <helmut.hummel@typo3.org>
typo3/sysext/core/Documentation/Changelog/7.3/Feature-66907-AddDataProcessingToFluidTemplateContentObject.rst
typo3/sysext/core/Documentation/Changelog/master/Breaking-67890-RedesignFluidTemplateDataProcessorInterfaceToDataProcessorInterface.rst [new file with mode: 0644]
typo3/sysext/frontend/Classes/ContentObject/DataProcessorInterface.php [new file with mode: 0644]
typo3/sysext/frontend/Classes/ContentObject/FluidTemplateContentObject.php
typo3/sysext/frontend/Classes/ContentObject/FluidTemplateDataProcessorInterface.php [deleted file]
typo3/sysext/frontend/Tests/Unit/ContentObject/FluidTemplateContentObjectTest.php

index 87d67cc..f46f296 100644 (file)
@@ -6,7 +6,8 @@ Description
 ===========
 
 cObject FLUIDTEMPLATE has been extended with ``dataProcessing``. This setting can be used to add one or multiple processors to
-manipulate the ``$data`` variable of the currently rendered content object, like tt_content or page.
+manipulate data of the currently rendered content object, like tt_content or page, and fill a key/value store that will be passed
+as variables to the Fluid template, where every key of the key/value store will be available as variable in the Fluid template.
 
 - dataProcessing = array of class references by full namespace
 
@@ -40,4 +41,4 @@ Example:
 Impact
 ======
 
-The data processors can be used in all new projects. There is no interference with any part of existing code.
\ No newline at end of file
+The data processors can be used in all new projects. There is no interference with any part of existing code.
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Breaking-67890-RedesignFluidTemplateDataProcessorInterfaceToDataProcessorInterface.rst b/typo3/sysext/core/Documentation/Changelog/master/Breaking-67890-RedesignFluidTemplateDataProcessorInterfaceToDataProcessorInterface.rst
new file mode 100644 (file)
index 0000000..cc367eb
--- /dev/null
@@ -0,0 +1,49 @@
+=========================================================================================
+Breaking: #67890 - Redesign FluidTemplateDataProcessorInterface to DataProcessorInterface
+=========================================================================================
+
+Description
+===========
+
+The ``FluidTemplateDataProcessorInterface`` introduced with #66907 has been refactored to ``DataProcessorInterface``.
+
+This decouples it from the Fluid StandaloneView and makes the ContentObjectRenderer available in the process method so the different DataProcessor classes do no have to initiate it on their own.
+Instead of manipulating the $data property of the ContentObjectRenderer a new key/value store can be filled/manipulated by the different dataProcessor classes.
+
+The new interface expects the following ``process()`` method:
+
+.. code-block:: php
+
+       /**
+        * Process content object data
+        *
+        * @param ContentObjectRenderer $cObj The data of the content element or page
+        * @param array $processorConfiguration The configuration of this processor
+        * @param array $contentObjectConfiguration The configuration of Content Object
+        * @param array $processedData Key/value store of processed data (e.g. to be passed to a Fluid View)
+        * @return array the processed data as key/value store
+        */
+       public function process(
+               ContentObjectRenderer $cObj,
+               array $contentObjectConfiguration,
+               array $processorConfiguration,
+               array $processedData
+       );
+
+
+Impact
+======
+
+This will break all frontend rendering for TYPO3 7.3 installations that use ``FLUIDTEMPLATE`` ``.dataProcessing``.
+
+
+Affected Installations
+======================
+
+All TYPO3 7.3 installations that already use the new ``FLUIDTEMPLATE`` ``.dataProcessing`` option.
+
+
+Migration
+=========
+
+Change the interface of all DataProcessor classes from ``FluidTemplateDataProcessorInterface`` to the new ``DataProcessorInterface`` and adjust the ``process()`` method to match the new parameters and make sure it returns the processed data as the processed data.
diff --git a/typo3/sysext/frontend/Classes/ContentObject/DataProcessorInterface.php b/typo3/sysext/frontend/Classes/ContentObject/DataProcessorInterface.php
new file mode 100644 (file)
index 0000000..ec87202
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+namespace TYPO3\CMS\Frontend\ContentObject;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Interface for data processor classes processing data from
+ * ContentObjectRenderer, used e.g. with the FLUIDTEMPLATE content object
+ */
+interface DataProcessorInterface {
+
+       /**
+        * Process content object data
+        *
+        * @param ContentObjectRenderer $cObj The data of the content element or page
+        * @param array $processorConfiguration The configuration of this processor
+        * @param array $contentObjectConfiguration The configuration of Content Object
+        * @param array $processedData Key/value store of processed data (e.g. to be passed to a Fluid View)
+        * @return array the processed data as key/value store
+        */
+       public function process(
+               ContentObjectRenderer $cObj,
+               array $contentObjectConfiguration,
+               array $processorConfiguration,
+               array $processedData
+       );
+}
index eb1409c..bc0a7c2 100644 (file)
@@ -71,9 +71,10 @@ class FluidTemplateContentObject extends AbstractContentObject {
                $this->setPartialRootPath($conf);
                $this->setExtbaseVariables($conf);
                $this->assignSettings($conf);
-               $this->assignContentObjectVariables($conf);
-               $this->processData($conf);
-               $this->assignContentObjectDataAndCurrent();
+               $variables = $this->getContentObjectVariables($conf);
+               $variables = $this->processData($conf, $variables);
+
+               $this->view->assignMultiple($variables);
 
                $content = $this->renderFluidView();
                $content = $this->applyStandardWrapToRenderedContent($content, $conf);
@@ -218,61 +219,61 @@ class FluidTemplateContentObject extends AbstractContentObject {
         * Check for the availability of processors, defined in TypoScript, and use them for data processing
         *
         * @param array $configuration Configuration array
-        * @return void
+        * @param array $variables the variables to be processed
+        * @return array the processed data and variables as key/value store
         * @throws \UnexpectedValueException
         */
-       protected function processData(array $configuration) {
+       protected function processData(array $configuration, array $variables) {
                if (
                        !empty($configuration['dataProcessing.'])
                        && is_array($configuration['dataProcessing.'])
                ) {
                        $processors = $configuration['dataProcessing.'];
+                       $processorKeys = \TYPO3\CMS\Core\TypoScript\TemplateService::sortedKeyList($processors);
 
-                       foreach ($processors as $key => $className) {
-                               if (strpos($key, '.') === FALSE && !empty($className)) {
-                                       $processor = GeneralUtility::makeInstance($className);
-
-                                       if (!$processor instanceof FluidTemplateDataProcessorInterface) {
-                                               throw new \UnexpectedValueException(
-                                                       '$processor with class name "' . $className . '" ' .
-                                                       'must implement interface "' . FluidTemplateDataProcessorInterface::class . '"',
-                                                       1427455377
-                                               );
-                                       }
-
-                                       $processorConfiguration = isset($processors[$key . '.']) ? $processors[$key . '.'] : array();
+                       foreach ($processorKeys as $key) {
+                               $className = $processors[$key];
+                               $processor = GeneralUtility::makeInstance($className);
 
-                                       $processor->process(
-                                               $this->cObj->data,
-                                               $processorConfiguration,
-                                               $configuration,
-                                               $this->view
+                               if (!$processor instanceof DataProcessorInterface) {
+                                       throw new \UnexpectedValueException(
+                                               '$processor with class name "' . $className . '" ' .
+                                               'must implement interface "' . DataProcessorInterface::class . '"',
+                                               1427455377
                                        );
                                }
+
+                               $processorConfiguration = isset($processors[$key . '.']) ? $processors[$key . '.'] : array();
+
+                               $variables = $processor->process(
+                                       $this->cObj,
+                                       $configuration,
+                                       $processorConfiguration,
+                                       $variables
+                               );
                        }
                }
+               return $variables;
        }
 
        /**
-        * Assign rendered content objects in variables array to view
+        * Compile rendered content objects in variables array ready to assign to the view
         *
         * @param array $conf Configuration array
-        * @return void
+        * @return array the variables to be assigned
         * @throws \InvalidArgumentException
         */
-       protected function assignContentObjectVariables(array $conf) {
+       protected function getContentObjectVariables(array $conf) {
+               $variables = array();
                $reservedVariables = array('data', 'current');
-               // Accumulate the variables to be replaced and loop them through cObjGetSingle
-               $variables = (array)$conf['variables.'];
-               foreach ($variables as $variableName => $cObjType) {
+               // Accumulate the variables to be process and loop them through cObjGetSingle
+               $variablesToProcess = (array)$conf['variables.'];
+               foreach ($variablesToProcess as $variableName => $cObjType) {
                        if (is_array($cObjType)) {
                                continue;
                        }
                        if (!in_array($variableName, $reservedVariables)) {
-                               $this->view->assign(
-                                       $variableName,
-                                       $this->cObj->cObjGetSingle($cObjType, $variables[$variableName . '.'])
-                               );
+                               $variables[$variableName] = $this->cObj->cObjGetSingle($cObjType, $variablesToProcess[$variableName . '.']);
                        } else {
                                throw new \InvalidArgumentException(
                                        'Cannot use reserved name "' . $variableName . '" as variable name in FLUIDTEMPLATE.',
@@ -280,6 +281,9 @@ class FluidTemplateContentObject extends AbstractContentObject {
                                );
                        }
                }
+               $variables['data'] = $this->cObj->data;
+               $variables['current'] = $this->cObj->data[$this->cObj->currentValKey];
+               return $variables;
        }
 
        /**
@@ -299,16 +303,6 @@ class FluidTemplateContentObject extends AbstractContentObject {
        }
 
        /**
-        * Assign content object renderer data and current to view
-        *
-        * @return void
-        */
-       protected function assignContentObjectDataAndCurrent() {
-               $this->view->assign('data', $this->cObj->data);
-               $this->view->assign('current', $this->cObj->data[$this->cObj->currentValKey]);
-       }
-
-       /**
         * Render fluid standalone view
         *
         * @return string
diff --git a/typo3/sysext/frontend/Classes/ContentObject/FluidTemplateDataProcessorInterface.php b/typo3/sysext/frontend/Classes/ContentObject/FluidTemplateDataProcessorInterface.php
deleted file mode 100644 (file)
index 738fa63..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-namespace TYPO3\CMS\Frontend\ContentObject;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Fluid\View\StandaloneView;
-
-/**
- * Interface for data processor classes with the FLUIDTEMPLATE content object
- */
-interface FluidTemplateDataProcessorInterface {
-
-       /**
-        * Process data passed to the FLUIDTEMPLATE content object
-        *
-        * @param array $data The data of the content element or page
-        * @param array $processorConfiguration The configuration of this processor
-        * @param array $configuration The configuration of FLUIDTEMPLATE
-        * @param \TYPO3\CMS\Fluid\View\StandaloneView $view The view
-        * @return void
-        */
-       public function process(
-               array &$data,
-               array $processorConfiguration,
-               array $configuration,
-               StandaloneView $view
-       );
-}
index 836277c..0f18a39 100644 (file)
@@ -615,9 +615,9 @@ class FluidTemplateContentObjectTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
                        ->method('cObjGetSingle')
                        ->will($this->returnValue('foo'));
                $this->standaloneView
-                       ->expects($this->at(1))
-                       ->method('assign')
-                       ->with('aVar', 'foo');
+                       ->expects($this->once())
+                       ->method('assignMultiple')
+                       ->with(array('aVar' => 'foo', 'data' => array(), 'current' => NULL));
                $this->subject->render($configuration);
        }
 
@@ -628,9 +628,9 @@ class FluidTemplateContentObjectTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
                $this->addMockViewToSubject();
                $this->contentObjectRenderer->data = array('foo');
                $this->standaloneView
-                       ->expects($this->at(1))
-                       ->method('assign')
-                       ->with('data', array('foo'));
+                       ->expects($this->once())
+                       ->method('assignMultiple')
+                       ->with(array('data' => array('foo'), 'current' => NULL));
                $this->subject->render(array());
        }
 
@@ -640,11 +640,11 @@ class FluidTemplateContentObjectTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
        public function renderAssignsContentObjectRendererCurrentValueToView() {
                $this->addMockViewToSubject();
                $this->contentObjectRenderer->data = array('currentKey' => 'currentValue');
-               $this->contentObjectRenderer->currentValKey= 'currentKey';
+               $this->contentObjectRenderer->currentValKey = 'currentKey';
                $this->standaloneView
-                       ->expects($this->at(2))
-                       ->method('assign')
-                       ->with('current', 'currentValue');
+                       ->expects($this->once())
+                       ->method('assignMultiple')
+                       ->with(array('data' => array('currentKey' => 'currentValue'), 'current' => 'currentValue'));
                $this->subject->render(array());
        }