[TASK] FormEngine: Replace placeholder resolving with a data provider 48/43748/6
authorMorton Jonuschat <m.jonuschat@mojocode.de>
Fri, 2 Oct 2015 18:50:55 +0000 (20:50 +0200)
committerChristian Kuhn <lolli@schwarzbu.ch>
Mon, 5 Oct 2015 13:57:51 +0000 (15:57 +0200)
Resolving of placeholder for field types text and input has been moved
from the element rendering into the form data providers. The data
provider approach allows reuse of existing providers and data groups and
reduces the amount of database queries by having access to previously
parsed data.

Resolves: #70370
Resolves: #70146
Resolves: #70297
Releases: master
Change-Id: I05fa2c6d3237e65627cae74811d1a9202e3ac0c8
Reviewed-on: http://review.typo3.org/43748
Reviewed-by: Frank Nägler <frank.naegler@typo3.org>
Tested-by: Frank Nägler <frank.naegler@typo3.org>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
typo3/sysext/backend/Classes/Form/AbstractNode.php
typo3/sysext/backend/Classes/Form/Container/SingleFieldContainer.php
typo3/sysext/backend/Classes/Form/Element/InputTextElement.php
typo3/sysext/backend/Classes/Form/Element/TextElement.php
typo3/sysext/backend/Classes/Form/FormDataGroup/TcaInputPlaceholderRecord.php [new file with mode: 0644]
typo3/sysext/backend/Classes/Form/FormDataProvider/TcaInputPlaceholders.php [new file with mode: 0644]
typo3/sysext/backend/Classes/Form/FormDataTraverser.php [deleted file]
typo3/sysext/backend/Tests/Unit/Form/FormDataGroup/TcaInputPlaceholderRecordTest.php [new file with mode: 0644]
typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/TcaInputPlaceholdersTest.php [new file with mode: 0644]
typo3/sysext/core/Configuration/DefaultConfiguration.php
typo3/sysext/rsaauth/Classes/Form/Element/RsaInputElement.php

