[FEATURE] Add Data Processor for fetching DB records 52/40952/19
authorBenjamin Mack <benni@typo3.org>
Tue, 7 Jul 2015 12:55:33 +0000 (14:55 +0200)
committerHelmut Hummel <helmut.hummel@typo3.org>
Sun, 26 Jul 2015 14:02:08 +0000 (16:02 +0200)
Releases: master
Resolves: #68094
Change-Id: I275f2b875ce78d3611975a1ffeec05395dd8b4db
Reviewed-on: http://review.typo3.org/40952
Reviewed-by: Sascha Egerer <sascha@sascha-egerer.de>
Tested-by: Sascha Egerer <sascha@sascha-egerer.de>
Reviewed-by: Frans Saris <franssaris@gmail.com>
Tested-by: Frans Saris <franssaris@gmail.com>
Reviewed-by: Helmut Hummel <helmut.hummel@typo3.org>
Tested-by: Helmut Hummel <helmut.hummel@typo3.org>
typo3/sysext/core/Documentation/Changelog/master/Feature-68094-DatabaseQueryDataProcessor.rst [new file with mode: 0644]
typo3/sysext/frontend/Classes/ContentObject/ContentContentObject.php
typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php
typo3/sysext/frontend/Classes/DataProcessing/DatabaseQueryProcessor.php [new file with mode: 0644]

diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-68094-DatabaseQueryDataProcessor.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-68094-DatabaseQueryDataProcessor.rst
new file mode 100644 (file)
index 0000000..5de464b
--- /dev/null
@@ -0,0 +1,61 @@
+==============================================
+Feature: #68094 - Database Query DataProcessor
+==============================================
+
+Description
+===========
+
+A new Database Query DataProcessor has been introduced, which can be used to fetch data from the Database
+to be handled by a ContentObject implementing the processors, e.g. the FLUIDTEMPLATE ContentObject.
+
+The Database Query Processor works like the code from the Content Object CONTENT, except for just handing
+over the result as array. A FLUIDTEMPLATE can then simply iterate over processed data automatically.
+
+.. code-block:: typoscript
+
+       tt_content.mycontent.20 = FLUIDTEMPLATE
+       tt_content.mycontent.20 {
+               file = EXT:myextension/Resources/Private/Templates/ContentObjects/MyContent.html
+
+               dataProcessing.10 = TYPO3\CMS\Frontend\DataProcessing\DatabaseQueryProcessor
+               dataProcessing.10 {
+                       # regular if syntax
+                       if.isTrue.field = records
+
+                       # the table name from which the data is fetched from
+                       # + stdWrap
+                       table = tt_address
+
+                       # All properties from .select can be used directly
+                       # + stdWrap
+                       colPos = 1
+                       pidInList = 13,14
+
+                       # The target variable to be handed to the ContentObject again, can be used
+                       # in Fluid e.g. to iterate over the objects. defaults to "records" when not defined
+                       # + stdWrap
+                       as = myrecords
+
+                       # The fetched records can also be processed by DataProcessors.
+                       # All configured processors are applied to every row of the result.
+                       dataProcessing {
+                               10 = TYPO3\CMS\Frontend\DataProcessing\FilesProcessor
+                               10 {
+                                       references.fieldName = image
+                               }
+                       }
+               }
+       }
+
+In the Fluid template then iterate over the files:
+
+.. code-block:: html
+
+       <ul>
+       <f:for each="{myrecords}" as="record">
+               <li>
+                       <f:image image="{record.files.0}" />
+                       <a href="{record.data.www}">{record.data.first_name} {record.data.last_name}</a>
+               </li>
+       </f:for>
+       </ul>
index 024e754..44168a0 100644 (file)
@@ -68,7 +68,7 @@ class ContentContentObject extends AbstractContentObject {
                $cobjValue = '';
 
                do {
-                       $records = $this->cObj->getRecords($conf);
+                       $records = $this->cObj->getRecords($conf['table'], $conf['select.']);
                        if (!empty($records)) {
                                $this->cObj->currentRecordTotal = count($records);
                                $this->getTimeTracker()->setTSlogMessage('NUMROWS: ' .  count($records));
index 3eefefa..fb1cb59 100755 (executable)
@@ -7838,13 +7838,14 @@ class ContentObjectRenderer {
         * Executes a SELECT query for records from $table and with conditions based on the configuration in the $conf array
         * and overlays with translation and version if available
         *
-        * @param array $configuration The TypoScript configuration properties
+        * @param string $tableName the name of the TCA database table
+        * @param array $queryConfiguration The TypoScript configuration properties, see .select in TypoScript reference
         * @return array The records
         */
-       public function getRecords(array $configuration) {
+       public function getRecords($tableName, array $queryConfiguration) {
                $records = [];
 
-               $res = $this->exec_getQuery($configuration['table'], $configuration['select.']);
+               $res = $this->exec_getQuery($tableName, $queryConfiguration);
 
                if ($error = $GLOBALS['TYPO3_DB']->sql_error()) {
                        $GLOBALS['TT']->setTSlogMessage($error, 3);
@@ -7853,15 +7854,15 @@ class ContentObjectRenderer {
                        while (($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) !== FALSE) {
 
                                // Versioning preview:
-                               $GLOBALS['TSFE']->sys_page->versionOL($configuration['table'], $row, TRUE);
+                               $GLOBALS['TSFE']->sys_page->versionOL($tableName, $row, TRUE);
 
                                // Language overlay:
                                if (is_array($row) && $GLOBALS['TSFE']->sys_language_contentOL) {
-                                       if ($configuration['table'] === 'pages') {
+                                       if ($tableName === 'pages') {
                                                $row = $GLOBALS['TSFE']->sys_page->getPageOverlay($row);
                                        } else {
                                                $row = $GLOBALS['TSFE']->sys_page->getRecordOverlay(
-                                                       $configuration['table'],
+                                                       $tableName,
                                                        $row,
                                                        $GLOBALS['TSFE']->sys_language_content,
                                                        $GLOBALS['TSFE']->sys_language_contentOL
diff --git a/typo3/sysext/frontend/Classes/DataProcessing/DatabaseQueryProcessor.php b/typo3/sysext/frontend/Classes/DataProcessing/DatabaseQueryProcessor.php
new file mode 100644 (file)
index 0000000..7f48b33
--- /dev/null
@@ -0,0 +1,94 @@
+<?php
+namespace TYPO3\CMS\Frontend\DataProcessing;
+
+/*
+ * 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\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
+use TYPO3\CMS\Frontend\ContentObject\DataProcessorInterface;
+use TYPO3\CMS\Frontend\ContentObject\DataProcessingTrait;
+
+/**
+ * Fetch records from the database, using the default .select syntax from TypoScript.
+ *
+ * This way, e.g. a FLUIDTEMPLATE cObject can iterate over the array of records.
+ *
+ * Example TypoScript configuration:
+ *
+ * 10 = TYPO3\CMS\Frontend\DataProcessing\DatabaseQueryProcessor
+ * 10 {
+ *   table = tt_address
+ *   pidInList = 123
+ *   where = company="Acme" AND first_name="Ralph"
+ *   order = RAND()
+ *   as = addresses
+ *   dataProcessing {
+ *     10 = TYPO3\CMS\Frontend\DataProcessing\FilesProcessor
+ *     10 {
+ *       references.fieldName = image
+ *     }
+ *   }
+ * }
+ *
+ * where "as" means the variable to be containing the result-set from the DB query.
+ */
+class DatabaseQueryProcessor implements DataProcessorInterface {
+       use DataProcessingTrait;
+
+       /**
+        * Fetches records from the database as an array
+        *
+        * @param ContentObjectRenderer $cObj The data of the content element or page
+        * @param array $contentObjectConfiguration The configuration of Content Object
+        * @param array $processorConfiguration The configuration of this processor
+        * @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) {
+               if (isset($processorConfiguration['if.']) && !$cObj->checkIf($processorConfiguration['if.'])) {
+                       return $processedData;
+               }
+
+               // the table to query, if none given, exit
+               $tableName = $cObj->stdWrapValue('table', $processorConfiguration);
+               if (empty($tableName)) {
+                       return $processedData;
+               }
+               if (isset($processorConfiguration['table.'])) {
+                       unset($processorConfiguration['table.']);
+               }
+               if (isset($processorConfiguration['table'])) {
+                       unset($processorConfiguration['table']);
+               }
+
+               // The variable to be used within the result
+               $targetVariableName = $cObj->stdWrapValue('as', $processorConfiguration, 'records');
+
+               // Execute a SQL statement to fetch the records
+               $records = $cObj->getRecords($tableName, $processorConfiguration);
+               $processedRecordVariables = array();
+               foreach ($records as $key => $record) {
+                       /** @var ContentObjectRenderer $recordContentObjectRenderer */
+                       $recordContentObjectRenderer = GeneralUtility::makeInstance(ContentObjectRenderer::class);
+                       $recordContentObjectRenderer->start($record, $tableName);
+                       $processedRecordVariables[$key] = array('data' => $record);
+                       $processedRecordVariables[$key] = $this->processData($recordContentObjectRenderer, $processorConfiguration, $processedRecordVariables[$key]);
+               }
+
+               $processedData[$targetVariableName] = $processedRecordVariables;
+
+               return $processedData;
+       }
+}