[BUGFIX] Respect page TSConfig pid overrides for new inline children
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Form / FormDataProvider / DatabaseRowInitializeNew.php
1 <?php
2 namespace TYPO3\CMS\Backend\Form\FormDataProvider;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Backend\Form\FormDataProviderInterface;
18 use TYPO3\CMS\Core\Utility\GeneralUtility;
19 use TYPO3\CMS\Core\Utility\MathUtility;
20
21 /**
22 * On "new" command, initialize new database row with default data
23 */
24 class DatabaseRowInitializeNew implements FormDataProviderInterface
25 {
26 /**
27 * Initialize new row with default values from various sources
28 * There are 4 sources of default values. Mind the order, the last takes precedence.
29 *
30 * @param array $result
31 * @return array
32 * @throws \UnexpectedValueException
33 */
34 public function addData(array $result)
35 {
36 if ($result['command'] !== 'new') {
37 return $result;
38 }
39 if (!is_array($result['databaseRow'])) {
40 throw new \UnexpectedValueException(
41 'databaseRow of table ' . $result['tableName'] . ' is not an array',
42 1444431128
43 );
44 }
45
46 $result = $this->setDefaultsFromUserTsConfig($result);
47 $result = $this->setDefaultsFromPageTsConfig($result);
48 $result = $this->setDefaultsFromNeighborRow($result);
49 $result = $this->setDefaultsFromDevVals($result);
50 $result = $this->setDefaultsFromInlineRelations($result);
51 $result = $this->setPid($result);
52
53 return $result;
54 }
55
56 /**
57 * Set defaults defined by user ts "TCAdefaults"
58 *
59 * @param array $result Result array
60 * @return array Modified result array
61 */
62 protected function setDefaultsFromUserTsConfig(array $result)
63 {
64 $tableNameWithDot = $result['tableName'] . '.';
65 // Apply default values from user typo script "TCAdefaults" if any
66 if (isset($result['userTsConfig']['TCAdefaults.'][$tableNameWithDot])
67 && is_array($result['userTsConfig']['TCAdefaults.'][$tableNameWithDot])
68 ) {
69 foreach ($result['userTsConfig']['TCAdefaults.'][$tableNameWithDot] as $fieldName => $fieldValue) {
70 if (isset($result['processedTca']['columns'][$fieldName])) {
71 $result['databaseRow'][$fieldName] = $fieldValue;
72 }
73 }
74 }
75 return $result;
76 }
77
78 /**
79 * Set defaults defined by page ts "TCAdefaults"
80 *
81 * @param array $result Result array
82 * @return array Modified result array
83 */
84 protected function setDefaultsFromPageTsConfig(array $result)
85 {
86 $tableNameWithDot = $result['tableName'] . '.';
87 if (isset($result['pageTsConfig']['TCAdefaults.'][$tableNameWithDot])
88 && is_array($result['pageTsConfig']['TCAdefaults.'][$tableNameWithDot])
89 ) {
90 foreach ($result['pageTsConfig']['TCAdefaults.'][$tableNameWithDot] as $fieldName => $fieldValue) {
91 if (isset($result['processedTca']['columns'][$fieldName])) {
92 $result['databaseRow'][$fieldName] = $fieldValue;
93 }
94 }
95 }
96 return $result;
97 }
98
99 /**
100 * If a neighbor row is given (if vanillaUid was negative), field can be initialized with values
101 * from neighbor for fields registered in TCA['ctrl']['useColumnsForDefaultValues'].
102 *
103 * @param array $result Result array
104 * @return array Modified result array
105 */
106 protected function setDefaultsFromNeighborRow(array $result)
107 {
108 if (is_array($result['neighborRow'])
109 && !empty($result['processedTca']['ctrl']['useColumnsForDefaultValues'])
110 ) {
111 $defaultColumns = GeneralUtility::trimExplode(',', $result['processedTca']['ctrl']['useColumnsForDefaultValues'], true);
112 foreach ($defaultColumns as $fieldName) {
113 if (isset($result['processedTca']['columns'][$fieldName])
114 && isset($result['neighborRow'][$fieldName])
115 ) {
116 $result['databaseRow'][$fieldName] = $result['neighborRow'][$fieldName];
117 }
118 }
119 }
120 return $result;
121 }
122
123 /**
124 * Apply default values from GET / POST
125 *
126 * @todo: Fetch this stuff from request object as soon as modules were moved to PSR-7,
127 * @todo: or hand values over via $result array, so the _GP access is transferred to
128 * @todo: controllers concern.
129 *
130 * @param array $result Result array
131 * @return array Modified result array
132 */
133 protected function setDefaultsFromDevVals(array $result)
134 {
135 $tableName = $result['tableName'];
136 $defaultValuesFromGetPost = GeneralUtility::_GP('defVals');
137 if (isset($defaultValuesFromGetPost[$tableName])
138 && is_array($defaultValuesFromGetPost[$tableName])
139 ) {
140 foreach ($defaultValuesFromGetPost[$tableName] as $fieldName => $fieldValue) {
141 if (isset($result['processedTca']['columns'][$fieldName])) {
142 $result['databaseRow'][$fieldName] = $fieldValue;
143 }
144 }
145 }
146 return $result;
147 }
148
149 /**
150 * Inline scenario if a new intermediate record to an existing child-child is
151 * compiled. Set "foreign_selector" field of this intermediate row to given
152 * "childChildUid". See TcaDataCompiler array comment of inlineChildChildUid
153 * for more details.
154 *
155 * @param array $result Result array
156 * @return array Modified result array
157 * @throws \UnexpectedValueException
158 */
159 protected function setDefaultsFromInlineRelations(array $result)
160 {
161 if ($result['inlineChildChildUid'] === null) {
162 return $result;
163 }
164 if (!is_int($result['inlineChildChildUid'])) {
165 throw new \UnexpectedValueException(
166 'An inlineChildChildUid is given for table ' . $result['tableName'] . ', but is not an integer',
167 1444434103
168 );
169 }
170 if (!isset($result['inlineParentConfig']['foreign_selector'])) {
171 throw new \UnexpectedValueException(
172 'An inlineChildChildUid is given for table ' . $result['tableName'] . ', but no foreign_selector in inlineParentConfig',
173 1444434102
174 );
175 }
176 $selectorFieldName = $result['inlineParentConfig']['foreign_selector'];
177 if (!isset($result['processedTca']['columns'][$selectorFieldName]['config']['type'])
178 || ($result['processedTca']['columns'][$selectorFieldName]['config']['type'] !== 'select'
179 && $result['processedTca']['columns'][$selectorFieldName]['config']['type'] !== 'group'
180 )
181 ) {
182 throw new \UnexpectedValueException(
183 $selectorFieldName . ' is target type of a foreign_selector field to table ' . $result['tableName'] . ' and must be either a select or group type field',
184 1444434104
185 );
186 }
187
188 if ($result['inlineChildChildUid']) {
189 $result['databaseRow'][$selectorFieldName] = $result['inlineChildChildUid'];
190 }
191
192 return $result;
193 }
194
195 /**
196 * Set the pid. This is either the vanillaUid (see description in FormDataCompiler),
197 * or a pid given by pageTsConfig for inline children.
198 *
199 * @param array $result Result array
200 * @return array Modified result array
201 * @throws \UnexpectedValueException
202 */
203 protected function setPid(array $result)
204 {
205 // Set pid to vanillaUid. This can be a negative value
206 // if the record is added relative to another record.
207 $result['databaseRow']['pid'] = $result['vanillaUid'];
208
209 // In case a new inline record is created, the pid can be set to a different value
210 // by pageTsConfig, but not by userTsConfig. This overrides the above pid selection
211 // and forces the pid of new inline children.
212 $tableNameWithDot = $result['tableName'] . '.';
213 if ($result['isInlineChild'] && isset($result['pageTsConfig']['TCAdefaults.'][$tableNameWithDot]['pid'])) {
214 if (!MathUtility::canBeInterpretedAsInteger($result['pageTsConfig']['TCAdefaults.'][$tableNameWithDot]['pid'])) {
215 throw new \UnexpectedValueException(
216 'page TSConfig setting TCAdefaults.' . $tableNameWithDot . 'pid must be a number, but given string '
217 . $result['pageTsConfig']['TCAdefaults.'][$tableNameWithDot]['pid'] . ' can not be interpreted as integer',
218 1461598332
219 );
220 }
221 $result['databaseRow']['pid'] = (int)$result['pageTsConfig']['TCAdefaults.'][$tableNameWithDot]['pid'];
222 }
223
224 return $result;
225 }
226 }