[FEATURE] Enable IRRE fields in FlexForms
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / DataHandling / DataHandler.php
index 26f6d18..48279d7 100644 (file)
@@ -1378,10 +1378,11 @@ class DataHandler {
         * @param string $field Field name. Must NOT be set if the call is for a flexform field (since flexforms are not allowed within flexforms).
         * @param [type] $uploadedFiles
         * @param [type] $tscPID
         * @param string $field Field name. Must NOT be set if the call is for a flexform field (since flexforms are not allowed within flexforms).
         * @param [type] $uploadedFiles
         * @param [type] $tscPID
+        * @param array $additionalData Additional data to be forwarded to sub-processors
         * @return array Returns the evaluated $value as key "value" in this array.
         * @todo Define visibility
         */
         * @return array Returns the evaluated $value as key "value" in this array.
         * @todo Define visibility
         */
-       public function checkValue_SW($res, $value, $tcaFieldConf, $table, $id, $curValue, $status, $realPid, $recFID, $field, $uploadedFiles, $tscPID) {
+       public function checkValue_SW($res, $value, $tcaFieldConf, $table, $id, $curValue, $status, $realPid, $recFID, $field, $uploadedFiles, $tscPID, array $additionalData = NULL) {
                $PP = array($table, $id, $curValue, $status, $realPid, $recFID, $tscPID);
                switch ($tcaFieldConf['type']) {
                case 'text':
                $PP = array($table, $id, $curValue, $status, $realPid, $recFID, $tscPID);
                switch ($tcaFieldConf['type']) {
                case 'text':
@@ -1407,7 +1408,7 @@ class DataHandler {
                        $res = $this->checkValue_group_select($res, $value, $tcaFieldConf, $PP, $uploadedFiles, $field);
                        break;
                case 'inline':
                        $res = $this->checkValue_group_select($res, $value, $tcaFieldConf, $PP, $uploadedFiles, $field);
                        break;
                case 'inline':
-                       $res = $this->checkValue_inline($res, $value, $tcaFieldConf, $PP, $field);
+                       $res = $this->checkValue_inline($res, $value, $tcaFieldConf, $PP, $field, $additionalData);
                        break;
                case 'flex':
                        // FlexForms are only allowed for real fields.
                        break;
                case 'flex':
                        // FlexForms are only allowed for real fields.
@@ -1961,6 +1962,7 @@ class DataHandler {
         */
        public function checkValue_flex($res, $value, $tcaFieldConf, $PP, $uploadedFiles, $field) {
                list($table, $id, $curValue, $status, $realPid, $recFID) = $PP;
         */
        public function checkValue_flex($res, $value, $tcaFieldConf, $PP, $uploadedFiles, $field) {
                list($table, $id, $curValue, $status, $realPid, $recFID) = $PP;
+
                if (is_array($value)) {
                        // This value is necessary for flex form processing to happen on flexform fields in page records when they are copied.
                        // The problem is, that when copying a page, flexfrom XML comes along in the array for the new record - but since $this->checkValue_currentRecord does not have a uid or pid for that sake, the t3lib_BEfunc::getFlexFormDS() function returns no good DS. For new records we do know the expected PID so therefore we send that with this special parameter. Only active when larger than zero.
                if (is_array($value)) {
                        // This value is necessary for flex form processing to happen on flexform fields in page records when they are copied.
                        // The problem is, that when copying a page, flexfrom XML comes along in the array for the new record - but since $this->checkValue_currentRecord does not have a uid or pid for that sake, the t3lib_BEfunc::getFlexFormDS() function returns no good DS. For new records we do know the expected PID so therefore we send that with this special parameter. Only active when larger than zero.
@@ -2005,6 +2007,7 @@ class DataHandler {
                        // Passthrough...:
                        $res['value'] = $value;
                }
                        // Passthrough...:
                        $res['value'] = $value;
                }
+
                return $res;
        }
 
                return $res;
        }
 
@@ -2066,10 +2069,11 @@ class DataHandler {
         * @param array $tcaFieldConf Field configuration from TCA
         * @param array $PP Additional parameters in a numeric array: $table,$id,$curValue,$status,$realPid,$recFID
         * @param string $field Field name
         * @param array $tcaFieldConf Field configuration from TCA
         * @param array $PP Additional parameters in a numeric array: $table,$id,$curValue,$status,$realPid,$recFID
         * @param string $field Field name
+        * @param array $additionalData Additional data to be forwarded to sub-processors
         * @return array Modified $res array
         * @todo Define visibility
         */
         * @return array Modified $res array
         * @todo Define visibility
         */
-       public function checkValue_inline($res, $value, $tcaFieldConf, $PP, $field) {
+       public function checkValue_inline($res, $value, $tcaFieldConf, $PP, $field, array $additionalData = NULL) {
                list($table, $id, $curValue, $status, $realPid, $recFID) = $PP;
                if (!$tcaFieldConf['foreign_table']) {
                        // Fatal error, inline fields should always have a foreign_table defined
                list($table, $id, $curValue, $status, $realPid, $recFID) = $PP;
                if (!$tcaFieldConf['foreign_table']) {
                        // Fatal error, inline fields should always have a foreign_table defined
@@ -2087,13 +2091,14 @@ class DataHandler {
                        $this->addNewValuesToRemapStackChildIds($valueArray);
                        $this->remapStack[] = array(
                                'func' => 'checkValue_inline_processDBdata',
                        $this->addNewValuesToRemapStackChildIds($valueArray);
                        $this->remapStack[] = array(
                                'func' => 'checkValue_inline_processDBdata',
-                               'args' => array($valueArray, $tcaFieldConf, $id, $status, $table, $field),
+                               'args' => array($valueArray, $tcaFieldConf, $id, $status, $table, $field, $additionalData),
                                'pos' => array('valueArray' => 0, 'tcaFieldConf' => 1, 'id' => 2, 'table' => 4),
                                'pos' => array('valueArray' => 0, 'tcaFieldConf' => 1, 'id' => 2, 'table' => 4),
-                               'field' => $field
+                               'additionalData' => $additionalData,
+                               'field' => $field,
                        );
                        unset($res['value']);
                } elseif ($value || \TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($id)) {
                        );
                        unset($res['value']);
                } elseif ($value || \TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($id)) {
-                       $res['value'] = $this->checkValue_inline_processDBdata($valueArray, $tcaFieldConf, $id, $status, $table, $field);
+                       $res['value'] = $this->checkValue_inline_processDBdata($valueArray, $tcaFieldConf, $id, $status, $table, $field, $additionalData);
                }
                return $res;
        }
                }
                return $res;
        }
@@ -2491,7 +2496,13 @@ class DataHandler {
                                                        } else {
                                                                // Default
                                                                list($CVtable, $CVid, $CVcurValue, $CVstatus, $CVrealPid, $CVrecFID, $CVtscPID) = $pParams;
                                                        } else {
                                                                // Default
                                                                list($CVtable, $CVid, $CVcurValue, $CVstatus, $CVrealPid, $CVrecFID, $CVtscPID) = $pParams;
-                                                               $res = $this->checkValue_SW(array(), $dataValues[$key][$vKey], $dsConf['TCEforms']['config'], $CVtable, $CVid, $dataValues_current[$key][$vKey], $CVstatus, $CVrealPid, $CVrecFID, '', $uploadedFiles[$key][$vKey], array(), $CVtscPID);
+
+                                                               $additionalData = array(
+                                                                       'flexFormId' => $CVrecFID,
+                                                                       'flexFormPath' => trim(rtrim($structurePath, '/') . '/' . $key . '/' . $vKey, '/'),
+                                                               );
+
+                                                               $res = $this->checkValue_SW(array(), $dataValues[$key][$vKey], $dsConf['TCEforms']['config'], $CVtable, $CVid, $dataValues_current[$key][$vKey], $CVstatus, $CVrealPid, $CVrecFID, '', $uploadedFiles[$key][$vKey], $CVtscPID, $additionalData);
                                                                // Look for RTE transformation of field:
                                                                if ($dataValues[$key]['_TRANSFORM_' . $vKey] == 'RTE' && !$this->dontProcessTransformations) {
                                                                        // Unsetting trigger field - we absolutely don't want that into the data storage!
                                                                // Look for RTE transformation of field:
                                                                if ($dataValues[$key]['_TRANSFORM_' . $vKey] == 'RTE' && !$this->dontProcessTransformations) {
                                                                        // Unsetting trigger field - we absolutely don't want that into the data storage!
@@ -2551,9 +2562,10 @@ class DataHandler {
         * @param string $status Status string ('update' or 'new')
         * @param string $table Table name, needs to be passed to t3lib_loadDBGroup
         * @param string $field The current field the values are modified for
         * @param string $status Status string ('update' or 'new')
         * @param string $table Table name, needs to be passed to t3lib_loadDBGroup
         * @param string $field The current field the values are modified for
+        * @param array $additionalData Additional data to be forwarded to sub-processors
         * @return string Modified values
         */
         * @return string Modified values
         */
-       protected function checkValue_inline_processDBdata($valueArray, $tcaFieldConf, $id, $status, $table, $field) {
+       protected function checkValue_inline_processDBdata($valueArray, $tcaFieldConf, $id, $status, $table, $field, array $additionalData = NULL) {
                $newValue = '';
                $foreignTable = $tcaFieldConf['foreign_table'];
                $valueArray = $this->applyFiltersToValues($tcaFieldConf, $valueArray);
                $newValue = '';
                $foreignTable = $tcaFieldConf['foreign_table'];
                $valueArray = $this->applyFiltersToValues($tcaFieldConf, $valueArray);
@@ -4784,6 +4796,8 @@ class DataHandler {
        public function processRemapStack() {
                // Processes the remap stack:
                if (is_array($this->remapStack)) {
        public function processRemapStack() {
                // Processes the remap stack:
                if (is_array($this->remapStack)) {
+                       $remapFlexForms = array();
+
                        foreach ($this->remapStack as $remapAction) {
                                // If no position index for the arguments was set, skip this remap action:
                                if (!is_array($remapAction['pos'])) {
                        foreach ($this->remapStack as $remapAction) {
                                // If no position index for the arguments was set, skip this remap action:
                                if (!is_array($remapAction['pos'])) {
@@ -4796,6 +4810,7 @@ class DataHandler {
                                $table = $remapAction['args'][$remapAction['pos']['table']];
                                $valueArray = $remapAction['args'][$remapAction['pos']['valueArray']];
                                $tcaFieldConf = $remapAction['args'][$remapAction['pos']['tcaFieldConf']];
                                $table = $remapAction['args'][$remapAction['pos']['table']];
                                $valueArray = $remapAction['args'][$remapAction['pos']['valueArray']];
                                $tcaFieldConf = $remapAction['args'][$remapAction['pos']['tcaFieldConf']];
+                               $additionalData = $remapAction['additionalData'];
                                // The record is new and has one or more new ids (in case of versioning/workspaces):
                                if (strpos($id, 'NEW') !== FALSE) {
                                        // Replace NEW...-ID with real uid:
                                // The record is new and has one or more new ids (in case of versioning/workspaces):
                                if (strpos($id, 'NEW') !== FALSE) {
                                        // Replace NEW...-ID with real uid:
@@ -4830,7 +4845,19 @@ class DataHandler {
                                        $newValue = implode(',', $this->checkValue_checkMax($tcaFieldConf, $newValue));
                                }
                                // Update in database (list of children (csv) or number of relations (foreign_field)):
                                        $newValue = implode(',', $this->checkValue_checkMax($tcaFieldConf, $newValue));
                                }
                                // Update in database (list of children (csv) or number of relations (foreign_field)):
-                               $this->updateDB($table, $id, array($field => $newValue));
+                               if (!empty($field)) {
+                                       $this->updateDB($table, $id, array($field => $newValue));
+                               // Collect data to update FlexForms
+                               } elseif (!empty($additionalData['flexFormId']) && !empty($additionalData['flexFormPath'])) {
+                                       $flexFormId = $additionalData['flexFormId'];
+                                       $flexFormPath = $additionalData['flexFormPath'];
+
+                                       if (!isset($remapFlexForms[$flexFormId])) {
+                                               $remapFlexForms[$flexFormId] = array();
+                                       }
+
+                                       $remapFlexForms[$flexFormId][$flexFormPath] = $newValue;
+                               }
                                // Process waiting Hook: processDatamap_afterDatabaseOperations:
                                if (isset($this->remapStackRecords[$table][$rawId]['processDatamap_afterDatabaseOperations'])) {
                                        $hookArgs = $this->remapStackRecords[$table][$rawId]['processDatamap_afterDatabaseOperations'];
                                // Process waiting Hook: processDatamap_afterDatabaseOperations:
                                if (isset($this->remapStackRecords[$table][$rawId]['processDatamap_afterDatabaseOperations'])) {
                                        $hookArgs = $this->remapStackRecords[$table][$rawId]['processDatamap_afterDatabaseOperations'];
@@ -4845,6 +4872,12 @@ class DataHandler {
                                        }
                                }
                        }
                                        }
                                }
                        }
+
+                       if ($remapFlexForms) {
+                               foreach ($remapFlexForms as $flexFormId => $modifications) {
+                                       $this->updateFlexFormData($flexFormId, $modifications);
+                               }
+                       }
                }
                // Processes the remap stack actions:
                if ($this->remapStackActions) {
                }
                // Processes the remap stack actions:
                if ($this->remapStackActions) {
@@ -4868,6 +4901,43 @@ class DataHandler {
                $this->remapStackRefIndex = array();
        }
 
                $this->remapStackRefIndex = array();
        }
 
+       /**
+        * Updates FlexForm data.
+        *
+        * @param string $flexFormId, e.g. <table>:<uid>:<field>
+        * @param array $modifications Modifications with paths and values (e.g. 'sDEF/lDEV/field/vDEF' => 'TYPO3')
+        * @return void
+        */
+       protected function updateFlexFormData($flexFormId, array $modifications) {
+               list ($table, $uid, $field) = explode(':', $flexFormId, 3);
+               $record = $this->recordInfo($table, $uid, '*');
+
+               if (!$table || !$uid || !$field || !is_array($record)) {
+                       return;
+               }
+
+               \TYPO3\CMS\Backend\Utility\BackendUtility::workspaceOL($table, $record);
+
+               // Get current data structure and value array:
+               $valueStructure = \TYPO3\CMS\Core\Utility\GeneralUtility::xml2array($record[$field]);
+
+               // Do recursive processing of the XML data:
+               foreach ($modifications as $path => $value) {
+                       $valueStructure['data'] = \TYPO3\CMS\Core\Utility\ArrayUtility::setValueByPath(
+                               $valueStructure['data'], $path, $value
+                       );
+               }
+
+               if (is_array($valueStructure['data'])) {
+                       // The return value should be compiled back into XML
+                       $values = array(
+                               $field => $this->checkValue_flexArray2Xml($valueStructure, TRUE),
+                       );
+
+                       $this->updateDB($table, $uid, $values);
+               }
+       }
+
        /**
         * Triggers a remap action for a specific record.
         *
        /**
         * Triggers a remap action for a specific record.
         *