index 00a94fa..2ae17d2 100644 (file)
@@ -114,32 +114,6 @@ abstract class AbstractNode implements NodeInterface {
        }
 
        /**
-        * Determine and get the value for the placeholder for an input field.
-        * Typically used in an inline relation where values from fields down the record chain
-        * are used as "default" values for fields.
-        *
-        * @param string $table
-        * @param array $config
-        * @param array $row
-        * @return mixed
-        */
-       protected function getPlaceholderValue($table, array $config, array $row) {
-               $value = trim($config['placeholder']);
-               if (!$value) {
-                       return '';
-               }
-               // Check if we have a reference to another field value from the current record
-               if (substr($value, 0, 6) === '__row|') {
-                       /** @var FormDataTraverser $traverser */
-                       $traverseFields = GeneralUtility::trimExplode('|', substr($value, 6));
-                       $traverser = GeneralUtility::makeInstance(FormDataTraverser::class);
-                       $value = $traverser->getTraversedFieldValue($traverseFields, $table, $row, $this->data['inlineFirstPid']);
-               }
-
-               return $value;
-       }
-
-       /**
         * Build JSON string for validations rules and return it
         * as data attribute for HTML elements.
         *
index ce0ad1b..74ec46c 100644 (file)
@@ -243,7 +243,7 @@ class SingleFieldContainer extends AbstractContainer {
                        // field has no name attribute and is not transferred at all. Those two are then hidden / shown depending
                        // on the state of the above checkbox in via JS.
 
-                       $placeholder = $this->getPlaceholderValue($table, $parameterArray['fieldConf']['config'], $row);
+                       $placeholder = empty($parameterArray['fieldConf']['config']['placeholder']) ? '' : $parameterArray['fieldConf']['config']['placeholder'];
                        $onChange = 'typo3form.fieldTogglePlaceholder(' . GeneralUtility::quoteJSvalue($parameterArray['itemFormElName']) . ', !this.checked)';
                        $checked = $parameterArray['itemFormElValue'] === NULL ? '' : ' checked="checked"';
 
index 75f20db..efcc62f 100644 (file)
@@ -180,9 +180,8 @@ class InputTextElement extends AbstractFormElement {
                }
 
                // This is the EDITABLE form field.
-               $placeholderValue = $this->getPlaceholderValue($table, $config, $row);
-               if (!empty($placeholderValue)) {
-                       $attributes['placeholder'] = trim($languageService->sL($placeholderValue));
+               if (!empty($config['placeholder'])) {
+                       $attributes['placeholder'] = trim($config['placeholder']);
                }
 
                // Build the attribute string
index 7ace129..095e148 100644 (file)
@@ -160,10 +160,9 @@ class TextElement extends AbstractFormElement {
                        }
 
                        // Build the textarea
-                       $placeholderValue = $this->getPlaceholderValue($table, $config, $row);
                        $placeholderAttribute = '';
-                       if (!empty($placeholderValue)) {
-                               $placeholderAttribute = ' placeholder="' . htmlspecialchars(trim($languageService->sL($placeholderValue))) . '" ';
+                       if (!empty($config['placeholder'])) {
+                               $placeholderAttribute = ' placeholder="' . htmlspecialchars(trim($config['placeholder'])) . '" ';
                        }
 
                        $html .= '<textarea'
diff --git a/typo3/sysext/backend/Classes/Form/FormDataGroup/TcaInputPlaceholderRecord.php b/typo3/sysext/backend/Classes/Form/FormDataGroup/TcaInputPlaceholderRecord.php
new file mode 100644 (file)
index 0000000..88cb0be
--- /dev/null
@@ -0,0 +1,56 @@
+<?php
+namespace TYPO3\CMS\Backend\Form\FormDataGroup;
+
+/*
+ * 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\Backend\Form\FormDataGroupInterface;
+use TYPO3\CMS\Backend\Form\FormDataProviderInterface;
+use TYPO3\CMS\Core\Service\DependencyOrderingService;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+/**
+ * A data provider group for database records used for input placeholder values
+ */
+class TcaInputPlaceholderRecord implements FormDataGroupInterface {
+
+       /**
+        * Compile form data
+        *
+        * @param array $result Initialized result array
+        * @return array Result filled with data
+        * @throws \UnexpectedValueException
+        */
+       public function compile(array $result) {
+               $dataProvider = $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['formDataGroup']['tcaInputPlaceholderRecord'];
+               $orderingService = GeneralUtility::makeInstance(DependencyOrderingService::class);
+               $orderedDataProvider = $orderingService->orderByDependencies($dataProvider, 'before', 'depends');
+
+               foreach ($orderedDataProvider as $providerClassName => $_) {
+                       /** @var FormDataProviderInterface $provider */
+                       $provider = GeneralUtility::makeInstance($providerClassName);
+
+                       if (!$provider instanceof FormDataProviderInterface) {
+                               throw new \UnexpectedValueException(
+                                       'Data provider ' . $providerClassName . ' must implement FormDataProviderInterface',
+                                       1443986127
+                               );
+                       }
+
+                       $result = $provider->addData($result);
+               }
+
+               return $result;
+       }
+
+}
diff --git a/typo3/sysext/backend/Classes/Form/FormDataProvider/TcaInputPlaceholders.php b/typo3/sysext/backend/Classes/Form/FormDataProvider/TcaInputPlaceholders.php
new file mode 100644 (file)
index 0000000..070c20d
--- /dev/null
@@ -0,0 +1,197 @@
+<?php
+namespace TYPO3\CMS\Backend\Form\FormDataProvider;
+
+/*
+ * 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\Backend\Form\FormDataCompiler;
+use TYPO3\CMS\Backend\Form\FormDataGroup\TcaInputPlaceholderRecord;
+use TYPO3\CMS\Backend\Form\FormDataProviderInterface;
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\StringUtility;
+
+/**
+ * Resolve placeholders for fields of type input or text. The placeholder value
+ * in the processedTca section of the result will be replaced with the resolved
+ * value.
+ */
+class TcaInputPlaceholders extends AbstractItemProvider implements FormDataProviderInterface {
+
+       /**
+        * Resolve placeholders for input/text fields. Placeholders that are simple
+        * strings will be returned unmodified. Placeholders beginning with __row are
+        * being resolved, possibly traversing multiple tables.
+        *
+        * @param array $result
+        * @return array
+        */
+       public function addData(array $result) {
+               foreach ($result['processedTca']['columns'] as $fieldName => $fieldConfig) {
+                       // Placeholders are only valid for input and text type fields
+                       if (
+                               ($fieldConfig['config']['type'] !== 'input' && $fieldConfig['config']['type'] !== 'text')
+                               || !isset($fieldConfig['config']['placeholder'])
+                       ) {
+                               continue;
+                       }
+
+                       // Resolve __row|field type placeholders
+                       if (StringUtility::beginsWith($fieldConfig['config']['placeholder'], '__row|')) {
+                               // split field names into array and remove the __row indicator
+                               $fieldNameArray = array_slice(
+                                       GeneralUtility::trimExplode('|', $fieldConfig['config']['placeholder'], TRUE),
+                                       1
+                               );
+                               $result['processedTca']['columns'][$fieldName]['config']['placeholder'] = $this->getPlaceholderValue($fieldNameArray, $result);
+                       }
+
+                       // Remove empty placeholders
+                       if (empty($fieldConfig['config']['placeholder'])) {
+                               unset($result['processedTca']['columns'][$fieldName]['config']['placeholder']);
+                       }
+               }
+
+               return $result;
+       }
+
+       /**
+        * Recursively resolve the placeholder value. A placeholder string with a
+        * syntax of __row|field1|field2|field3 will be recursively resolved to a
+        * final value.
+        *
+        * @param array $fieldNameArray
+        * @param array $result
+        * @param int $recursionLevel
+        * @return string
+        */
+       protected function getPlaceholderValue($fieldNameArray, $result, $recursionLevel = 0) {
+               if ($recursionLevel > 99) {
+                       // This should not happen, treat as misconfiguration
+                       return '';
+               }
+
+               $fieldName = array_shift($fieldNameArray);
+               $fieldConfig = $result['processedTca']['columns'][$fieldName]['config'];
+
+               // Skip if a defined field was actually not present in the database row
+               // Using array_key_exists here, since NULL values are valid as well.
+               if (!array_key_exists($fieldName, $result['databaseRow'])) {
+                       return '';
+               }
+
+               $value = $result['databaseRow'][$fieldName];
+
+               switch($fieldConfig['type']) {
+                       case 'select':
+                               // The FormDataProviders already resolved the select items to an array of uids
+                               $possibleUids = $value;
+                               $foreignTableName = $fieldConfig['foreign_table'];
+                               break;
+                       case 'group':
+                               $possibleUids = $this->getRelatedGroupFieldUids($fieldConfig, $value);
+                               $foreignTableName = $this->getAllowedTableForGroupField($fieldConfig);
+                               break;
+                       case 'inline':
+                               $possibleUids = array_filter(GeneralUtility::trimExplode(',', $value, TRUE));
+                               $foreignTableName = $fieldConfig['foreign_table'];
+                               break;
+                       default:
+                               $possibleUids = [];
+                               $foreignTableName = '';
+               }
+
+               if (!empty($possibleUids) && !empty($fieldNameArray)) {
+                       $relatedFormData = $this->getRelatedFormData($foreignTableName, $possibleUids[0]);
+                       $value = $this->getPlaceholderValue($fieldNameArray, $relatedFormData, $recursionLevel + 1);
+               }
+
+               // @todo: This might not be the best solution. The database row
+               // @todo: can include array type values. Final resolution would
+               // @todo: need to take the recursion into account.
+               return (string)$value;
+       }
+
+       /**
+        * Compile a formdata result set based on the tablename and record uid.
+        *
+        * @param string $tableName Name of the table for which to compile formdata
+        * @param int $uid UID of the record for which to compile the formdata
+        * @return array The compiled formdata
+        */
+       protected function getRelatedFormData($tableName, $uid) {
+               $fakeDataInput = [
+                       'command' => 'edit',
+                       'vanillaUid' => (int)$uid,
+                       'tableName' => $tableName,
+               ];
+               /** @var TcaInputPlaceholderRecord $formDataGroup */
+               $formDataGroup = GeneralUtility::makeInstance(TcaInputPlaceholderRecord::class);
+               /** @var FormDataCompiler $formDataCompiler */
+               $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup);
+               $compilerResult = $formDataCompiler->compile($fakeDataInput);
+               return $compilerResult;
+       }
+
+       /**
+        * Return uids of related records for group type fields. Uids consisting of
+        * multiple parts like [table]_[uid]|[title] will be reduced to integers and
+        * validated against the allowed table. Uids without a table prefix are
+        * accepted in any case.
+        *
+        * @param array $fieldConfig TCA "config" section for the group type field.
+        * @param string $value A comma separated list of records
+        * @return array
+        */
+       protected function getRelatedGroupFieldUids(array $fieldConfig, $value) {
+               $relatedUids = [];
+               $allowedTable = $this->getAllowedTableForGroupField($fieldConfig);
+
+               // Skip if it's not a database relation with a resolvable foreign table
+               if (($fieldConfig['internal_type'] !== 'db') || ($allowedTable === FALSE)) {
+                       return $relatedUids;
+               }
+
+               $values = GeneralUtility::trimExplode(',', $value, TRUE);
+               foreach ($values as $groupValue) {
+                       list($foreignIdentifier, $_) = GeneralUtility::trimExplode('|', $groupValue);
+                       list($recordForeignTable, $foreignUid) = BackendUtility::splitTable_Uid($foreignIdentifier);
+                       // skip records that do not match the allowed table
+                       if (!empty($recordForeignTable) && ($recordForeignTable !== $allowedTable)) {
+                               continue;
+                       }
+                       $relatedUids[] = $foreignUid;
+               }
+
+               return $relatedUids;
+       }
+
+       /**
+        * Will read the "allowed" value from the given field configuration
+        * and returns FALSE if none or more than one has been defined.
+        * Otherwise the name of the allowed table will be returned.
+        *
+        * @param array $fieldConfig TCA "config" section for the group type field.
+        * @return bool|string
+        */
+       protected function getAllowedTableForGroupField(array $fieldConfig) {
+               $allowedTable = FALSE;
+
+               $allowedTables = GeneralUtility::trimExplode(',', $fieldConfig['allowed'], TRUE);
+               if (count($allowedTables) === 1) {
+                       $allowedTable = $allowedTables[0];
+               }
+
+               return $allowedTable;
+       }
+}
diff --git a/typo3/sysext/backend/Classes/Form/FormDataTraverser.php b/typo3/sysext/backend/Classes/Form/FormDataTraverser.php
deleted file mode 100644 (file)
index cddd993..0000000
+++ /dev/null
@@ -1,429 +0,0 @@
-<?php
-namespace TYPO3\CMS\Backend\Form;
-
-/*
- * 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\Backend\Form\FormDataGroup\TcaDatabaseRecord;
-use TYPO3\CMS\Backend\Utility\BackendUtility;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-
-/**
- * Utility class for traversing related fields in the TCA.
- *
- * This thing basically resolves __row|field syntax for the placeholder stuff. It follows a
- * given path and returns a value of a connected foreign record.
- *
- * @todo: This whole class is very hard to understand and hard to debug. It should be
- * @todo: done as a data provider to work on prepared structures instead.
- *
- * @internal: Do not use in extensions, class will be changed / removed in the future
- */
-class FormDataTraverser {
-
-       /**
-        * If this value is set during traversal and the traversal chain can
-        * not be walked to the end this value will be returned instead.
-        *
-        * @var string
-        */
-       protected $alternativeFieldValue;
-
-       /**
-        * If this is TRUE the alternative field value will be used even if
-        * the detected field value is not empty.
-        *
-        * @var bool
-        */
-       protected $forceAlternativeFieldValueUse = FALSE;
-
-       /**
-        * The row data of the record that is currently traversed.
-        *
-        * @var array
-        */
-       protected $currentRow;
-
-       /**
-        * Name of the table that is currently traversed.
-        *
-        * @var string
-        */
-       protected $currentTable;
-
-       /**
-        * If the first record in the chain is translatable the language
-        * UID of this record is stored in this variable.
-        *
-        * @var int
-        */
-       protected $originalLanguageUid = NULL;
-
-       /**
-        * Inline first pid
-        *
-        * @var int
-        */
-       protected $inlineFirstPid;
-
-       /**
-        * Traverses the array of given field names by using the TCA.
-        *
-        * @param array $fieldNameArray The field names that should be traversed.
-        * @param string $tableName The starting table name.
-        * @param array $row The starting record row.
-        * @param int $inlineFirstPid Inline first pid
-        * @return mixed The value of the last field in the chain.
-        */
-       public function getTraversedFieldValue(array $fieldNameArray, $tableName, array $row, $inlineFirstPid) {
-               $this->currentTable = $tableName;
-               $this->currentRow = $row;
-               $this->inlineFirstPid = $inlineFirstPid;
-               $fieldValue = '';
-               if (!empty($fieldNameArray)) {
-                       $this->initializeOriginalLanguageUid();
-                       $fieldValue = $this->getFieldValue($fieldNameArray);
-               }
-               return $fieldValue;
-       }
-
-       /**
-        * Checks if the current table is translatable and initializes the
-        * originalLanguageUid with the value of the languageField of the
-        * current row.
-        *
-        * @return void
-        */
-       protected function initializeOriginalLanguageUid() {
-               $fieldCtrlConfig = $GLOBALS['TCA'][$this->currentTable]['ctrl'];
-               if (!empty($fieldCtrlConfig['languageField']) && isset($this->currentRow[$fieldCtrlConfig['languageField']])) {
-                       $this->originalLanguageUid = (int)$this->currentRow[$fieldCtrlConfig['languageField']];
-               } else {
-                       $this->originalLanguageUid = FALSE;
-               }
-       }
-
-       /**
-        * Traverses the fields in the $fieldNameArray and tries to read
-        * the field values.
-        *
-        * @param array $fieldNameArray The field names that should be traversed.
-        * @return mixed The value of the last field.
-        */
-       protected function getFieldValue(array $fieldNameArray) {
-               $value = '';
-
-               $count = 0;
-               foreach ($fieldNameArray as $fieldName) {
-                       $count = $count + 1;
-                       // Skip if a defined field was actually not present in the database row
-                       // Using array_key_exists here, since TYPO3 supports NULL values as well
-                       if (!array_key_exists($fieldName, $this->currentRow) || $this->currentRow[$fieldName] === "0") {
-                               $value = '';
-                               break;
-                       }
-
-                       $value = $this->currentRow[$fieldName];
-                       // @todo: the first value was not processed with old data preprocessor and contains no |
-                       // @todo: this is simuluated here
-                       if ($count === 1) {
-                               if (!is_array($value)) {
-                                       $value = explode('|', $value);
-                               }
-                               $value = $value[0];
-                       }
-
-                       if (empty($value)) {
-                               break;
-                       }
-
-                       $this->currentRow = $this->getRelatedRecordRow($fieldName, $value);
-                       if ($this->currentRow === FALSE) {
-                               break;
-                       }
-               }
-
-               if ((empty($value) || $this->forceAlternativeFieldValueUse) && !empty($this->alternativeFieldValue)) {
-                       $value = $this->alternativeFieldValue;
-               }
-
-               return $value;
-       }
-
-       /**
-        * Tries to read the related record from the database depending on
-        * the TCA. Supported types are group (db), select and inline.
-        *
-        * @param string $fieldName The name of the field of which the related record should be fetched.
-        * @param string $value The current field value.
-        * @return array|boolean The related row if it could be found otherwise FALSE.
-        */
-       protected function getRelatedRecordRow($fieldName, $value) {
-               $fieldConfig = $GLOBALS['TCA'][$this->currentTable]['columns'][$fieldName]['config'];
-               $possibleUids = array();
-
-               switch ($fieldConfig['type']) {
-                       case 'group':
-                               $possibleUids = $this->getRelatedGroupFieldUids($fieldConfig, $value);
-                               break;
-                       case 'select':
-                               $possibleUids = $this->getRelatedSelectFieldUids($fieldConfig, $fieldName, $value);
-                               break;
-                       case 'inline':
-                               $possibleUids = $this->getRelatedInlineFieldUids($fieldConfig, $fieldName, $value);
-                               break;
-               }
-
-               $relatedRow = FALSE;
-               $possibleUidsCount = count($possibleUids);
-               if ($possibleUidsCount === 1) {
-                       $relatedRow = $this->getRecordRow($possibleUids[0]);
-               }
-
-               return $relatedRow;
-       }
-
-       /**
-        * Tries to get the related UIDs of a group field.
-        *
-        * @param array $fieldConfig "config" section from the TCA for the current field.
-        * @param string $value The current value (normally a comma separated record list, possibly consisting of multiple parts [table]_[uid]|[title]).
-        * @return array Array of related UIDs.
-        */
-       protected function getRelatedGroupFieldUids(array $fieldConfig, $value) {
-               $relatedUids = array();
-               $allowedTable = $this->getAllowedTableForGroupField($fieldConfig);
-
-               if (($fieldConfig['internal_type'] !== 'db') || ($allowedTable === FALSE)) {
-                       return $relatedUids;
-               }
-
-               $values = GeneralUtility::trimExplode(',', $value, TRUE);
-               foreach ($values as $groupValue) {
-                       list($foreignIdentifier, $foreignTitle) = GeneralUtility::trimExplode('|', $groupValue);
-                       list($recordForeignTable, $foreignUid) = BackendUtility::splitTable_Uid($foreignIdentifier);
-                       // skip records that do not match the allowed table
-                       if (!empty($recordForeignTable) && ($recordForeignTable !== $allowedTable)) {
-                               continue;
-                       }
-                       if (!empty($foreignTitle)) {
-                               $this->alternativeFieldValue = rawurldecode($foreignTitle);
-                       }
-                       $relatedUids[] = $foreignUid;
-               }
-
-               if (!empty($relatedUids)) {
-                       $this->currentTable = $allowedTable;
-               }
-
-               return $relatedUids;
-       }
-
-       /**
-        * Tries to get the related UID of an inline field.
-        *
-        * @param array $fieldConfig "config" section of the TCA configuration of the related inline field.
-        * @param string $fieldName The name of the inline field.
-        * @param string $value The value in the local table (normally a comma separated list of the inline record UIDs).
-        * @return array Array of related UIDs.
-        */
-       protected function getRelatedInlineFieldUids(array $fieldConfig, $fieldName, $value) {
-               $relatedUids = array();
-
-               $PA = array('itemFormElValue' => $value);
-               $inlineRelatedRecordResolver = GeneralUtility::makeInstance(InlineRelatedRecordResolver::class);
-               $items = $inlineRelatedRecordResolver->getRelatedRecords($this->currentTable, $fieldName, $this->currentRow, $PA, $fieldConfig, $this->inlineFirstPid);
-               if ($items['count'] > 0) {
-                       $this->currentTable = $fieldConfig['foreign_table'];
-                       foreach ($items['records'] as $inlineRecord) {
-                               $relatedUids[] = $inlineRecord['uid'];
-                       }
-               }
-
-               return $relatedUids;
-       }
-
-       /**
-        * Will read the "allowed" value from the given field configuration
-        * and returns FALSE if none was defined or more than one.
-        *
-        * If exactly one table was defined the name of that table is returned.
-        *
-        * @param array $fieldConfig "config" section of a group field from the TCA.
-        * @return bool|string FALSE if none ore more than one table was found, otherwise the name of the table.
-        */
-       protected function getAllowedTableForGroupField(array $fieldConfig) {
-               $allowedTable = FALSE;
-
-               $allowedTables = GeneralUtility::trimExplode(',', $fieldConfig['allowed'], TRUE);
-               if (count($allowedTables) === 1) {
-                       $allowedTable = $allowedTables[0];
-               }
-
-               return $allowedTable;
-       }
-
-       /**
-        * Fetch a record from the database
-        *
-        * @param int $uid The UID of the record that should be fetched.
-        * @return array|boolean FALSE if the record can not be accessed, otherwise the data of the requested record.
-        */
-       protected function getRecordRow($uid) {
-               $selectDataInput = [
-                       'command' => 'edit',
-                       'vanillaUid' => (int)$uid,
-                       'tableName' => $this->currentTable,
-               ];
-               /** @var TcaDatabaseRecord $formDataGroup */
-               $formDataGroup = GeneralUtility::makeInstance(TcaDatabaseRecord::class);
-               /** @var FormDataCompiler $formDataCompiler */
-               $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup);
-               $compilerResult = $formDataCompiler->compile($selectDataInput);
-               $databaseRow = $compilerResult['databaseRow'];
-               $newDatabaseRow = [];
-               foreach ($databaseRow as $fieldName => $value) {
-                       $newDatabaseRow[$fieldName] = $value;
-                       if (is_array($value)) {
-                               $newDatabaseRow[$fieldName] = implode(',', $value);
-                       }
-               }
-               return $newDatabaseRow;
-       }
-
-       /**
-        * Tries to get the correct record based on the parent translation by
-        * traversing all given related UIDs and checking if their language UID
-        * matches the stored original language UID.
-        *
-        * If exactly one match was found for the original language the resulting
-        * row is returned, otherwise FALSE.
-        *
-        * @param array $relatedUids All possible matching UIDs.
-        * @return bool|array The row data if a matching record was found, FALSE otherwise.
-        */
-       protected function getMatchingRecordRowByTranslation(array $relatedUids) {
-               if ($this->originalLanguageUid === FALSE) {
-                       return FALSE;
-               }
-
-               $fieldCtrlConfig = $GLOBALS['TCA'][$this->currentTable]['ctrl'];
-               if (empty($fieldCtrlConfig['languageField'])) {
-                       return FALSE;
-               }
-
-               $languageField = $fieldCtrlConfig['languageField'];
-               $foundRows = array();
-               foreach ($relatedUids as $relatedUid) {
-                       $currentRow = $this->getRecordRow($relatedUid);
-                       if (!isset($currentRow[$languageField])) {
-                               continue;
-                       }
-                       if ((int)$currentRow[$languageField] === $this->originalLanguageUid) {
-                               $foundRows[] = $currentRow;
-                       }
-               }
-
-               $relatedRow = FALSE;
-               if (count($foundRows) === 1) {
-                       $relatedRow = $foundRows[0];
-               }
-
-               return $relatedRow;
-       }
-
-       /**
-        * If the select field is build by a foreign_table the related UIDs
-        * will be returned.
-        *
-        * Otherwise the label of the currently selected value will be written
-        * to the alternativeFieldValue class property.
-        *
-        * @param array $fieldConfig The "config" section of the TCA for the current select field.
-        * @param string $fieldName The name of the select field.
-        * @param string $value The current value in the local record, usually a comma separated list of selected values.
-        * @return array Array of related UIDs.
-        */
-       protected function getRelatedSelectFieldUids(array $fieldConfig, $fieldName, $value) {
-               $relatedUids = array();
-
-               $isTraversable = FALSE;
-               if (isset($fieldConfig['foreign_table'])) {
-                       $isTraversable = TRUE;
-                       // if a foreign_table is used we pre-filter the records for performance
-                       $fieldConfig['foreign_table_where'] .= ' AND ' . $fieldConfig['foreign_table'] . '.uid IN (' . $value . ')';
-               }
-
-               /** @var TcaDatabaseRecord $formDataGroup */
-               $formDataGroup = GeneralUtility::makeInstance(TcaDatabaseRecord::class);
-               /** @var FormDataCompiler $formDataCompiler */
-               $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup);
-               $formDataInput = [
-                       'vanillaUid' => (int)$this->currentRow['uid'],
-                       'tableName' => $this->currentTable,
-                       'command' => 'edit',
-               ];
-               $formDataResult = $formDataCompiler->compile($formDataInput);
-               $selectItemArray = [];
-               if (isset($formDataResult['processedTca']['columns'][$fieldName]['config']['items'])
-                       && is_array($formDataResult['processedTca']['columns'][$fieldName]['config']['items'])
-               ) {
-                       $selectItemArray = $formDataResult['processedTca']['columns'][$fieldName]['config']['items'];
-               }
-
-               if ($isTraversable && !empty($selectItemArray)) {
-                       $this->currentTable = $fieldConfig['foreign_table'];
-                       $relatedUids = $this->getSelectedValuesFromSelectItemArray($selectItemArray, $value);
-               } else {
-                       $selectedLabels = $this->getSelectedValuesFromSelectItemArray($selectItemArray, $value, 1, TRUE);
-                       if (count($selectedLabels) === 1) {
-                               $this->alternativeFieldValue = $selectedLabels[0];
-                               $this->forceAlternativeFieldValueUse = TRUE;
-                       }
-               }
-
-               return $relatedUids;
-       }
-
-       /**
-        * Extracts the selected values from a given array of select items.
-        *
-        * @param array $selectItemArray The select item array generated by \TYPO3\CMS\Backend\Form\FormEngine->getSelectItems.
-        * @param string $value The currently selected value(s) as comma separated list.
-        * @param int|NULL $maxItems Optional value, if set processing is skipped and an empty array will be returned when the number of selected values is larger than the provided value.
-        * @param bool $returnLabels If TRUE the select labels will be returned instead of the values.
-        * @return array
-        */
-       protected function getSelectedValuesFromSelectItemArray(array $selectItemArray, $value, $maxItems = NULL, $returnLabels = FALSE) {
-               $values = GeneralUtility::trimExplode(',', $value);
-               $selectedValues = array();
-
-               if ($maxItems !== NULL && (count($values) > (int)$maxItems)) {
-                       return $selectedValues;
-               }
-
-               foreach ($selectItemArray as $selectItem) {
-                       $selectItemValue = $selectItem[1];
-                       if (in_array($selectItemValue, $values)) {
-                               if ($returnLabels) {
-                                       $selectedValues[] = $selectItem[0];
-                               } else {
-                                       $selectedValues[] = $selectItemValue;
-                               }
-                       }
-               }
-
-               return $selectedValues;
-       }
-
-}
diff --git a/typo3/sysext/backend/Tests/Unit/Form/FormDataGroup/TcaInputPlaceholderRecordTest.php b/typo3/sysext/backend/Tests/Unit/Form/FormDataGroup/TcaInputPlaceholderRecordTest.php
new file mode 100644 (file)
index 0000000..cdd2963
--- /dev/null
@@ -0,0 +1,97 @@
+<?php
+namespace TYPO3\CMS\Backend\Tests\Unit\Form\FormDataGroup;
+
+/*
+ * 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 Prophecy\Argument;
+use Prophecy\Prophecy\ObjectProphecy;
+use TYPO3\CMS\Backend\Form\FormDataProviderInterface;
+use TYPO3\CMS\Backend\Form\FormDataGroup\TcaInputPlaceholderRecord;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Service\DependencyOrderingService;
+use TYPO3\CMS\Core\Tests\UnitTestCase;
+
+/**
+ * Test case
+ */
+class TcaInputPlaceholderRecordTest extends UnitTestCase {
+
+       /**
+        * @var TcaInputPlaceholderRecord
+        */
+       protected $subject;
+
+       protected function setUp() {
+               $this->subject = new TcaInputPlaceholderRecord();
+       }
+
+       /**
+        * @test
+        */
+       public function compileReturnsIncomingData() {
+               /** @var DependencyOrderingService|ObjectProphecy $orderingServiceProphecy */
+               $orderingServiceProphecy = $this->prophesize(DependencyOrderingService::class);
+               GeneralUtility::addInstance(DependencyOrderingService::class, $orderingServiceProphecy->reveal());
+               $orderingServiceProphecy->orderByDependencies(Argument::cetera())->willReturnArgument(0);
+
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['formDataGroup']['tcaInputPlaceholderRecord'] = array();
+
+               $input = array('foo');
+
+               $this->assertEquals($input, $this->subject->compile($input));
+       }
+
+       /**
+        * @test
+        */
+       public function compileReturnsResultChangedByDataProvider() {
+               /** @var DependencyOrderingService|ObjectProphecy $orderingServiceProphecy */
+               $orderingServiceProphecy = $this->prophesize(DependencyOrderingService::class);
+               GeneralUtility::addInstance(DependencyOrderingService::class, $orderingServiceProphecy->reveal());
+               $orderingServiceProphecy->orderByDependencies(Argument::cetera())->willReturnArgument(0);
+
+               /** @var FormDataProviderInterface|ObjectProphecy $formDataProviderProphecy */
+               $formDataProviderProphecy = $this->prophesize(FormDataProviderInterface::class);
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['formDataGroup']['tcaInputPlaceholderRecord'] = array(
+                       FormDataProviderInterface::class => array(),
+               );
+               GeneralUtility::addInstance(FormDataProviderInterface::class, $formDataProviderProphecy->reveal());
+               $providerResult = array('foo');
+               $formDataProviderProphecy->addData(Argument::cetera())->shouldBeCalled()->willReturn($providerResult);
+
+               $this->assertEquals($providerResult, $this->subject->compile([]));
+       }
+
+       /**
+        * @test
+        */
+       public function compileThrowsExceptionIfDataProviderDoesNotImplementInterface() {
+               /** @var DependencyOrderingService|ObjectProphecy $orderingServiceProphecy */
+               $orderingServiceProphecy = $this->prophesize(DependencyOrderingService::class);
+               GeneralUtility::addInstance(DependencyOrderingService::class, $orderingServiceProphecy->reveal());
+               $orderingServiceProphecy->orderByDependencies(Argument::cetera())->willReturnArgument(0);
+
+               /** @var FormDataProviderInterface|ObjectProphecy $formDataProviderProphecy */
+               $formDataProviderProphecy = $this->prophesize(\stdClass::class);
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['formDataGroup']['tcaInputPlaceholderRecord'] = array(
+                       \stdClass::class => array(),
+               );
+               GeneralUtility::addInstance(\stdClass::class, $formDataProviderProphecy->reveal());
+
+               $this->setExpectedException(\UnexpectedValueException::class, $this->anything(), 1443986127);
+
+               $this->subject->compile([]);
+       }
+
+}
diff --git a/typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/TcaInputPlaceholdersTest.php b/typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/TcaInputPlaceholdersTest.php
new file mode 100644 (file)
index 0000000..1980023
--- /dev/null
@@ -0,0 +1,370 @@
+<?php
+namespace TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider;
+
+/*
+ * 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 Prophecy\Prophecy\ObjectProphecy;
+use TYPO3\CMS\Backend\Form\FormDataCompiler;
+use TYPO3\CMS\Backend\Form\FormDataGroup\TcaInputPlaceholderRecord;
+use TYPO3\CMS\Backend\Form\FormDataProvider\TcaInputPlaceholders;
+use TYPO3\CMS\Core\Tests\UnitTestCase;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+/**
+ * Test case
+ */
+class TcaInputPlaceholdersTest extends UnitTestCase {
+
+       /**
+        * @var TcaInputPlaceholders
+        */
+       protected $subject;
+
+       public function setUp() {
+               $this->subject = new TcaInputPlaceholders();
+       }
+
+       /**
+        * @test
+        */
+       public function addDataRemovesEmptyPlaceholderOption() {
+               $input = [
+                       'tableName' => 'aTable',
+                       'databaseRow' => [],
+                       'processedTca' => [
+                               'columns' => [
+                                       'aField' => [
+                                               'config' => [
+                                                       'type' => 'input',
+                                                       'placeholder' => '',
+                                               ]
+                                       ]
+                               ],
+                       ],
+               ];
+
+               $expected = $input;
+               unset($expected['processedTca']['columns']['aField']['config']['placeholder']);
+
+               $this->assertSame($expected, $this->subject->addData($input));
+       }
+
+       /**
+        * @test
+        */
+       public function addDataReturnsUnmodifiedSimpleStringPlaceholder() {
+               $input = [
+                       'tableName' => 'aTable',
+                       'databaseRow' => [],
+                       'processedTca' => [
+                               'columns' => [
+                                       'aField' => [
+                                               'config' => [
+                                                       'type' => 'input',
+                                                       'placeholder' => 'aPlaceholder',
+                                               ]
+                                       ]
+                               ],
+                       ],
+               ];
+
+               $expected = $input;
+
+               $this->assertSame($expected, $this->subject->addData($input));
+       }
+
+       /**
+        * @test
+        */
+       public function addDataReturnsValueFromDatabaseRowAsPlaceholder() {
+               $input = [
+                       'tableName' => 'aTable',
+                       'databaseRow' => [
+                               'anotherField' => 'anotherPlaceholder'
+                       ],
+                       'processedTca' => [
+                               'columns' => [
+                                       'aField' => [
+                                               'config' => [
+                                                       'type' => 'input',
+                                                       'placeholder' => '__row|anotherField',
+                                               ]
+                                       ]
+                               ],
+                       ],
+               ];
+
+               $expected = $input;
+               $expected['processedTca']['columns']['aField']['config']['placeholder'] = 'anotherPlaceholder';
+
+               $this->assertSame($expected, $this->subject->addData($input));
+       }
+
+       /**
+        * @test
+        */
+       public function addDataReturnsValueFromSelectTypeRelation() {
+               $input = [
+                       'tableName' => 'aTable',
+                       'databaseRow' => [
+                               'aField' => '',
+                               'aRelationField' => ['42'],
+                       ],
+                       'processedTca' => [
+                               'columns' => [
+                                       'aField' => [
+                                               'config' => [
+                                                       'type' => 'input',
+                                                       'placeholder' => '__row|aRelationField|aForeignField',
+                                               ]
+                                       ],
+                                       'aRelationField' => [
+                                               'config' => [
+                                                       'type' => 'select',
+                                                       'foreign_table' => 'aForeignTable'
+                                               ]
+                                       ]
+                               ],
+                       ],
+               ];
+
+               $aForeignTableInput = [
+                       'tableName' => 'aForeignTable',
+                       'databaseRow' => [
+                               'aForeignField' => 'aForeignValue',
+                       ],
+                       'processedTca' => [
+                               'columns' => [
+                                       'aForeignField' => [
+                                               'config' => [
+                                                       'type' => 'input',
+                                               ]
+                                       ],
+                               ],
+                       ],
+               ];
+
+               /** @var TcaInputPlaceholderRecord $languageService */
+               $formDataCompilerProphecy = $this->prophesize(FormDataCompiler::class);
+               GeneralUtility::addInstance(FormDataCompiler::class, $formDataCompilerProphecy->reveal());
+               $formDataCompilerProphecy->compile(['command' => 'edit', 'vanillaUid' => 42, 'tableName' => 'aForeignTable'])
+                       ->shouldBeCalled()
+                       ->willReturn($aForeignTableInput);
+
+               $expected = $input;
+               $expected['processedTca']['columns']['aField']['config']['placeholder'] = $aForeignTableInput['databaseRow']['aForeignField'];
+
+               $this->assertSame($expected, $this->subject->addData($input));
+       }
+
+       /**
+        * @test
+        */
+       public function addDataReturnsValueFromGroupTypeRelation() {
+               $input = [
+                       'tableName' => 'aTable',
+                       'databaseRow' => [
+                               'aField' => '',
+                               'uid_local' => 'sys_file_3|aLabel,sys_file_5|anotherLabel',
+                       ],
+                       'processedTca' => [
+                               'columns' => [
+                                       'aField' => [
+                                               'config' => [
+                                                       'type' => 'input',
+                                                       'placeholder' => '__row|uid_local|sha1',
+                                               ]
+                                       ],
+                                       'uid_local' => [
+                                               'config' => [
+                                                       'type' => 'group',
+                                                       'internal_type' => 'db',
+                                                       'allowed' => 'sys_file'
+                                               ]
+                                       ]
+                               ],
+                       ],
+               ];
+
+               $sysFileProphecyResult = [
+                       'tableName' => 'sys_file',
+                       'databaseRow' => [
+                               'sha1' => 'aSha1Value',
+                       ],
+                       'processedTca' => [
+                               'columns' => [
+                                       'sha1' => [
+                                               'config' => [
+                                                       'type' => 'input',
+                                               ]
+                                       ],
+                               ],
+                       ],
+               ];
+
+               /** @var TcaInputPlaceholderRecord $languageService */
+               $formDataCompilerProphecy = $this->prophesize(FormDataCompiler::class);
+               GeneralUtility::addInstance(FormDataCompiler::class, $formDataCompilerProphecy->reveal());
+               $formDataCompilerProphecy->compile(['command' => 'edit', 'vanillaUid' => 3, 'tableName' => 'sys_file'])
+                       ->shouldBeCalled()
+                       ->willReturn($sysFileProphecyResult);
+
+               $expected = $input;
+               $expected['processedTca']['columns']['aField']['config']['placeholder'] = $sysFileProphecyResult['databaseRow']['sha1'];
+
+               $this->assertSame($expected, $this->subject->addData($input));
+       }
+
+       /**
+        * @test
+        */
+       public function addDataReturnsValueFromInlineTypeRelation() {
+               $input = [
+                       'tableName' => 'aTable',
+                       'databaseRow' => [
+                               'aField' => '',
+                               'metadata' => '2',
+                       ],
+                       'processedTca' => [
+                               'columns' => [
+                                       'aField' => [
+                                               'config' => [
+                                                       'type' => 'input',
+                                                       'placeholder' => '__row|metadata|title',
+                                               ]
+                                       ],
+                                       'metadata' => [
+                                               'config' => [
+                                                       'readOnly' => 1,
+                                                       'type' => 'inline',
+                                                       'foreign_table' => 'sys_file_metadata',
+                                                       'foreign_field' => 'file',
+                                               ]
+                                       ]
+                               ],
+                       ],
+               ];
+
+               $sysFileMetadataProphecyResult = [
+                       'tableName' => 'sys_file_metadata',
+                       'databaseRow' => [
+                               'title' => 'aTitle',
+                       ],
+                       'processedTca' => [
+                               'columns' => [
+                                       'sha1' => [
+                                               'config' => [
+                                                       'type' => 'input',
+                                               ]
+                                       ],
+                               ],
+                       ],
+               ];
+
+               /** @var TcaInputPlaceholderRecord $languageService */
+               $formDataCompilerProphecy = $this->prophesize(FormDataCompiler::class);
+               GeneralUtility::addInstance(FormDataCompiler::class, $formDataCompilerProphecy->reveal());
+               $formDataCompilerProphecy->compile(['command' => 'edit', 'vanillaUid' => 2, 'tableName' => 'sys_file_metadata'])
+                       ->shouldBeCalled()
+                       ->willReturn($sysFileMetadataProphecyResult);
+
+               $expected = $input;
+               $expected['processedTca']['columns']['aField']['config']['placeholder'] = $sysFileMetadataProphecyResult['databaseRow']['title'];
+
+               $this->assertSame($expected, $this->subject->addData($input));
+       }
+
+       /**
+        * @test
+        */
+       public function addDataReturnsValueFromRelationsRecursively() {
+               $input = [
+                       'tableName' => 'aTable',
+                       'databaseRow' => [
+                               'aField' => '',
+                               'uid_local' => 'sys_file_3|aLabel,sys_file_5|anotherLabel',
+                       ],
+                       'processedTca' => [
+                               'columns' => [
+                                       'aField' => [
+                                               'config' => [
+                                                       'type' => 'input',
+                                                       'placeholder' => '__row|uid_local|metadata|title',
+                                               ]
+                                       ],
+                                       'uid_local' => [
+                                               'config' => [
+                                                       'type' => 'group',
+                                                       'internal_type' => 'db',
+                                                       'allowed' => 'sys_file'
+                                               ]
+                                       ]
+                               ],
+                       ],
+               ];
+
+               $sysFileProphecyResult = [
+                       'tableName' => 'sys_file',
+                       'databaseRow' => [
+                               'metadata' => '7',
+                       ],
+                       'processedTca' => [
+                               'columns' => [
+                                       'metadata' => [
+                                               'config' => [
+                                                       'readOnly' => 1,
+                                                       'type' => 'inline',
+                                                       'foreign_table' => 'sys_file_metadata',
+                                                       'foreign_field' => 'file',
+                                               ]
+                                       ]
+                               ],
+                       ],
+               ];
+
+               $sysFileMetadataProphecyResult = [
+                       'tableName' => 'sys_file_metadata',
+                       'databaseRow' => [
+                               'title' => 'aTitle',
+                       ],
+                       'processedTca' => [
+                               'columns' => [
+                                       'sha1' => [
+                                               'config' => [
+                                                       'type' => 'input',
+                                               ]
+                                       ],
+                               ],
+                       ],
+               ];
+
+               $sysFileFormDataCompilerProphecy = $this->prophesize(FormDataCompiler::class);
+               GeneralUtility::addInstance(FormDataCompiler::class, $sysFileFormDataCompilerProphecy->reveal());
+               $sysFileFormDataCompilerProphecy->compile(['command' => 'edit', 'vanillaUid' => 3, 'tableName' => 'sys_file'])
+                       ->shouldBeCalled()
+                       ->willReturn($sysFileProphecyResult);
+
+               $sysFileMetaDataFormDataCompilerProphecy = $this->prophesize(FormDataCompiler::class);
+               GeneralUtility::addInstance(FormDataCompiler::class, $sysFileMetaDataFormDataCompilerProphecy->reveal());
+               $sysFileMetaDataFormDataCompilerProphecy->compile(['command' => 'edit', 'vanillaUid' => 7, 'tableName' => 'sys_file_metadata'])
+                       ->shouldBeCalled()
+                       ->willReturn($sysFileMetadataProphecyResult);
+
+               $expected = $input;
+               $expected['processedTca']['columns']['aField']['config']['placeholder'] = $sysFileMetadataProphecyResult['databaseRow']['title'];
+
+               $this->assertSame($expected, $this->subject->addData($input));
+       }
+
+}
index b38a9e4..c1986bf 100644 (file)
@@ -469,6 +469,11 @@ return array(
                                                        \TYPO3\CMS\Backend\Form\FormDataProvider\TcaSelectItems::class,
                                                ),
                                        ),
