[BUGFIX] Fix several typos in php comments
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Form / FormDataCompiler.php
1 <?php
2 namespace TYPO3\CMS\Backend\Form;
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 /**
18 * Create and return a defined array of data ready to be used by the
19 * container / element render part of FormEngine
20 */
21 class FormDataCompiler
22 {
23 /**
24 * Data group that provides data
25 *
26 * @var FormDataGroupInterface
27 */
28 protected $formDataGroup;
29
30 /**
31 * List of top level array elements to be unset from
32 * result array before final result is returned.
33 *
34 * @var array
35 */
36 protected $removeKeysFromFinalResultArray = [
37 ];
38
39 /**
40 * Get form data group injected
41 *
42 * @param FormDataGroupInterface $formDataGroup
43 */
44 public function __construct(FormDataGroupInterface $formDataGroup)
45 {
46 $this->formDataGroup = $formDataGroup;
47 }
48
49 /**
50 * Main entry method maps given data input array and sanitizes some
51 * crucial input parameters and calls compile on FormDataGroupInterface.
52 *
53 * @param array $initialData Initial set of data to map into result array
54 * @return array Result with data
55 * @throws \InvalidArgumentException
56 * @throws \UnexpectedValueException
57 */
58 public function compile(array $initialData)
59 {
60 $result = $this->initializeResultArray();
61
62 // There must be only keys that actually exist in result data.
63 $keysNotInResult = array_diff(array_keys($initialData), array_keys($result));
64 if (!empty($keysNotInResult)) {
65 throw new \InvalidArgumentException(
66 'Array keys ' . implode(',', $keysNotInResult) . ' do not exist in result array and can not be set',
67 1440601540
68 );
69 }
70
71 foreach ($initialData as $dataKey => $dataValue) {
72 if ($dataKey === 'command') {
73 // Sanitize $command
74 if ($dataValue !== 'edit' && $dataValue !== 'new') {
75 throw new \InvalidArgumentException('Command must be either "edit" or "new"', 1437653136);
76 }
77 }
78 if ($dataKey === 'tableName') {
79 // Sanitize $tableName
80 if (empty($dataValue)) {
81 throw new \InvalidArgumentException('No $tableName given', 1437654409);
82 }
83 }
84 if ($dataKey === 'vanillaUid') {
85 if (!is_int($dataValue)) {
86 throw new \InvalidArgumentException('$vanillaUid is not an integer', 1437654247);
87 }
88 if (isset($initialData['command']) && $initialData['command'] === 'edit' && $dataValue < 0) {
89 throw new \InvalidArgumentException('Negative $vanillaUid is not supported with $command="edit', 1437654332);
90 }
91 }
92 $result[$dataKey] = $dataValue;
93 }
94
95 // Call the data group provider but take care it does not add or remove result keys
96 // This is basically a safety measure against data providers colliding with our array "contract"
97 $resultKeysBeforeFormDataGroup = array_keys($result);
98
99 $result = $this->formDataGroup->compile($result);
100
101 if (!is_array($result)) {
102 throw new \UnexpectedValueException(
103 'Data group provider must return array',
104 1446664764
105 );
106 }
107
108 if (!empty($result['renderData'])) {
109 throw new \RuntimeException(
110 'Array \'renderData\' not empty. Data providers must not add data here',
111 1485201279
112 );
113 }
114
115 $resultKeysAfterFormDataGroup = array_keys($result);
116
117 if ($resultKeysAfterFormDataGroup !== $resultKeysBeforeFormDataGroup) {
118 throw new \UnexpectedValueException(
119 'Data group provider must not change result key list',
120 1438079402
121 );
122 }
123
124 // Remove some data elements form result that are data provider internal and should
125 // not be exposed to calling object.
126 foreach ($this->removeKeysFromFinalResultArray as $key) {
127 unset($result[$key]);
128 }
129
130 return $result;
131 }
132
133 /**
134 * @return array
135 */
136 protected function initializeResultArray()
137 {
138 return [
139 // Either "edit" or "new"
140 'command' => '',
141 // Table name of the handled row
142 'tableName' => '',
143 // Forced integer of otherwise not changed uid of the record, meaning of value depends on context (new / edit)
144 // * If $command is "edit"
145 // ** $vanillaUid is a positive integer > 0 pointing to the record in the table
146 // * If $command is "new":
147 // ** If $vanillaUid > 0, it is the uid of a page the record should be added at
148 // ** If $vanillaUid < 0, it is the uid of a record in the same table after which the new record should be added
149 // ** If $vanillaUid = 0, a new record is added on page 0
150 'vanillaUid' => 0,
151 // Url to return to
152 'returnUrl' => null,
153 // Title of the handled record.
154 'recordTitle' => '',
155 // Parent page record is either the full row of the parent page the record is located at or should
156 // be added to, or it is NULL, if a record is added or edited below the root page node.
157 'parentPageRow' => null,
158 // If a translated page is handled, the page row of the default language (the page against all page checks
159 // are made) is set here
160 'defaultLanguagePageRow' => null,
161 // Holds the "neighbor" row if incoming vanillaUid is negative and record creation is relative to a row of the same table.
162 'neighborRow' => null,
163 // For "new" this is the fully initialized row with defaults
164 // The database row. For "edit" fixVersioningPid() was applied already.
165 // @todo: rename to valueStructure or handledData or similar
166 'databaseRow' => [],
167 // The "effective" page uid we're working on. This is the uid of a page if a page is edited, or the uid
168 // of the parent page if a page or other record is added, or 0 if a record is added or edited below root node.
169 'effectivePid' => 0,
170 // Rootline of page the record that is handled is located at as created by BackendUtility::BEgetRootline()
171 'rootline' => [],
172 // The resolved SiteInterface object of the page or page given record is located on.
173 'site' => null,
174 // For "edit", this is the permission bitmask of the page that is edited, or of the page a record is located at
175 // For "new", this is the permission bitmask of the page the record is added to
176 // @todo: Remove if not needed on a lower level
177 'userPermissionOnPage' => 0,
178 // Full user TsConfig
179 'userTsConfig' => [],
180 // Full page TSConfig of the page that is edited or of the parent page if a record is added.
181 // This includes any defaultPageTSconfig and is merged with user TsConfig page. section. After type
182 // of handled record was determined, record type specific settings [TCEFORM.][tableName.][field.][types.][type.]
183 // are merged into [TCEFORM.][tableName.][field.]. Array keys still contain the concatenation dots.
184 'pageTsConfig' => [],
185 // List of available system languages. Array key is the system language uid, value array
186 // contains details of the record, with iso code resolved. Key is the sys_language_uid uid.
187 'systemLanguageRows' => [],
188 // If the page that is handled has "page_language_overlay" records (page has localizations in
189 // different languages), then this array holds those rows.
190 'pageLanguageOverlayRows' => [],
191 // If the handled row is a localized row, this entry hold the default language row array
192 'defaultLanguageRow' => null,
193 // If the handled row is a localized row and $TCA[<tableName>]['ctrl']['translationSource'] is configured,
194 // This entry holds the row of the language source record.
195 'sourceLanguageRow' => null,
196 // If the handled row is a localized row and a transOrigDiffSourceField is defined, this
197 // is the unserialized version of it. The diff source field is basically a shadow version
198 // of the default language record at the time when the language overlay record was created.
199 // This is used later to compare the default record with this content to show a "diff" if
200 // the default language record changed meanwhile.
201 'defaultLanguageDiffRow' => null,
202 // With userTS options.additionalPreviewLanguages set, field values of additional languages
203 // can be shown. This array holds those additional language records, Array key is sys_language_uid.
204 'additionalLanguageRows' => [],
205 // The tca record type value of the record. Forced to string, there can be "named" type values.
206 'recordTypeValue' => '',
207 // TCA of table with processed fields. After processing, this array contains merged and resolved
208 // array data, items were resolved, only used types are set, renderTypes are set.
209 'processedTca' => [],
210 // List of columns to be processed by data provider. Array value is the column name.
211 'columnsToProcess' => [],
212 // If set to TRUE, no wizards are calculated and rendered later
213 'disabledWizards' => false,
214
215 // Flex form field data handling is done in a separated FormDataCompiler instance. The full databaseRow
216 // of the record this flex form is embedded in is transferred in case features like single fields
217 // itemsProcFunc need to have this data at hand to do their job.
218 'flexParentDatabaseRow' => [],
219 // If not empty, it tells the TcaFlexProcess data provider to not calculate existing flex fields and
220 // existing flex container sections, but to instead prepare field values and the data structure TCA
221 // for a new container section. This is used by FormFlexAjaxController, the array contains details
222 // which container of which flex field should be created.
223 'flexSectionContainerPreparation' => [],
224
225 // If true, TcaSelectTreeItems data provider will compile tree items. This is false by default since
226 // on opening a record items are not calculated but are fetch in an ajax request, see FormSelectTreeAjaxController.
227 'selectTreeCompileItems' => false,
228
229 // BackendUser->uc['inlineView'] - This array holds status of expand / collapsed inline items
230 // This array is "flat", an inline structure with parent uid 1 having firstChild uid 2 having secondChild uid 3
231 // firstChild and secondChild are not nested. If a uid is set it means "record is expanded", example:
232 // 'parent' => [
233 // 1 => [
234 // 'firstChild' => [ 2 ], // record 2 of firstChild table is open in inline context to parent 1
235 // 'secondChild' => [ 3 ], // record 3 of secondChild table is open in inline context to parent 1
236 // ],
237 // ]
238 'inlineExpandCollapseStateArray' => [],
239 // The "entry" pid for inline records. Nested inline records can potentially hang around on different
240 // pid's, but the entry pid is needed for AJAX calls, so that they would know where the action takes
241 // place on the page structure.
242 'inlineFirstPid' => null,
243 // The "config" section of an inline parent, prepared and sanitized by TcaInlineConfiguration provider
244 'inlineParentConfig' => [],
245 // Flag that is enabled if a records is child of an inline parent
246 'isInlineChild' => false,
247 // Flag if an inline child is expanded so that additional fields need to be rendered
248 'isInlineChildExpanded' => false,
249 // Flag if the inline is in an ajax context that wants to expand the element
250 'isInlineAjaxOpeningContext' => false,
251 // Uid of the direct parent of the inline element. Handled as string since it may be a "NEW123" string
252 'inlineParentUid' => '',
253 // Table name of the direct parent of the inline element
254 'inlineParentTableName' => '',
255 // Field name of the direct parent of the inline element
256 'inlineParentFieldName' => '',
257 // Uid of the top most parent element. Handled as string since it may be a "NEW123" string
258 'inlineTopMostParentUid' => '',
259 // Table name of the top most parent element
260 'inlineTopMostParentTableName' => '',
261 // Field name of the top most parent element
262 'inlineTopMostParentFieldName' => '',
263
264 // If is on symmetric side of an inline child parent reference.
265 // symmetric side can be achieved in case of an mm relation to the same table. If record A has a relation
266 // to record B, the symmetric side is set in case that record B gets edited.
267 // Record A (table1) <=> mm <=> Record B (table1)
268 'isOnSymmetricSide' => false,
269
270 // Uid of a "child-child" if a new record of an intermediate table is compiled to an existing child. This
271 // happens if foreign_selector in parent inline config is set. It will be used by default database row
272 // data providers to set this as value for the foreign_selector field on the intermediate table. One use
273 // case is FAL, where for instance a tt_content parent adds relation to an existing sys_file record and
274 // should set the uid of the existing sys_file record as uid_local - the foreign_selector of this inline
275 // configuration - of the new intermediate sys_file_reference record. Data provider that are called later
276 // will then use this relation to resolve for instance input placeholder relation values.
277 'inlineChildChildUid' => null,
278 // Inline scenario: A localized parent record is handled, so inline parents can have localized children.
279 // This value is set to TRUE if this array represents a default language
280 // child record that was not yet localized.
281 'isInlineDefaultLanguageRecordInLocalizedParentContext' => false,
282 // If set, inline children will be resolved. This is set to FALSE in inline ajax context where new children
283 // are created and existing children don't matter much.
284 'inlineResolveExistingChildren' => true,
285 // @todo - for input placeholder inline to suppress an infinite loop, this *may* become obsolete if
286 // @todo compilation of certain fields is possible
287 'inlineCompileExistingChildren' => true,
288
289 // @todo: keys below must be handled / further defined
290 'elementBaseName' => '',
291 'tabAndInlineStack' => [],
292 'inlineData' => [],
293 'inlineStructure' => [],
294
295 // This array of fields will be set as hidden-fields instead of rendered normally!
296 // This is used by EditDocumentController to force some field values if set as "overrideVals" in _GP
297 'overrideValues' => [],
298 // Default values for fields. This is for example used in DatabaseRowInitializeNew data provider to set
299 // fields to specific values if new records are created. Values are often carried around as "defVals" GET
300 // parameters and hand over by controllers to FormEngine using this array. Array structure is
301 // ['aTableName']['aFieldName'] = 'aValue'.
302 'defaultValues' => [],
303
304 // This array must NOT be set / manipulated by data providers but is instead used by the render part
305 // of FormEngine to add runtime data. Containers and elements add data here which is given to
306 // sub-containers, elements, controls and wizards.
307 'renderData' => [],
308
309 // A place for non-core, additional, custom data providers to add data. If a data provider needs to add
310 // additional data to the data array that doesn't fit elsewhere, it can place it here to use it in the
311 // render part again. Data in here should be namespaced in a way that it does not collide with other
312 // data providers adding further data here. Using the extension key as array key could be a good idea.
313 'customData' => [],
314 ];
315 }
316 }