[TASK] Remove comments for revised in TYPO3 3.6
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Form / DataPreprocessor.php
1 <?php
2 namespace TYPO3\CMS\Backend\Form;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 1999-2013 Kasper Skårhøj (kasperYYYY@typo3.com)
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the textfile GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29
30 use TYPO3\CMS\Backend\Utility\BackendUtility;
31 use TYPO3\CMS\Core\Utility\GeneralUtility;
32
33 /**
34 * Class for getting and transforming data for display in backend forms (TCEforms)
35 *
36 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
37 */
38 class DataPreprocessor {
39
40 // External, static:
41 // If set, the records requested are locked.
42 /**
43 * @todo Define visibility
44 */
45 public $lockRecords = 0;
46
47 // Is set externally if RTE is disabled.
48 /**
49 * @todo Define visibility
50 */
51 public $disableRTE = 0;
52
53 // If the pid in the command is 'prev' then $prevPageID is used as pid for the record. This is used to attach new records to other previous records eg. new pages.
54 /**
55 * @todo Define visibility
56 */
57 public $prevPageID = '';
58
59 // Can be set with an array of default values for tables. First key is table name, second level keys are field names. Originally this was a GLOBAL array used internally.
60 /**
61 * @todo Define visibility
62 */
63 public $defVals = array();
64
65 // If set, the processed data is overlaid the raw record.
66 /**
67 * @todo Define visibility
68 */
69 public $addRawData = FALSE;
70
71 // Internal, dynamic
72 // Used to register, which items are already loaded!!
73 /**
74 * @todo Define visibility
75 */
76 public $regTableItems = array();
77
78 // This stores the record data of the loaded records
79 /**
80 * @todo Define visibility
81 */
82 public $regTableItems_data = array();
83
84 // Contains loadModules object, if used. (for reuse internally)
85 /**
86 * @todo Define visibility
87 */
88 public $loadModules = '';
89
90 /***********************************************
91 *
92 * Getting record content, ready for display in TCEforms
93 *
94 ***********************************************/
95 /**
96 * A function which can be used for load a batch of records from $table into internal memory of this object.
97 * The function is also used to produce proper default data for new records
98 * Ultimately the function will call renderRecord()
99 *
100 * @param string $table Table name, must be found in $GLOBALS['TCA']
101 * @param string $idList Comma list of id values. If $idList is "prev" then the value from $this->prevPageID is used. NOTICE: If $operation is "new", then negative ids are meant to point to a "previous" record and positive ids are PID values for new records. Otherwise (for existing records that is) it is straight forward table/id pairs.
102 * @param string $operation If "new", then a record with default data is returned. Further, the $id values are meant to be PID values (or if negative, pointing to a previous record). If NOT new, then the table/ids are just pointing to an existing record!
103 * @return void
104 * @see renderRecord()
105 * @todo Define visibility
106 */
107 public function fetchRecord($table, $idList, $operation) {
108 if ((string) $idList == 'prev') {
109 $idList = $this->prevPageID;
110 }
111 if ($GLOBALS['TCA'][$table]) {
112 // For each ID value (integer) we
113 $ids = GeneralUtility::trimExplode(',', $idList, 1);
114 foreach ($ids as $id) {
115 // If ID is not blank:
116 if (strcmp($id, '')) {
117 // For new records to be created, find default values:
118 if ($operation == 'new') {
119 // Default values:
120 // Used to store default values as found here:
121 $newRow = array();
122 // Default values as set in userTS:
123 $TCAdefaultOverride = $GLOBALS['BE_USER']->getTSConfigProp('TCAdefaults');
124 if (is_array($TCAdefaultOverride[$table . '.'])) {
125 foreach ($TCAdefaultOverride[$table . '.'] as $theF => $theV) {
126 if (isset($GLOBALS['TCA'][$table]['columns'][$theF])) {
127 $newRow[$theF] = $theV;
128 }
129 }
130 }
131 if ($id < 0) {
132 $record = BackendUtility::getRecord($table, abs($id), 'pid');
133 $pid = $record['pid'];
134 unset($record);
135 } else {
136 $pid = intval($id);
137 }
138 $pageTS = BackendUtility::getPagesTSconfig($pid);
139 if (isset($pageTS['TCAdefaults.'])) {
140 $TCAPageTSOverride = $pageTS['TCAdefaults.'];
141 if (is_array($TCAPageTSOverride[$table . '.'])) {
142 foreach ($TCAPageTSOverride[$table . '.'] as $theF => $theV) {
143 if (isset($GLOBALS['TCA'][$table]['columns'][$theF])) {
144 $newRow[$theF] = $theV;
145 }
146 }
147 }
148 }
149 // Default values as submitted:
150 if (is_array($this->defVals[$table])) {
151 foreach ($this->defVals[$table] as $theF => $theV) {
152 if (isset($GLOBALS['TCA'][$table]['columns'][$theF])) {
153 $newRow[$theF] = $theV;
154 }
155 }
156 }
157 // Fetch default values if a previous record exists
158 if ($id < 0 && $GLOBALS['TCA'][$table]['ctrl']['useColumnsForDefaultValues']) {
159 // Fetches the previous record:
160 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $table, 'uid=' . abs($id) . BackendUtility::deleteClause($table));
161 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
162 // Gets the list of fields to copy from the previous record.
163 $fArr = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$table]['ctrl']['useColumnsForDefaultValues'], 1);
164 foreach ($fArr as $theF) {
165 if (isset($GLOBALS['TCA'][$table]['columns'][$theF]) && !isset($newRow[$theF])) {
166 $newRow[$theF] = $row[$theF];
167 }
168 }
169 }
170 $GLOBALS['TYPO3_DB']->sql_free_result($res);
171 }
172 // Finally, call renderRecord:
173 $this->renderRecord($table, uniqid('NEW'), $id, $newRow);
174 } else {
175 $id = intval($id);
176 // Fetch database values
177 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $table, 'uid=' . intval($id) . BackendUtility::deleteClause($table));
178 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
179 BackendUtility::fixVersioningPid($table, $row);
180 $this->renderRecord($table, $id, $row['pid'], $row);
181 $contentTable = $GLOBALS['TYPO3_CONF_VARS']['SYS']['contentTable'];
182 $this->lockRecord($table, $id, $contentTable == $table ? $row['pid'] : 0);
183 }
184 $GLOBALS['TYPO3_DB']->sql_free_result($res);
185 }
186 }
187 }
188 }
189 }
190
191 /**
192 * This function performs processing on the input $row array and stores internally a corresponding array which contains processed values, ready to pass on to the TCEforms rendering in the frontend!
193 * The objective with this function is to prepare the content for handling in TCEforms.
194 * Default values from outside/TSconfig is added by fetchRecord(). In this function default values from TCA is used if a field is NOT defined in $row.
195 * The resulting, processed row is stored in $this->regTableItems_data[$uniqueItemRef], where $uniqueItemRef is "[tablename]_[id-value]"
196 *
197 * @param string $table The table name
198 * @param string $id The uid value of the record (integer). Can also be a string (NEW-something) if the record is a NEW record.
199 * @param integer $pid The pid integer. For existing records this is of course the row's "pid" field. For new records it can be either a page id (positive) or a pointer to another record from the SAME table (negative) after which the record should be inserted (or on same page)
200 * @param array $row The row of the current record. If NEW record, then it may be loaded with default values (by eg. fetchRecord()).
201 * @return void
202 * @see fetchRecord()
203 * @todo Define visibility
204 */
205 public function renderRecord($table, $id, $pid, $row) {
206 $dateTimeFormats = $GLOBALS['TYPO3_DB']->getDateTimeFormats($table);
207 foreach ($GLOBALS['TCA'][$table]['columns'] as $column => $config) {
208 if (isset($config['config']['dbType']) && GeneralUtility::inList('date,datetime', $config['config']['dbType'])) {
209 $emptyValue = $dateTimeFormats[$config['config']['dbType']]['empty'];
210 $row[$column] = !empty($row[$column]) && $row[$column] !== $emptyValue ? strtotime($row[$column]) : 0;
211 }
212 }
213 // Init:
214 $uniqueItemRef = $table . '_' . $id;
215 // Fetches the true PAGE TSconfig pid to use later, if needed. (Until now, only for the RTE, but later..., who knows?)
216 list($tscPID) = BackendUtility::getTSCpid($table, $id, $pid);
217 $TSconfig = BackendUtility::getTCEFORM_TSconfig($table, array_merge($row, array('uid' => $id, 'pid' => $pid)));
218 // If the record has not already been loaded (in which case we DON'T do it again)...
219 if (!$this->regTableItems[$uniqueItemRef]) {
220 $this->regTableItems[$uniqueItemRef] = 1;
221 // set "loaded" flag.
222 // If the table is pages, set the previous page id internally.
223 if ($table == 'pages') {
224 $this->prevPageID = $id;
225 }
226 $this->regTableItems_data[$uniqueItemRef] = $this->renderRecordRaw($table, $id, $pid, $row, $TSconfig, $tscPID);
227 // Merges the processed array on-top of the raw one - this is done because some things in TCEforms may need access to other fields than those in the columns configuration!
228 if ($this->addRawData && is_array($row) && is_array($this->regTableItems_data[$uniqueItemRef])) {
229 $this->regTableItems_data[$uniqueItemRef] = array_merge($row, $this->regTableItems_data[$uniqueItemRef]);
230 }
231 }
232 }
233
234 /**
235 * This function performs processing on the input $row array and stores internally a corresponding array which contains processed values, ready to pass on to the TCEforms rendering in the frontend!
236 * The objective with this function is to prepare the content for handling in TCEforms.
237 * In opposite to renderRecord() this function do not prepare things like fetching TSconfig and others.
238 * The resulting, processed row will be returned.
239 *
240 * @param string $table The table name
241 * @param string $id The uid value of the record (integer). Can also be a string (NEW-something) if the record is a NEW record.
242 * @param integer $pid The pid integer. For existing records this is of course the row's "pid" field. For new records it can be either a page id (positive) or a pointer to another record from the SAME table (negative) after which the record should be inserted (or on same page)
243 * @param array $row The row of the current record. If NEW record, then it may be loaded with default values (by eg. fetchRecord()).
244 * @param array $TSconfig Tsconfig array
245 * @param integer $tscPID PAGE TSconfig pid
246 * @return array Processed record data
247 * @see renderRecord()
248 * @todo Define visibility
249 */
250 public function renderRecordRaw($table, $id, $pid, $row, $TSconfig = '', $tscPID = 0) {
251 if (!is_array($TSconfig)) {
252 $TSconfig = array();
253 }
254 // Create blank accumulation array:
255 $totalRecordContent = array();
256 // Traverse the configured columns for the table (TCA):
257 // For each column configured, we will perform processing if needed based on the type (eg. for "group" and "select" types this is needed)
258 $copyOfColumns = $GLOBALS['TCA'][$table]['columns'];
259 foreach ($copyOfColumns as $field => $fieldConfig) {
260 // Set $data variable for the field, either inputted value from $row - or if not found, the default value as defined in the "config" array
261 if (isset($row[$field])) {
262 $data = (string) $row[$field];
263 } elseif (array_key_exists($field, $row) && !empty($fieldConfig['config']['eval']) && GeneralUtility::inList($fieldConfig['config']['eval'], 'null')) {
264 $data = NULL;
265 } else {
266 $data = (string) $fieldConfig['config']['default'];
267 }
268 $data = $this->renderRecord_SW($data, $fieldConfig, $TSconfig, $table, $row, $field);
269 $totalRecordContent[$field] = $data;
270 }
271 // Further processing may apply for each field in the record depending on the settings in the "types" configuration (the list of fields to currently display for a record in TCEforms).
272 // For instance this could be processing instructions for the Rich Text Editor.
273 $types_fieldConfig = BackendUtility::getTCAtypes($table, $totalRecordContent);
274 if (is_array($types_fieldConfig)) {
275 $totalRecordContent = $this->renderRecord_typesProc($totalRecordContent, $types_fieldConfig, $tscPID, $table, $pid);
276 }
277 // Register items, mostly for external use (overriding the regItem() function)
278 foreach ($totalRecordContent as $field => $data) {
279 $this->regItem($table, $id, $field, $data);
280 }
281 // Finally, store the result:
282 reset($totalRecordContent);
283 return $totalRecordContent;
284 }
285
286 /**
287 * Function with the switch() construct which triggers functions for processing of the data value depending on the TCA-config field type.
288 *
289 * @param string $data Value to process
290 * @param array $fieldConfig TCA/columns array for field (independant of TCA for flexforms - coming from XML then)
291 * @param array $TSconfig TSconfig (blank for flexforms for now)
292 * @param string $table Table name
293 * @param array $row The row array, always of the real record (also for flexforms)
294 * @param string $field The field (empty for flexforms!)
295 * @return string Modified $value
296 * @todo Define visibility
297 */
298 public function renderRecord_SW($data, $fieldConfig, $TSconfig, $table, $row, $field) {
299 switch ((string) $fieldConfig['config']['type']) {
300 case 'group':
301 $data = $this->renderRecord_groupProc($data, $fieldConfig, $TSconfig, $table, $row, $field);
302 break;
303 case 'select':
304 $data = $this->renderRecord_selectProc($data, $fieldConfig, $TSconfig, $table, $row, $field);
305 break;
306 case 'flex':
307 $data = $this->renderRecord_flexProc($data, $fieldConfig, $TSconfig, $table, $row, $field);
308 break;
309 case 'inline':
310 $data = $this->renderRecord_inlineProc($data, $fieldConfig, $TSconfig, $table, $row, $field);
311 break;
312 }
313 return $data;
314 }
315
316 /**
317 * Processing of the data value in case the field type is "group"
318 *
319 * @param string $data The field value
320 * @param array $fieldConfig TCA field config
321 * @param array $TSconfig TCEform TSconfig for the record
322 * @param string $table Table name
323 * @param array $row The row
324 * @param string $field Field name
325 * @return string The processed input field value ($data)
326 * @access private
327 * @see renderRecord()
328 * @todo Define visibility
329 */
330 public function renderRecord_groupProc($data, $fieldConfig, $TSconfig, $table, $row, $field) {
331 switch ($fieldConfig['config']['internal_type']) {
332 case 'file':
333 // Init array used to accumulate the files:
334 $dataAcc = array();
335 // Now, load the files into the $dataAcc array, whether stored by MM or as a list of filenames:
336 if ($fieldConfig['config']['MM']) {
337 $loadDB = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Database\\RelationHandler');
338 $loadDB->start('', 'files', $fieldConfig['config']['MM'], $row['uid']);
339 // Setting dummy startup
340 foreach ($loadDB->itemArray as $value) {
341 if ($value['id']) {
342 $dataAcc[] = rawurlencode($value['id']) . '|' . rawurlencode($value['id']);
343 }
344 }
345 } else {
346 $fileList = GeneralUtility::trimExplode(',', $data, 1);
347 foreach ($fileList as $value) {
348 if ($value) {
349 $dataAcc[] = rawurlencode($value) . '|' . rawurlencode($value);
350 }
351 }
352 }
353 // Implode the accumulation array to a comma separated string:
354 $data = implode(',', $dataAcc);
355 break;
356 case 'db':
357 $loadDB = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Database\\RelationHandler');
358 /** @var $loadDB \TYPO3\CMS\Core\Database\RelationHandler */
359 $loadDB->start($data, $fieldConfig['config']['allowed'], $fieldConfig['config']['MM'], $row['uid'], $table, $fieldConfig['config']);
360 $loadDB->getFromDB();
361 $data = $loadDB->readyForInterface();
362 break;
363 }
364 return $data;
365 }
366
367 /**
368 * Processing of the data value in case the field type is "select"
369 *
370 * @param string $data The field value
371 * @param array $fieldConfig TCA field config
372 * @param array $TSconfig TCEform TSconfig for the record
373 * @param string $table Table name
374 * @param array $row The row
375 * @param string $field Field name
376 * @return string The processed input field value ($data)
377 * @access private
378 * @see renderRecord()
379 * @todo Define visibility
380 */
381 public function renderRecord_selectProc($data, $fieldConfig, $TSconfig, $table, $row, $field) {
382 // Initialize:
383 // Current data set.
384 $elements = GeneralUtility::trimExplode(',', $data, 1);
385 // New data set, ready for interface (list of values, rawurlencoded)
386 $dataAcc = array();
387 // For list selectors (multi-value):
388 if (intval($fieldConfig['config']['maxitems']) > 1) {
389 // Add regular elements:
390 if (!is_array($fieldConfig['config']['items'])) {
391 $fieldConfig['config']['items'] = array();
392 }
393 $fieldConfig['config']['items'] = $this->procesItemArray($fieldConfig['config']['items'], $fieldConfig['config'], $TSconfig[$field], $table, $row, $field);
394 foreach ($fieldConfig['config']['items'] as $pvpv) {
395 foreach ($elements as $eKey => $value) {
396 if (!strcmp($value, $pvpv[1])) {
397 $dataAcc[$eKey] = rawurlencode($pvpv[1]) . '|' . rawurlencode($this->sL($pvpv[0]));
398 }
399 }
400 }
401 // Add "special"
402 if ($fieldConfig['config']['special']) {
403 $dataAcc = $this->selectAddSpecial($dataAcc, $elements, $fieldConfig['config']['special']);
404 }
405 // Add "foreign table" stuff:
406 if ($GLOBALS['TCA'][$fieldConfig['config']['foreign_table']]) {
407 $dataAcc = $this->selectAddForeign($dataAcc, $elements, $fieldConfig, $field, $TSconfig, $row, $table);
408 }
409 // Always keep the native order for display in interface:
410 ksort($dataAcc);
411 } else {
412 // Normal, <= 1 -> value without title on it
413 if ($GLOBALS['TCA'][$fieldConfig['config']['foreign_table']]) {
414 // Getting the data
415 $dataIds = $this->getDataIdList($elements, $fieldConfig, $row, $table);
416 if (!count($dataIds)) {
417 $dataIds = array(0);
418 }
419 $dataAcc[] = $dataIds[0];
420 } else {
421 $dataAcc[] = $elements[0];
422 }
423 }
424 return implode(',', $dataAcc);
425 }
426
427 /**
428 * Processing of the data value in case the field type is "flex"
429 * MUST NOT be called in case of already INSIDE a flexform!
430 *
431 * @param string $data The field value
432 * @param array $fieldConfig CA field config
433 * @param array $TSconfig TCEform TSconfig for the record
434 * @param string $table Table name
435 * @param array $row The row
436 * @param string $field Field name
437 * @return string The processed input field value ($data)
438 * @access private
439 * @see renderRecord()
440 * @todo Define visibility
441 */
442 public function renderRecord_flexProc($data, $fieldConfig, $TSconfig, $table, $row, $field) {
443 // Convert the XML data to PHP array:
444 $currentValueArray = GeneralUtility::xml2array($data);
445 if (is_array($currentValueArray)) {
446 // Get current value array:
447 $dataStructArray = BackendUtility::getFlexFormDS($fieldConfig['config'], $row, $table, $field);
448 // Manipulate Flexform DS via TSConfig and group access lists
449 if (is_array($dataStructArray)) {
450 $flexFormHelper = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Form\\FlexFormsHelper');
451 $dataStructArray = $flexFormHelper->modifyFlexFormDS($dataStructArray, $table, $field, $row, $fieldConfig);
452 unset($flexFormHelper);
453 }
454 if (is_array($dataStructArray)) {
455 $currentValueArray['data'] = $this->renderRecord_flexProc_procInData($currentValueArray['data'], $dataStructArray, array($data, $fieldConfig, $TSconfig, $table, $row, $field));
456 $flexObj = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Configuration\\FlexForm\\FlexFormTools');
457 $data = $flexObj->flexArray2Xml($currentValueArray, TRUE);
458 }
459 }
460 return $data;
461 }
462
463 /**
464 * Processing of the content in $totalRecordcontent based on settings in the types-configuration
465 *
466 * @param array $totalRecordContent The array of values which has been processed according to their type (eg. "group" or "select")
467 * @param array $types_fieldConfig The "types" configuration for the current display of fields.
468 * @param integer $tscPID PAGE TSconfig PID
469 * @param string $table Table name
470 * @param integer $pid PID value
471 * @return array The processed version of $totalRecordContent
472 * @access private
473 * @todo Define visibility
474 */
475 public function renderRecord_typesProc($totalRecordContent, $types_fieldConfig, $tscPID, $table, $pid) {
476 foreach ($types_fieldConfig as $vconf) {
477 // Find file to write to, if configured:
478 $eFile = \TYPO3\CMS\Core\Html\RteHtmlParser::evalWriteFile($vconf['spec']['static_write'], $totalRecordContent);
479 // Write file configuration:
480 if (is_array($eFile)) {
481 if ($eFile['loadFromFileField'] && $totalRecordContent[$eFile['loadFromFileField']]) {
482 // Read the external file, and insert the content between the ###TYPO3_STATICFILE_EDIT### markers:
483 $SW_fileContent = GeneralUtility::getUrl($eFile['editFile']);
484 $parseHTML = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Html\\RteHtmlParser');
485 $parseHTML->init('', '');
486 $totalRecordContent[$vconf['field']] = $parseHTML->getSubpart($SW_fileContent, $eFile['markerField'] && trim($totalRecordContent[$eFile['markerField']]) ? trim($totalRecordContent[$eFile['markerField']]) : '###TYPO3_STATICFILE_EDIT###');
487 }
488 }
489 }
490 return $totalRecordContent;
491 }
492
493 /**
494 * Processing of the data value in case the field type is "inline"
495 * In some parts nearly the same as type "select"
496 *
497 * @param string $data The field value
498 * @param array $fieldConfig TCA field config
499 * @param array $TSconfig TCEform TSconfig for the record
500 * @param string $table Table name
501 * @param array $row The row
502 * @param string $field Field name
503 * @return string The processed input field value ($data)
504 * @access private
505 * @see renderRecord()
506 * @todo Define visibility
507 */
508 public function renderRecord_inlineProc($data, $fieldConfig, $TSconfig, $table, $row, $field) {
509 // Initialize:
510 // Current data set.
511 $elements = GeneralUtility::trimExplode(',', $data);
512 // New data set, ready for interface (list of values, rawurlencoded)
513 $dataAcc = array();
514 // At this point all records that CAN be selected is found in $recordList
515 // Now, get the data from loadDBgroup based on the input list of values.
516 $dataIds = $this->getDataIdList($elements, $fieldConfig, $row, $table);
517 // After this we can traverse the loadDBgroup values and match values with the list of possible values in $recordList:
518 foreach ($dataIds as $theId) {
519 if ($fieldConfig['config']['MM'] || $fieldConfig['config']['foreign_field']) {
520 $dataAcc[] = $theId;
521 } else {
522 foreach ($elements as $eKey => $value) {
523 if (!strcmp($theId, $value)) {
524 $dataAcc[$eKey] = $theId;
525 }
526 }
527 }
528 }
529 return implode(',', $dataAcc);
530 }
531
532 /***********************************************
533 *
534 * FlexForm processing functions
535 *
536 ***********************************************/
537 /**
538 * Function traversing sheets/languages for flex form data structures
539 *
540 * @param array $dataPart Data array
541 * @param array $dataStructArray Data Structure array
542 * @param array $pParams Various parameters to pass-through
543 * @return array Modified $dataPart array.
544 * @access private
545 * @see \TYPO3\CMS\Core\DataHandling\DataHandler::checkValue_flex_procInData(), renderRecord_flexProc_procInData_travDS()
546 * @todo Define visibility
547 */
548 public function renderRecord_flexProc_procInData($dataPart, $dataStructArray, $pParams) {
549 if (is_array($dataPart)) {
550 foreach ($dataPart as $sKey => $sheetDef) {
551 list($dataStruct, $actualSheet) = GeneralUtility::resolveSheetDefInDS($dataStructArray, $sKey);
552 if (is_array($dataStruct) && $actualSheet == $sKey && is_array($sheetDef)) {
553 foreach ($sheetDef as $lKey => $lData) {
554 $this->renderRecord_flexProc_procInData_travDS($dataPart[$sKey][$lKey], $dataStruct['ROOT']['el'], $pParams);
555 }
556 }
557 }
558 }
559 return $dataPart;
560 }
561
562 /**
563 * Traverse data array / structure
564 *
565 * @param array $dataValues Data array passed by reference.
566 * @param array $DSelements Data structure
567 * @param array $pParams Various parameters pass-through.
568 * @return void
569 * @see \TYPO3\CMS\Core\DataHandling\DataHandler::checkValue_flex_procInData(), renderRecord_flexProc_procInData_travDS()
570 * @todo Define visibility
571 */
572 public function renderRecord_flexProc_procInData_travDS(&$dataValues, $DSelements, $pParams) {
573 if (is_array($DSelements)) {
574 // For each DS element:
575 foreach ($DSelements as $key => $dsConf) {
576 // Array/Section:
577 if ($DSelements[$key]['type'] == 'array') {
578 if (is_array($dataValues[$key]['el'])) {
579 if ($DSelements[$key]['section']) {
580 foreach ($dataValues[$key]['el'] as $ik => $el) {
581 if (is_array($el)) {
582 $theKey = key($el);
583 if (is_array($dataValues[$key]['el'][$ik][$theKey]['el'])) {
584 $this->renderRecord_flexProc_procInData_travDS($dataValues[$key]['el'][$ik][$theKey]['el'], $DSelements[$key]['el'][$theKey]['el'], $pParams);
585 }
586 }
587 }
588 } else {
589 if (!isset($dataValues[$key]['el'])) {
590 $dataValues[$key]['el'] = array();
591 }
592 $this->renderRecord_flexProc_procInData_travDS($dataValues[$key]['el'], $DSelements[$key]['el'], $pParams);
593 }
594 }
595 } else {
596 if (is_array($dsConf['TCEforms']['config']) && is_array($dataValues[$key])) {
597 foreach ($dataValues[$key] as $vKey => $data) {
598 // $data,$fieldConfig,$TSconfig,$table,$row,$field
599 list(, , $CVTSconfig, $CVtable, $CVrow, $CVfield) = $pParams;
600 // Set default value:
601 if (!isset($dataValues[$key][$vKey])) {
602 $dataValues[$key][$vKey] = $dsConf['TCEforms']['config']['default'];
603 }
604 // Process value:
605 $dataValues[$key][$vKey] = $this->renderRecord_SW($dataValues[$key][$vKey], $dsConf['TCEforms'], $CVTSconfig, $CVtable, $CVrow, '');
606 }
607 }
608 }
609 }
610 }
611 }
612
613 /***********************************************
614 *
615 * Selector box processing functions
616 *
617 ***********************************************/
618 /**
619 * Adding "special" types to the $dataAcc array of selector items
620 *
621 * @param array $dataAcc Array with numeric keys, containing values for the selector box, prepared for interface. We are going to add elements to this array as needed.
622 * @param array $elements The array of original elements - basically the field value exploded by ",
623 * @param string $specialKey The "special" key from the TCA config of the field. Determines the type of processing in here.
624 * @return array Modified $dataAcc array
625 * @access private
626 * @see renderRecord_selectProc()
627 * @todo Define visibility
628 */
629 public function selectAddSpecial($dataAcc, $elements, $specialKey) {
630 // Special select types:
631 switch ((string) $specialKey) {
632 case 'tables':
633 $tNames = array_keys($GLOBALS['TCA']);
634 foreach ($tNames as $tableName) {
635 foreach ($elements as $eKey => $value) {
636 if (!strcmp($tableName, $value)) {
637 $dataAcc[$eKey] = rawurlencode($value) . '|' . rawurlencode($this->sL($GLOBALS['TCA'][$value]['ctrl']['title']));
638 }
639 }
640 }
641 break;
642 case 'pagetypes':
643 $theTypes = $GLOBALS['TCA']['pages']['columns']['doktype']['config']['items'];
644 if (is_array($theTypes)) {
645 foreach ($theTypes as $theTypesArrays) {
646 foreach ($elements as $eKey => $value) {
647 if (!strcmp($theTypesArrays[1], $value)) {
648 $dataAcc[$eKey] = rawurlencode($value) . '|' . rawurlencode($this->sL($theTypesArrays[0]));
649 }
650 }
651 }
652 }
653 break;
654 case 'exclude':
655 $theExcludeFields = BackendUtility::getExcludeFields();
656 if (is_array($theExcludeFields)) {
657 foreach ($theExcludeFields as $theExcludeFieldsArrays) {
658 foreach ($elements as $eKey => $value) {
659 if (!strcmp($theExcludeFieldsArrays[1], $value)) {
660 $dataAcc[$eKey] = rawurlencode($value) . '|' . rawurlencode(rtrim($theExcludeFieldsArrays[0], ':'));
661 }
662 }
663 }
664 }
665 break;
666 case 'explicitValues':
667 $theTypes = BackendUtility::getExplicitAuthFieldValues();
668 foreach ($theTypes as $tableFieldKey => $theTypeArrays) {
669 if (is_array($theTypeArrays['items'])) {
670 foreach ($theTypeArrays['items'] as $itemValue => $itemContent) {
671 foreach ($elements as $eKey => $value) {
672 if (!strcmp(($tableFieldKey . ':' . $itemValue . ':' . $itemContent[0]), $value)) {
673 $dataAcc[$eKey] = rawurlencode($value) . '|' . rawurlencode(('[' . $itemContent[2] . '] ' . $itemContent[1]));
674 }
675 }
676 }
677 }
678 }
679 break;
680 case 'languages':
681 $theLangs = BackendUtility::getSystemLanguages();
682 foreach ($theLangs as $lCfg) {
683 foreach ($elements as $eKey => $value) {
684 if (!strcmp($lCfg[1], $value)) {
685 $dataAcc[$eKey] = rawurlencode($value) . '|' . rawurlencode($lCfg[0]);
686 }
687 }
688 }
689 break;
690 case 'custom':
691 $customOptions = $GLOBALS['TYPO3_CONF_VARS']['BE']['customPermOptions'];
692 if (is_array($customOptions)) {
693 foreach ($customOptions as $coKey => $coValue) {
694 if (is_array($coValue['items'])) {
695 // Traverse items:
696 foreach ($coValue['items'] as $itemKey => $itemCfg) {
697 foreach ($elements as $eKey => $value) {
698 if (!strcmp(($coKey . ':' . $itemKey), $value)) {
699 $dataAcc[$eKey] = rawurlencode($value) . '|' . rawurlencode($this->sL($itemCfg[0]));
700 }
701 }
702 }
703 }
704 }
705 }
706 break;
707 case 'modListGroup':
708
709 case 'modListUser':
710 if (!$this->loadModules) {
711 $this->loadModules = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Module\\ModuleLoader');
712 $this->loadModules->load($GLOBALS['TBE_MODULES']);
713 }
714 $modList = $specialKey == 'modListUser' ? $this->loadModules->modListUser : $this->loadModules->modListGroup;
715 foreach ($modList as $theModName) {
716 foreach ($elements as $eKey => $value) {
717 $label = '';
718 // Add label for main module:
719 $pp = explode('_', $value);
720 if (count($pp) > 1) {
721 $label .= $GLOBALS['LANG']->moduleLabels['tabs'][($pp[0] . '_tab')] . '>';
722 }
723 // Add modules own label now:
724 $label .= $GLOBALS['LANG']->moduleLabels['tabs'][$value . '_tab'];
725 if (!strcmp($theModName, $value)) {
726 $dataAcc[$eKey] = rawurlencode($value) . '|' . rawurlencode($label);
727 }
728 }
729 }
730 break;
731 }
732 return $dataAcc;
733 }
734
735 /**
736 * Adds the foreign record elements to $dataAcc, if any
737 *
738 * @param array $dataAcc Array with numeric keys, containing values for the selector box, prepared for interface. We are going to add elements to this array as needed.
739 * @param array $elements The array of original elements - basically the field value exploded by ",
740 * @param array $fieldConfig Field configuration from TCA
741 * @param string $field The field name
742 * @param array $TSconfig TSconfig for the record
743 * @param array $row The record
744 * @param array $table The current table
745 * @return array Modified $dataAcc array
746 * @access private
747 * @see renderRecord_selectProc()
748 * @todo Define visibility
749 */
750 public function selectAddForeign($dataAcc, $elements, $fieldConfig, $field, $TSconfig, $row, $table) {
751 // Init:
752 $recordList = array();
753 // Foreign_table
754 $subres = BackendUtility::exec_foreign_table_where_query($fieldConfig, $field, $TSconfig);
755 while ($subrow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($subres)) {
756 $recordList[$subrow['uid']] = BackendUtility::getRecordTitle($fieldConfig['config']['foreign_table'], $subrow);
757 }
758 $GLOBALS['TYPO3_DB']->sql_free_result($subres);
759 // neg_foreign_table
760 if (is_array($GLOBALS['TCA'][$fieldConfig['config']['neg_foreign_table']])) {
761 $subres = BackendUtility::exec_foreign_table_where_query($fieldConfig, $field, $TSconfig, 'neg_');
762 while ($subrow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($subres)) {
763 $recordList[-$subrow['uid']] = BackendUtility::getRecordTitle($fieldConfig['config']['neg_foreign_table'], $subrow);
764 }
765 $GLOBALS['TYPO3_DB']->sql_free_result($subres);
766 }
767 // At this point all records that CAN be selected is found in $recordList
768 // Now, get the data from loadDBgroup based on the input list of values.
769 $dataIds = $this->getDataIdList($elements, $fieldConfig, $row, $table);
770 if ($fieldConfig['config']['MM']) {
771 $dataAcc = array();
772 }
773 // Reset, if MM (which cannot bear anything but real relations!)
774 // After this we can traverse the loadDBgroup values and match values with the list of possible values in $recordList:
775 foreach ($dataIds as $theId) {
776 if (isset($recordList[$theId])) {
777 $lPrefix = $this->sL($fieldConfig['config'][($theId > 0 ? '' : 'neg_') . 'foreign_table_prefix']);
778 if ($fieldConfig['config']['MM'] || $fieldConfig['config']['foreign_field']) {
779 $dataAcc[] = rawurlencode($theId) . '|' . rawurlencode(GeneralUtility::fixed_lgd_cs(($lPrefix . strip_tags($recordList[$theId])), $GLOBALS['BE_USER']->uc['titleLen']));
780 } else {
781 foreach ($elements as $eKey => $value) {
782 if (!strcmp($theId, $value)) {
783 $dataAcc[$eKey] = rawurlencode($theId) . '|' . rawurlencode(GeneralUtility::fixed_lgd_cs(($lPrefix . strip_tags($recordList[$theId])), $GLOBALS['BE_USER']->uc['titleLen']));
784 }
785 }
786 }
787 }
788 }
789 return $dataAcc;
790 }
791
792 /**
793 * Returning the id-list processed by loadDBgroup for the foreign tables.
794 *
795 * @param array $elements The array of original elements - basically the field value exploded by ",
796 * @param array $fieldConfig Field configuration from TCA
797 * @param array $row The data array, currently. Used to set the "local_uid" for selecting MM relation records.
798 * @param string $table Current table name. passed on to \TYPO3\CMS\Core\Database\RelationHandler
799 * @return array An array with ids of the records from the input elements array.
800 * @access private
801 * @todo Define visibility
802 */
803 public function getDataIdList($elements, $fieldConfig, $row, $table) {
804 $loadDB = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Database\\RelationHandler');
805 $loadDB->registerNonTableValues = $fieldConfig['config']['allowNonIdValues'] ? 1 : 0;
806 $loadDB->start(implode(',', $elements), $fieldConfig['config']['foreign_table'] . ',' . $fieldConfig['config']['neg_foreign_table'], $fieldConfig['config']['MM'], $row['uid'], $table, $fieldConfig['config']);
807 $idList = $loadDB->convertPosNeg($loadDB->getValueArray(), $fieldConfig['config']['foreign_table'], $fieldConfig['config']['neg_foreign_table']);
808 return $idList;
809 }
810
811 /**
812 * Processing of selector box items. This includes the automated adding of elements plus user-function processing.
813 *
814 * @param array The elements to process
815 * @param array TCA/columns configuration
816 * @param array TSconfig for the field
817 * @param string The table name
818 * @param array The current row
819 * @param string The field name
820 * @return array The modified input $selItems array
821 * @access private
822 * @see renderRecord_selectProc()
823 * @todo Define visibility
824 */
825 public function procesItemArray($selItems, $config, $fieldTSConfig, $table, $row, $field) {
826 $selItems = $this->addItems($selItems, $fieldTSConfig['addItems.']);
827 if ($config['itemsProcFunc']) {
828 $selItems = $this->procItems($selItems, $fieldTSConfig['itemsProcFunc.'], $config, $table, $row, $field);
829 }
830 return $selItems;
831 }
832
833 /**
834 * Adding items from $iArray to $items array
835 *
836 * @param array $items The array of selector box items to which key(value) / value(label) pairs from $iArray will be added.
837 * @param array $iArray The array of elements to add. The keys will become values. The value will become the label.
838 * @return array The modified input $items array
839 * @access private
840 * @see procesItemArray()
841 * @todo Define visibility
842 */
843 public function addItems($items, $iArray) {
844 if (is_array($iArray)) {
845 foreach ($iArray as $value => $label) {
846 $items[] = array($label, $value);
847 }
848 }
849 return $items;
850 }
851
852 /**
853 * User processing of a selector box array of values.
854 *
855 * @param array $items The array of selector box items
856 * @param array $itemsProcFuncTSconfig TSconfig for the fields itemProcFunc
857 * @param array $config TCA/columns configuration
858 * @param string $table The table name
859 * @param array $row The current row
860 * @param string $field The field name
861 * @return array The modified input $items array
862 * @access private
863 * @see procesItemArray()
864 * @todo Define visibility
865 */
866 public function procItems($items, $itemsProcFuncTSconfig, $config, $table, $row, $field) {
867 $params = array();
868 $params['items'] = &$items;
869 $params['config'] = $config;
870 $params['TSconfig'] = $itemsProcFuncTSconfig;
871 $params['table'] = $table;
872 $params['row'] = $row;
873 $params['field'] = $field;
874 GeneralUtility::callUserFunction($config['itemsProcFunc'], $params, $this);
875 return $items;
876 }
877
878 /***********************************************
879 *
880 * Helper functions
881 *
882 ***********************************************/
883 /**
884 * Sets the lock for a record from table/id, IF $this->lockRecords is set!
885 *
886 * @param string $table The table name
887 * @param integer $id The id of the record
888 * @param integer $pid The pid of the record
889 * @return void
890 * @todo Define visibility
891 */
892 public function lockRecord($table, $id, $pid = 0) {
893 if ($this->lockRecords) {
894 BackendUtility::lockRecords($table, $id, $pid);
895 }
896 }
897
898 /**
899 * Dummy function, can be used to "register" records. Used by eg. the "show_item" script.
900 *
901 * @param string $table Table name
902 * @param integer $id Record id
903 * @param string $field Field name
904 * @param string $content Field content.
905 * @return void
906 * @access private
907 * @see renderRecord()
908 * @todo Define visibility
909 */
910 public function regItem($table, $id, $field, $content) {
911
912 }
913
914 /**
915 * Local wrapper function for LANG->sL (returning language labels)
916 *
917 * @param string Language label key
918 * @return string Localized label value.
919 * @access private
920 * @todo Define visibility
921 */
922 public function sL($in) {
923 return $GLOBALS['LANG']->sL($in);
924 }
925
926 }
927
928
929 ?>