+                                       \TYPO3\CMS\Backend\Form\FormDataProvider\TcaInputPlaceholders::class => array(
+                                               'depends' => array(
+                                                       \TYPO3\CMS\Backend\Form\FormDataProvider\TcaInline::class,
+                                               ),
+                                       ),
                                        \TYPO3\CMS\Backend\Form\FormDataProvider\TcaRecordTitle::class => array(
                                                'depends' => array(
                                                        \TYPO3\CMS\Backend\Form\FormDataProvider\TcaInline::class,
@@ -508,6 +513,57 @@ return array(
                                                ),
                                        ),
                                ),
+                               'tcaInputPlaceholderRecord' => array(
+                                       \TYPO3\CMS\Backend\Form\FormDataProvider\DatabaseEditRow::class => array(),
+                                       \TYPO3\CMS\Backend\Form\FormDataProvider\TableTca::class => array(
+                                               'depends' => array(
+                                                       \TYPO3\CMS\Backend\Form\FormDataProvider\DatabaseEditRow::class,
+                                               ),
+                                       ),
+                                       \TYPO3\CMS\Backend\Form\FormDataProvider\DatabaseRowDefaultValues::class => array(
+                                               'depends' => array(
+                                                       \TYPO3\CMS\Backend\Form\FormDataProvider\TableTca::class,
+                                               ),
+                                       ),
+                                       \TYPO3\CMS\Backend\Form\FormDataProvider\TcaGroup::class => array(
+                                               'depends' => array(
+                                                       \TYPO3\CMS\Backend\Form\FormDataProvider\TableTca::class,
+                                               ),
+                                       ),
+                                       \TYPO3\CMS\Backend\Form\FormDataProvider\DatabaseRecordTypeValue::class => array(
+                                               'depends' => array(
+                                                       \TYPO3\CMS\Backend\Form\FormDataProvider\TableTca::class,
+                                               ),
+                                       ),
+                                       \TYPO3\CMS\Backend\Form\FormDataProvider\InitializeProcessedTca::class => array(
+                                               'depends' => array(
+                                                       \TYPO3\CMS\Backend\Form\FormDataProvider\TableTca::class,
+                                                       \TYPO3\CMS\Backend\Form\FormDataProvider\DatabaseRecordTypeValue::class,
+                                               ),
+                                       ),
+                                       \TYPO3\CMS\Backend\Form\FormDataProvider\TcaRadioItems::class => array(
+                                               'depends' => array(
+                                                       \TYPO3\CMS\Backend\Form\FormDataProvider\InitializeProcessedTca::class,
+                                               ),
+                                       ),
+                                       \TYPO3\CMS\Backend\Form\FormDataProvider\TcaCheckboxItems::class => array(
+                                               'depends' => array(
+                                                       \TYPO3\CMS\Backend\Form\FormDataProvider\InitializeProcessedTca::class,
+                                                       \TYPO3\CMS\Backend\Form\FormDataProvider\TcaRadioItems::class
+                                               ),
+                                       ),
+                                       \TYPO3\CMS\Backend\Form\FormDataProvider\TcaSelectItems::class => array(
+                                               'depends' => array(
+                                                       \TYPO3\CMS\Backend\Form\FormDataProvider\InitializeProcessedTca::class,
+                                                       \TYPO3\CMS\Backend\Form\FormDataProvider\TcaCheckboxItems::class,
+                                               ),
+                                       ),
+                                       \TYPO3\CMS\Backend\Form\FormDataProvider\TcaInline::class => array(
+                                               'depends' => array(
+                                                       \TYPO3\CMS\Backend\Form\FormDataProvider\TcaSelectItems::class,
+                                               ),
+                                       ),
+                               ),
                        ),
                ),
        ),
index d160965..6d2693c 100644 (file)
@@ -120,9 +120,8 @@ class RsaInputElement extends AbstractFormElement {
                }
 
                // This is the EDITABLE form field.
-               $placeholderValue = $this->getPlaceholderValue($table, $config, $row);
-               if (!empty($placeholderValue)) {
-                       $attributes['placeholder'] = trim($languageService->sL($placeholderValue));
+               if (!empty($config['placeholder'])) {
+                       $attributes['placeholder'] = trim($config['placeholder']);
                }
 
                // Build the attribute string