PageRenderTime 406ms CodeModel.GetById 181ms app.highlight 65ms RepoModel.GetById 66ms app.codeStats 4ms

/t3lib/class.t3lib_tcemain.php

https://bitbucket.org/linxpinx/mercurial
PHP | 7828 lines | 4516 code | 1002 blank | 2310 comment | 1277 complexity | e84bb17658713a4bc785c78204eec1be MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1<?php
  2/***************************************************************
  3*  Copyright notice
  4*
  5*  (c) 1999-2010 Kasper Skaarhoj (kasperYYYY@typo3.com)
  6*  All rights reserved
  7*
  8*  This script is part of the TYPO3 project. The TYPO3 project is
  9*  free software; you can redistribute it and/or modify
 10*  it under the terms of the GNU General Public License as published by
 11*  the Free Software Foundation; either version 2 of the License, or
 12*  (at your option) any later version.
 13*
 14*  The GNU General Public License can be found at
 15*  http://www.gnu.org/copyleft/gpl.html.
 16*  A copy is found in the textfile GPL.txt and important notices to the license
 17*  from the author is found in LICENSE.txt distributed with these scripts.
 18*
 19*
 20*  This script is distributed in the hope that it will be useful,
 21*  but WITHOUT ANY WARRANTY; without even the implied warranty of
 22*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 23*  GNU General Public License for more details.
 24*
 25*  This copyright notice MUST APPEAR in all copies of the script!
 26***************************************************************/
 27/**
 28 * Contains the TYPO3 Core Engine
 29 *
 30 * $Id: class.t3lib_tcemain.php 8157 2010-07-11 12:45:16Z psychomieze $
 31 * Revised for TYPO3 3.9 October 2005 by Kasper Skaarhoj
 32 *
 33 * @author	Kasper Skaarhoj <kasperYYYY@typo3.com>
 34 */
 35/**
 36 * [CLASS/FUNCTION INDEX of SCRIPT]
 37 *
 38 *
 39 *
 40 *  242: class t3lib_TCEmain
 41 *  367:     function start($data,$cmd,$altUserObject='')
 42 *  406:     function setMirror($mirror)
 43 *  431:     function setDefaultsFromUserTS($userTS)
 44 *  454:     function process_uploads($postFiles)
 45 *  492:     function process_uploads_traverseArray(&$outputArr,$inputArr,$keyToSet)
 46 *
 47 *              SECTION: PROCESSING DATA
 48 *  528:     function process_datamap()
 49 *  886:     function placeholderShadowing($table,$id)
 50 *  929:     function fillInFieldArray($table,$id,$fieldArray,$incomingFieldArray,$realPid,$status,$tscPID)
 51 *
 52 *              SECTION: Evaluation of input values
 53 * 1152:     function checkValue($table,$field,$value,$id,$status,$realPid,$tscPID)
 54 * 1212:     function checkValue_SW($res,$value,$tcaFieldConf,$table,$id,$curValue,$status,$realPid,$recFID,$field,$uploadedFiles,$tscPID)
 55 * 1261:     function checkValue_input($res,$value,$tcaFieldConf,$PP,$field='')
 56 * 1299:     function checkValue_check($res,$value,$tcaFieldConf,$PP)
 57 * 1322:     function checkValue_radio($res,$value,$tcaFieldConf,$PP)
 58 * 1348:     function checkValue_group_select($res,$value,$tcaFieldConf,$PP,$uploadedFiles,$field)
 59 * 1458:     function checkValue_group_select_file($valueArray,$tcaFieldConf,$curValue,$uploadedFileArray,$status,$table,$id,$recFID)
 60 * 1632:     function checkValue_flex($res,$value,$tcaFieldConf,$PP,$uploadedFiles,$field)
 61 * 1709:     function checkValue_flexArray2Xml($array, $addPrologue=FALSE)
 62 * 1721:     function _DELETE_FLEX_FORMdata(&$valueArrayToRemoveFrom,$deleteCMDS)
 63 * 1743:     function _MOVE_FLEX_FORMdata(&$valueArrayToMoveIn, $moveCMDS, $direction)
 64 * 1783:     function checkValue_inline($res,$value,$tcaFieldConf,$PP,$field)
 65 * 1825:     function checkValue_checkMax($tcaFieldConf, $valueArray)
 66 *
 67 *              SECTION: Helper functions for evaluation functions.
 68 * 1877:     function getUnique($table,$field,$value,$id,$newPid=0)
 69 * 1915:     function checkValue_input_Eval($value,$evalArray,$is_in)
 70 * 2012:     function checkValue_group_select_processDBdata($valueArray,$tcaFieldConf,$id,$status,$type,$currentTable)
 71 * 2058:     function checkValue_group_select_explodeSelectGroupValue($value)
 72 * 2082:     function checkValue_flex_procInData($dataPart,$dataPart_current,$uploadedFiles,$dataStructArray,$pParams,$callBackFunc='')
 73 * 2121:     function checkValue_flex_procInData_travDS(&$dataValues,$dataValues_current,$uploadedFiles,$DSelements,$pParams,$callBackFunc,$structurePath)
 74 *
 75 *              SECTION: PROCESSING COMMANDS
 76 * 2267:     function process_cmdmap()
 77 *
 78 *              SECTION: Cmd: Copying
 79 * 2407:     function copyRecord($table,$uid,$destPid,$first=0,$overrideValues=array(),$excludeFields='')
 80 * 2529:     function copyPages($uid,$destPid)
 81 * 2583:     function copySpecificPage($uid,$destPid,$copyTablesArray,$first=0)
 82 * 2617:     function copyRecord_raw($table,$uid,$pid,$overrideArray=array())
 83 * 2681:     function rawCopyPageContent($old_pid,$new_pid,$copyTablesArray)
 84 * 2705:     function insertNewCopyVersion($table,$fieldArray,$realPid)
 85 * 2757:     function copyRecord_procBasedOnFieldType($table,$uid,$field,$value,$row,$conf,$realDestPid)
 86 * 2836:     function copyRecord_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2)
 87 * 2864:     function copyRecord_procFilesRefs($conf, $uid, $value)
 88 *
 89 *              SECTION: Cmd: Moving, Localizing
 90 * 2933:     function moveRecord($table,$uid,$destPid)
 91 * 3128:     function moveRecord_procFields($table,$uid,$destPid)
 92 * 3148:     function moveRecord_procBasedOnFieldType($table,$uid,$destPid,$field,$value,$conf)
 93 * 3182:     function localize($table,$uid,$language)
 94 *
 95 *              SECTION: Cmd: Deleting
 96 * 3296:     function deleteAction($table, $id)
 97 * 3343:     function deleteEl($table, $uid, $noRecordCheck=FALSE, $forceHardDelete=FALSE)
 98 * 3360:     function deleteVersionsForRecord($table, $uid, $forceHardDelete)
 99 * 3382:     function undeleteRecord($table,$uid)
100 * 3399:     function deleteRecord($table,$uid, $noRecordCheck=FALSE, $forceHardDelete=FALSE,$undeleteRecord=FALSE)
101 * 3512:     function deleteRecord_flexFormCallBack($dsArr, $dataValue, $PA, $structurePath, &$pObj)
102 * 3539:     function deletePages($uid,$force=FALSE,$forceHardDelete=FALSE)
103 * 3567:     function deleteSpecificPage($uid,$forceHardDelete=FALSE)
104 * 3592:     function canDeletePage($uid)
105 * 3619:     function cannotDeleteRecord($table,$id)
106 * 3638:     function deleteRecord_procFields($table, $uid, $undeleteRecord = false)
107 * 3661:     function deleteRecord_procBasedOnFieldType($table, $uid, $field, $value, $conf, $undeleteRecord = false)
108 *
109 *              SECTION: Cmd: Versioning
110 * 3722:     function versionizeRecord($table,$id,$label,$delete=FALSE,$versionizeTree=-1)
111 * 3798:     function versionizePages($uid,$label,$versionizeTree)
112 * 3861:     function version_swap($table,$id,$swapWith,$swapIntoWS=0)
113 * 4032:     function version_clearWSID($table,$id)
114 * 4066:     function version_setStage($table,$id,$stageId,$comment='')
115 *
116 *              SECTION: Cmd: Helper functions
117 * 4111:     function remapListedDBRecords()
118 * 4192:     function remapListedDBRecords_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2)
119 * 4219:     function remapListedDBRecords_procDBRefs($conf, $value, $MM_localUid, $table)
120 * 4265:     function remapListedDBRecords_procInline($conf, $value, $uid, $table)
121 *
122 *              SECTION: Access control / Checking functions
123 * 4308:     function checkModifyAccessList($table)
124 * 4320:     function isRecordInWebMount($table,$id)
125 * 4334:     function isInWebMount($pid)
126 * 4348:     function checkRecordUpdateAccess($table,$id)
127 * 4372:     function checkRecordInsertAccess($insertTable,$pid,$action=1)
128 * 4406:     function isTableAllowedForThisPage($page_uid, $checkTable)
129 * 4439:     function doesRecordExist($table,$id,$perms)
130 * 4504:     function doesRecordExist_pageLookUp($id, $perms)
131 * 4530:     function doesBranchExist($inList,$pid,$perms,$recurse)
132 * 4564:     function tableReadOnly($table)
133 * 4576:     function tableAdminOnly($table)
134 * 4590:     function destNotInsideSelf($dest,$id)
135 * 4622:     function getExcludeListArray()
136 * 4645:     function doesPageHaveUnallowedTables($page_uid,$doktype)
137 *
138 *              SECTION: Information lookup
139 * 4694:     function pageInfo($id,$field)
140 * 4714:     function recordInfo($table,$id,$fieldList)
141 * 4735:     function getRecordProperties($table,$id,$noWSOL=FALSE)
142 * 4751:     function getRecordPropertiesFromRow($table,$row)
143 *
144 *              SECTION: Storing data to Database Layer
145 * 4794:     function updateDB($table,$id,$fieldArray)
146 * 4846:     function insertDB($table,$id,$fieldArray,$newVersion=FALSE,$suggestedUid=0,$dontSetNewIdIndex=FALSE)
147 * 4919:     function checkStoredRecord($table,$id,$fieldArray,$action)
148 * 4956:     function setHistory($table,$id,$logId)
149 * 4989:     function clearHistory($maxAgeSeconds=604800,$table)
150 * 5003:     function updateRefIndex($table,$id)
151 *
152 *              SECTION: Misc functions
153 * 5035:     function getSortNumber($table,$uid,$pid)
154 * 5108:     function resorting($table,$pid,$sortRow, $return_SortNumber_After_This_Uid)
155 * 5139:     function setTSconfigPermissions($fieldArray,$TSConfig_p)
156 * 5156:     function newFieldArray($table)
157 * 5188:     function addDefaultPermittedLanguageIfNotSet($table,&$incomingFieldArray)
158 * 5212:     function overrideFieldArray($table,$data)
159 * 5228:     function compareFieldArrayWithCurrentAndUnset($table,$id,$fieldArray)
160 * 5274:     function assemblePermissions($string)
161 * 5291:     function rmComma($input)
162 * 5301:     function convNumEntityToByteValue($input)
163 * 5323:     function destPathFromUploadFolder($folder)
164 * 5333:     function deleteClause($table)
165 * 5349:     function getTCEMAIN_TSconfig($tscPID)
166 * 5364:     function getTableEntries($table,$TSconfig)
167 * 5377:     function getPID($table,$uid)
168 * 5390:     function dbAnalysisStoreExec()
169 * 5406:     function removeRegisteredFiles()
170 * 5418:     function removeCacheFiles()
171 * 5432:     function int_pageTreeInfo($CPtable,$pid,$counter, $rootID)
172 * 5453:     function compileAdminTables()
173 * 5470:     function fixUniqueInPid($table,$uid)
174 * 5506:     function fixCopyAfterDuplFields($table,$uid,$prevUid,$update, $newData=array())
175 * 5531:     function extFileFields($table)
176 * 5552:     function getUniqueFields($table)
177 * 5577:     function isReferenceField($conf)
178 * 5588:     function getInlineFieldType($conf)
179 * 5611:     function getCopyHeader($table,$pid,$field,$value,$count,$prevTitle='')
180 * 5640:     function prependLabel($table)
181 * 5657:     function resolvePid($table,$pid)
182 * 5687:     function clearPrefixFromValue($table,$value)
183 * 5702:     function extFileFunctions($table,$field,$filelist,$func)
184 * 5732:     function noRecordsFromUnallowedTables($inList)
185 * 5758:     function notifyStageChange($stat,$stageId,$table,$id,$comment)
186 * 5853:     function notifyStageChange_getEmails($listOfUsers,$noTablePrefix=FALSE)
187 *
188 *              SECTION: Clearing cache
189 * 5899:     function clear_cache($table,$uid)
190 * 6009:     function clear_cacheCmd($cacheCmd)
191 *
192 *              SECTION: Logging
193 * 6113:     function log($table,$recuid,$action,$recpid,$error,$details,$details_nr=-1,$data=array(),$event_pid=-1,$NEWid='')
194 * 6130:     function newlog($message, $error=0)
195 * 6140:     function printLogErrorMessages($redirect)
196 *
197 *              SECTION: Internal (do not use outside Core!)
198 * 6202:     function internal_clearPageCache()
199 *
200 * TOTAL FUNCTIONS: 126
201 * (This index is automatically created/updated by the extension "extdeveval")
202 *
203 */
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219/**
220 * This is the TYPO3 Core Engine class for manipulation of the database
221 * This class is used by eg. the tce_db.php script which provides an the interface for POST forms to this class.
222 *
223 * Dependencies:
224 * - $GLOBALS['TCA'] must exist
225 * - $GLOBALS['LANG'] must exist
226 *
227 * tce_db.php for further comments and SYNTAX! Also see document 'TYPO3 Core API' for details.
228 *
229 * @author	Kasper Skaarhoj <kasperYYYY@typo3.com>
230 * @package TYPO3
231 * @subpackage t3lib
232 */
233class t3lib_TCEmain	{
234
235
236		// *********************
237		// Public variables you can configure before using the class:
238		// *********************
239
240	var $storeLogMessages = TRUE;			// Boolean: If true, the default log-messages will be stored. This should not be necessary if the locallang-file for the log-display is properly configured. So disabling this will just save some database-space as the default messages are not saved.
241	var $enableLogging = TRUE;				// Boolean: If true, actions are logged to sys_log.
242	var $reverseOrder = FALSE;				// Boolean: If true, the datamap array is reversed in the order, which is a nice thing if you're creating a whole new bunch of records.
243	var $checkSimilar = TRUE;				// Boolean: If true, only fields which are different from the database values are saved! In fact, if a whole input array is similar, it's not saved then.
244	var $stripslashes_values = TRUE;		// Boolean: If true, incoming values in the data-array have their slashes stripped. ALWAYS SET THIS TO ZERO and supply an unescaped data array instead. This switch may totally disappear in future versions of this class!
245	var $checkStoredRecords = TRUE;			// Boolean: This will read the record after having updated or inserted it. If anything is not properly submitted an error is written to the log. This feature consumes extra time by selecting records
246	var $checkStoredRecords_loose = TRUE;	// Boolean: If set, values '' and 0 will equal each other when the stored records are checked.
247	var $deleteTree = FALSE;				// Boolean. If this is set, then a page is deleted by deleting the whole branch under it (user must have deletepermissions to it all). If not set, then the page is deleted ONLY if it has no branch
248	var $neverHideAtCopy = FALSE;			// Boolean. If set, then the 'hideAtCopy' flag for tables will be ignored.
249	var $dontProcessTransformations = FALSE;	// Boolean: If set, then transformations are NOT performed on the input.
250	var $clear_flexFormData_vDEFbase = FALSE;	// Boolean: If set, .vDEFbase values are unset in flexforms.
251	var $updateModeL10NdiffData = TRUE;		// Boolean/Mixed: TRUE: (traditional) Updates when record is saved. For flexforms, updates if change is made to the localized value. FALSE: Will not update anything. "FORCE_FFUPD" (string): Like TRUE, but will force update to the FlexForm Field
252	var $updateModeL10NdiffDataClear = FALSE;	// Boolean: If true, the translation diff. fields will in fact be reset so that they indicate that all needs to change again! It's meant as the opposite of declaring the record translated.
253	var $bypassWorkspaceRestrictions = FALSE;	// Boolean: If true, workspace restrictions are bypassed on edit an create actions (process_datamap()). YOU MUST KNOW what you do if you use this feature!
254	var $bypassFileHandling = FALSE;			// Boolean: If true, file handling of attached files (addition, deletion etc) is bypassed - the value is saved straight away. YOU MUST KNOW what you are doing with this feature!
255	var $bypassAccessCheckForRecords = FALSE;	// Boolean: If true, access check, check for deleted etc. for records is bypassed. YOU MUST KNOW what you are doing if you use this feature!
256
257	var $copyWhichTables = '*';				// String. Comma-list. This list of tables decides which tables will be copied. If empty then none will. If '*' then all will (that the user has permission to of course)
258	var $generalComment = '';				// General comment, eg. for staging in workspaces.
259
260	var $copyTree = 0;						// Integer. If 0 then branch is NOT copied. If 1 then pages on the 1st level is copied. If 2 then pages on the second level is copied ... and so on
261
262	var $defaultValues = array();			// Array [table][fields]=value: New records are created with default values and you can set this array on the form $defaultValues[$table][$field] = $value to override the default values fetched from TCA. If ->setDefaultsFromUserTS is called UserTSconfig default values will overrule existing values in this array (thus UserTSconfig overrules externally set defaults which overrules TCA defaults)
263	var $overrideValues = array();			// Array [table][fields]=value: You can set this array on the form $overrideValues[$table][$field] = $value to override the incoming data. You must set this externally. You must make sure the fields in this array are also found in the table, because it's not checked. All columns can be set by this array!
264	var $alternativeFileName = array();		// Array [filename]=alternative_filename: Use this array to force another name onto a file. Eg. if you set ['/tmp/blablabal'] = 'my_file.txt' and '/tmp/blablabal' is set for a certain file-field, then 'my_file.txt' will be used as the name instead.
265	var $alternativeFilePath = array();		// Array [filename]=alternative_filepath: Same as alternativeFileName but with relative path to the file
266	var $data_disableFields=array();		// If entries are set in this array corresponding to fields for update, they are ignored and thus NOT updated. You could set this array from a series of checkboxes with value=0 and hidden fields before the checkbox with 1. Then an empty checkbox will disable the field.
267	var $suggestedInsertUids=array();		// Use this array to validate suggested uids for tables by setting [table]:[uid]. This is a dangerous option since it will force the inserted record to have a certain UID. The value just have to be true, but if you set it to "DELETE" it will make sure any record with that UID will be deleted first (raw delete). The option is used for import of T3D files when synchronizing between two mirrored servers. As a security measure this feature is available only for Admin Users (for now)
268
269	var $callBackObj;						// Object. Call back object for flex form traversation. Useful when external classes wants to use the iteration functions inside tcemain for traversing a FlexForm structure.
270
271
272
273
274		// *********************
275		// Internal variables (mapping arrays) which can be used (read-only) from outside
276		// *********************
277	var $autoVersionIdMap = Array();			// Contains mapping of auto-versionized records.
278	var $substNEWwithIDs = Array();				// When new elements are created, this array contains a map between their "NEW..." string IDs and the eventual UID they got when stored in database
279	var $substNEWwithIDs_table = Array();		// Like $substNEWwithIDs, but where each old "NEW..." id is mapped to the table it was from.
280	var $newRelatedIDs = Array();				// Holds the tables and there the ids of newly created child records from IRRE
281	var $copyMappingArray_merged = Array();		// This array is the sum of all copying operations in this class. May be READ from outside, thus partly public.
282	var $copiedFileMap = Array();				// A map between input file name and final destination for files being attached to records.
283	var $RTEmagic_copyIndex = Array();			// Contains [table][id][field] of fiels where RTEmagic images was copied. Holds old filename as key and new filename as value.
284	var $errorLog = Array();					// Errors are collected in this variable.
285	var $accumulateForNotifEmail = Array();		// For accumulating information about workspace stages raised on elements so a single mail is sent as notification.
286
287
288
289		// *********************
290		// Internal Variables, do not touch.
291		// *********************
292
293		// Variables set in init() function:
294	/**
295	 * The user-object the script uses. If not set from outside, this is set to the current global $BE_USER.
296	 *
297	 * @var t3lib_beUserAuth
298	 */
299	var $BE_USER;
300	var $userid;		// will be set to uid of be_user executing this script
301	var $username;		// will be set to username of be_user executing this script
302	var $admin;			// will be set if user is admin
303
304	var $defaultPermissions = array(		// Can be overridden from $TYPO3_CONF_VARS
305		'user' => 'show,edit,delete,new,editcontent',
306		'group' => 'show,edit,new,editcontent',
307		'everybody' => ''
308	);
309
310	var $exclude_array;			// The list of <table>-<fields> that cannot be edited by user. This is compiled from TCA/exclude-flag combined with non_exclude_fields for the user.
311	var $datamap = Array();		// Set with incoming data array
312	var $cmdmap = Array();		// Set with incoming cmd array
313
314		// Internal static:
315	var $pMap = Array(		// Permission mapping
316		'show' => 1,			// 1st bit
317		'edit' => 2,			// 2nd bit
318		'delete' => 4,			// 3rd bit
319		'new' => 8,				// 4th bit
320		'editcontent' => 16		// 5th bit
321	);
322	var $sortIntervals = 256;					// Integer: The interval between sorting numbers used with tables with a 'sorting' field defined. Min 1
323
324		// Internal caching arrays
325	var $recUpdateAccessCache = Array();		// Used by function checkRecordUpdateAccess() to store whether a record is updateable or not.
326	var $recInsertAccessCache = Array();		// User by function checkRecordInsertAccess() to store whether a record can be inserted on a page id
327	var $isRecordInWebMount_Cache=array();		// Caching array for check of whether records are in a webmount
328	var $isInWebMount_Cache=array();			// Caching array for page ids in webmounts
329	var $cachedTSconfig = array();				// Caching for collecting TSconfig for page ids
330	var $pageCache = Array();					// Used for caching page records in pageInfo()
331	var $checkWorkspaceCache = Array();			// Array caching workspace access for BE_USER
332
333		// Other arrays:
334	var $dbAnalysisStore=array();				// For accumulation of MM relations that must be written after new records are created.
335	var $removeFilesStore=array();				// For accumulation of files which must be deleted after processing of all input content
336	var $uploadedFileArray = array();			// Uploaded files, set by process_uploads()
337	var $registerDBList=array();				// Used for tracking references that might need correction after operations
338	var $registerDBPids=array();				// Used for tracking references that might need correction in pid field after operations (e.g. IRRE)
339	var $copyMappingArray = Array();			// Used by the copy action to track the ids of new pages so subpages are correctly inserted! THIS is internally cleared for each executed copy operation! DO NOT USE THIS FROM OUTSIDE! Read from copyMappingArray_merged instead which is accumulating this information.
340	var $remapStack = array();					// array used for remapping uids and values at the end of process_datamap
341	var $remapStackRecords = array();			// array used for remapping uids and values at the end of process_datamap (e.g. $remapStackRecords[<table>][<uid>] = <index in $remapStack>)
342	var $updateRefIndexStack = array();			// array used for additional calls to $this->updateRefIndex
343	var $callFromImpExp = false;				// tells, that this TCEmain was called from tx_impext - this variable is set by tx_impexp
344	var $newIndexMap = array();					// Array for new flexform index mapping
345
346		// Various
347	/**
348	 * basicFileFunctions object
349	 *
350	 * @var t3lib_basicFileFunctions
351	 */
352	var $fileFunc;								// For "singleTon" file-manipulation object
353	var $checkValue_currentRecord=array();		// Set to "currentRecord" during checking of values.
354	var $autoVersioningUpdate = FALSE;			// A signal flag used to tell file processing that autoversioning has happend and hence certain action should be applied.
355
356	protected $disableDeleteClause = false;		// Disable delete clause
357	protected $checkModifyAccessListHookObjects;
358
359
360
361
362
363
364
365
366
367
368
369	/**
370	 * Initializing.
371	 * For details, see 'TYPO3 Core API' document.
372	 * This function does not start the processing of data, but merely initializes the object
373	 *
374	 * @param	array		Data to be modified or inserted in the database
375	 * @param	array		Commands to copy, move, delete, localize, versionize records.
376	 * @param	object		An alternative userobject you can set instead of the default, which is $GLOBALS['BE_USER']
377	 * @return	void
378	 */
379	function start($data,$cmd,$altUserObject='')	{
380
381			// Initializing BE_USER
382		$this->BE_USER = is_object($altUserObject) ? $altUserObject : $GLOBALS['BE_USER'];
383		$this->userid = $this->BE_USER->user['uid'];
384		$this->username = $this->BE_USER->user['username'];
385		$this->admin = $this->BE_USER->user['admin'];
386
387		if ($this->BE_USER->uc['recursiveDelete']) {
388			$this->deleteTree = 1;
389		}
390
391		if ($GLOBALS['TYPO3_CONF_VARS']['BE']['explicitConfirmationOfTranslation'] && $this->updateModeL10NdiffData===TRUE)	{
392			$this->updateModeL10NdiffData = FALSE;
393		}
394
395			// Initializing default permissions for pages
396		$defaultPermissions = $GLOBALS['TYPO3_CONF_VARS']['BE']['defaultPermissions'];
397		if (isset($defaultPermissions['user']))		{$this->defaultPermissions['user'] = $defaultPermissions['user'];}
398		if (isset($defaultPermissions['group']))		{$this->defaultPermissions['group'] = $defaultPermissions['group'];}
399		if (isset($defaultPermissions['everybody']))		{$this->defaultPermissions['everybody'] = $defaultPermissions['everybody'];}
400
401			// generates the excludelist, based on TCA/exclude-flag and non_exclude_fields for the user:
402		$this->exclude_array = $this->admin ? array() : $this->getExcludeListArray();
403
404			// Setting the data and cmd arrays
405		if (is_array($data)) {
406			reset($data);
407			$this->datamap = $data;
408		}
409		if (is_array($cmd))	{
410			reset($cmd);
411			$this->cmdmap = $cmd;
412		}
413	}
414
415	/**
416	 * Function that can mirror input values in datamap-array to other uid numbers.
417	 * Example: $mirror[table][11] = '22,33' will look for content in $this->datamap[table][11] and copy it to $this->datamap[table][22] and $this->datamap[table][33]
418	 *
419	 * @param	array		This array has the syntax $mirror[table_name][uid] = [list of uids to copy data-value TO!]
420	 * @return	void
421	 */
422	function setMirror($mirror)	{
423		if (is_array($mirror))	{
424			foreach ($mirror as $table => $uid_array) {
425				if (isset($this->datamap[$table]))	{
426					reset($uid_array);
427					foreach ($uid_array as $id => $uidList) {
428						if (isset($this->datamap[$table][$id]))	{
429							$theIdsInArray = t3lib_div::trimExplode(',',$uidList,1);
430							foreach ($theIdsInArray as $copyToUid) {
431								$this->datamap[$table][$copyToUid] = $this->datamap[$table][$id];
432							}
433						}
434					}
435				}
436			}
437		}
438	}
439
440	/**
441	 * Initializes default values coming from User TSconfig
442	 *
443	 * @param	array		User TSconfig array
444	 * @return	void
445	 */
446	function setDefaultsFromUserTS($userTS)	{
447		global $TCA;
448		if (is_array($userTS))	{
449			foreach($userTS as $k => $v)	{
450				$k = substr($k,0,-1);
451				if ($k && is_array($v) && isset($TCA[$k]))	{
452					if (is_array($this->defaultValues[$k]))	{
453						$this->defaultValues[$k] = array_merge($this->defaultValues[$k],$v);
454					} else {
455						$this->defaultValues[$k] = $v;
456					}
457				}
458			}
459		}
460	}
461
462	/**
463	 * Processing of uploaded files.
464	 * It turns out that some versions of PHP arranges submitted data for files different if sent in an array. This function will unify this so the internal array $this->uploadedFileArray will always contain files arranged in the same structure.
465	 *
466	 * @param	array		$_FILES array
467	 * @return	void
468	 */
469	function process_uploads($postFiles)	{
470
471		if (is_array($postFiles))	{
472
473				// Editing frozen:
474			if ($this->BE_USER->workspace!==0 && $this->BE_USER->workspaceRec['freeze'])	{
475				$this->newlog('All editing in this workspace has been frozen!',1);
476				return FALSE;
477			}
478
479			reset($postFiles);
480			$subA = current($postFiles);
481			if (is_array($subA))	{
482				if (is_array($subA['name']) && is_array($subA['type']) && is_array($subA['tmp_name']) && is_array($subA['size']))	{
483						// Initialize the uploadedFilesArray:
484					$this->uploadedFileArray=array();
485
486						// For each entry:
487					foreach($subA as $key => $values)	{
488						$this->process_uploads_traverseArray($this->uploadedFileArray,$values,$key);
489					}
490				} else {
491					$this->uploadedFileArray=$subA;
492				}
493			}
494		}
495	}
496
497	/**
498	 * Traverse the upload array if needed to rearrange values.
499	 *
500	 * @param	array		$this->uploadedFileArray passed by reference
501	 * @param	array		Input array  ($_FILES parts)
502	 * @param	string		The current $_FILES array key to set on the outermost level.
503	 * @return	void
504	 * @access private
505	 * @see process_uploads()
506	 */
507	function process_uploads_traverseArray(&$outputArr,$inputArr,$keyToSet)	{
508		if (is_array($inputArr))	{
509			foreach($inputArr as $key => $value)	{
510				$this->process_uploads_traverseArray($outputArr[$key],$inputArr[$key],$keyToSet);
511			}
512		} else {
513			$outputArr[$keyToSet]=$inputArr;
514		}
515	}
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531	/*********************************************
532	 *
533	 * HOOKS
534	 *
535	 *********************************************/
536
537	/**
538	 * Hook: processDatamap_afterDatabaseOperations
539	 * (calls $hookObj->processDatamap_afterDatabaseOperations($status, $table, $id, $fieldArray, $this);)
540	 *
541	 * Note: When using the hook after INSERT operations, you will only get the temporary NEW... id passed to your hook as $id,
542	 *		 but you can easily translate it to the real uid of the inserted record using the $this->substNEWwithIDs array.
543	 *
544	 * @param	object		$hookObjectsArr: (reference) Array with hook objects
545	 * @param	string		$status: (reference) Status of the current operation, 'new' or 'update
546	 * @param	string		$table: (refrence) The table currently processing data for
547	 * @param	string		$id: (reference) The record uid currently processing data for, [integer] or [string] (like 'NEW...')
548	 * @param	array		$fieldArray: (reference) The field array of a record
549	 * @return	void
550	 */
551	function hook_processDatamap_afterDatabaseOperations(&$hookObjectsArr, &$status, &$table, &$id, &$fieldArray) {
552			// Process hook directly:
553		if (!isset($this->remapStackRecords[$table][$id])) {
554			foreach($hookObjectsArr as $hookObj)	{
555				if (method_exists($hookObj, 'processDatamap_afterDatabaseOperations')) {
556					$hookObj->processDatamap_afterDatabaseOperations($status, $table, $id, $fieldArray, $this);
557				}
558			}
559			// If this record is in remapStack (e.g. when using IRRE), values will be updated/remapped later on. So the hook will also be called later:
560		} else {
561			$this->remapStackRecords[$table][$id]['processDatamap_afterDatabaseOperations'] = array(
562				'status' => $status,
563				'fieldArray' => $fieldArray,
564				'hookObjectsArr' => $hookObjectsArr,
565			);
566		}
567	}
568
569	/**
570	 * Gets the 'checkModifyAccessList' hook objects.
571	 * The first call initializes the accordant objects.
572	 *
573	 * @return	array		The 'checkModifyAccessList' hook objects (if any)
574	 */
575	protected function getCheckModifyAccessListHookObjects() {
576		if (!isset($this->checkModifyAccessListHookObjects)) {
577			$this->checkModifyAccessListHookObjects = array();
578
579			if(is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['checkModifyAccessList'])) {
580				foreach($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['checkModifyAccessList'] as $classData) {
581					$hookObject = t3lib_div::getUserObj($classData);
582
583					if(!($hookObject instanceof t3lib_TCEmain_checkModifyAccessListHook)) {
584						throw new UnexpectedValueException('$hookObject must implement interface t3lib_TCEmain_checkModifyAccessListHook', 1251892472);
585					}
586
587					$this->checkModifyAccessListHookObjects[] = $hookObject;
588				}
589			}
590		}
591
592		return $this->checkModifyAccessListHookObjects;
593	}
594
595
596
597
598
599
600
601
602
603
604
605
606
607	/*********************************************
608	 *
609	 * PROCESSING DATA
610	 *
611	 *********************************************/
612
613	/**
614	 * Processing the data-array
615	 * Call this function to process the data-array set by start()
616	 *
617	 * @return	void
618	 */
619	function process_datamap() {
620		global $TCA, $TYPO3_CONF_VARS;
621			// Keep versionized(!) relations here locally:
622		$registerDBList = array();
623
624			// Editing frozen:
625		if ($this->BE_USER->workspace!==0 && $this->BE_USER->workspaceRec['freeze'])	{
626			$this->newlog('All editing in this workspace has been frozen!',1);
627			return FALSE;
628		}
629
630			// First prepare user defined objects (if any) for hooks which extend this function:
631		$hookObjectsArr = array();
632		if (is_array ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'])) {
633			foreach ($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'] as $classRef) {
634				$hookObjectsArr[] = t3lib_div::getUserObj($classRef);
635			}
636		}
637
638			// Organize tables so that the pages-table is always processed first. This is required if you want to make sure that content pointing to a new page will be created.
639		$orderOfTables = Array();
640		if (isset($this->datamap['pages']))	{		// Set pages first.
641			$orderOfTables[]='pages';
642		}
643		$orderOfTables = array_unique(array_merge($orderOfTables, array_keys($this->datamap)));
644
645			// Process the tables...
646		foreach($orderOfTables as $table)	{
647				/* Check if
648					- table is set in $TCA,
649					- table is NOT readOnly
650					- the table is set with content in the data-array (if not, there's nothing to process...)
651					- permissions for tableaccess OK
652				*/
653			$modifyAccessList = $this->checkModifyAccessList($table);
654			if (!$modifyAccessList)	{
655				$id = 0;
656				$this->log($table,$id,2,0,1,"Attempt to modify table '%s' without permission",1,array($table));
657			}
658			if (isset($TCA[$table]) && !$this->tableReadOnly($table) && is_array($this->datamap[$table]) && $modifyAccessList)	{
659				if ($this->reverseOrder)	{
660					$this->datamap[$table] = array_reverse($this->datamap[$table], 1);
661				}
662
663					// For each record from the table, do:
664					// $id is the record uid, may be a string if new records...
665					// $incomingFieldArray is the array of fields
666				foreach($this->datamap[$table] as $id => $incomingFieldArray)	{
667					if (is_array($incomingFieldArray))	{
668
669							// Hook: processDatamap_preProcessFieldArray
670						foreach($hookObjectsArr as $hookObj)	{
671							if (method_exists($hookObj, 'processDatamap_preProcessFieldArray')) {
672								$hookObj->processDatamap_preProcessFieldArray($incomingFieldArray, $table, $id, $this);
673							}
674						}
675
676							// ******************************
677							// Checking access to the record
678							// ******************************
679						$createNewVersion = FALSE;
680						$recordAccess = FALSE;
681						$old_pid_value = '';
682						$this->autoVersioningUpdate = FALSE;
683
684						if (!t3lib_div::testInt($id)) {               // Is it a new record? (Then Id is a string)
685							$fieldArray = $this->newFieldArray($table);	// Get a fieldArray with default values
686							if (isset($incomingFieldArray['pid']))	{	// A pid must be set for new records.
687									// $value = the pid
688								$pid_value = $incomingFieldArray['pid'];
689
690									// Checking and finding numerical pid, it may be a string-reference to another value
691								$OK = 1;
692								if (strstr($pid_value,'NEW'))	{	// If a NEW... id
693									if (substr($pid_value,0,1)=='-') {$negFlag=-1;$pid_value=substr($pid_value,1);} else {$negFlag=1;}
694									if (isset($this->substNEWwithIDs[$pid_value]))	{	// Trying to find the correct numerical value as it should be mapped by earlier processing of another new record.
695										$old_pid_value = $pid_value;
696										$pid_value=intval($negFlag*$this->substNEWwithIDs[$pid_value]);
697									} else {$OK = 0;}	// If not found in the substArray we must stop the process...
698								} elseif ($pid_value>=0 && $this->BE_USER->workspace!==0 && $TCA[$table]['ctrl']['versioning_followPages'])	{	// PID points to page, the workspace is an offline space and the table follows page during versioning: This means we must check if the PID page has a version in the workspace with swapmode set to 0 (zero = page+content) and if so, change the pid to the uid of that version.
699									if ($WSdestPage = t3lib_BEfunc::getWorkspaceVersionOfRecord($this->BE_USER->workspace, 'pages', $pid_value, 'uid,t3ver_swapmode'))	{	// Looks for workspace version of page.
700										if ($WSdestPage['t3ver_swapmode']==0)	{	// if swapmode is zero, then change pid value.
701											$pid_value = $WSdestPage['uid'];
702										}
703									}
704								}
705								$pid_value = intval($pid_value);
706
707									// The $pid_value is now the numerical pid at this point
708								if ($OK)	{
709									$sortRow = $TCA[$table]['ctrl']['sortby'];
710									if ($pid_value>=0)	{	// Points to a page on which to insert the element, possibly in the top of the page
711										if ($sortRow)	{	// If this table is sorted we better find the top sorting number
712											$fieldArray[$sortRow] = $this->getSortNumber($table,0,$pid_value);
713										}
714										$fieldArray['pid'] = $pid_value;	// The numerical pid is inserted in the data array
715									} else {	// points to another record before ifself
716										if ($sortRow)	{	// If this table is sorted we better find the top sorting number
717											$tempArray=$this->getSortNumber($table,0,$pid_value);	// Because $pid_value is < 0, getSortNumber returns an array
718											$fieldArray['pid'] = $tempArray['pid'];
719											$fieldArray[$sortRow] = $tempArray['sortNumber'];
720										} else {	// Here we fetch the PID of the record that we point to...
721											$tempdata = $this->recordInfo($table,abs($pid_value),'pid');
722											$fieldArray['pid']=$tempdata['pid'];
723										}
724									}
725								}
726							}
727							$theRealPid = $fieldArray['pid'];
728
729								// Now, check if we may insert records on this pid.
730							if ($theRealPid>=0)	{
731								$recordAccess = $this->checkRecordInsertAccess($table,$theRealPid);		// Checks if records can be inserted on this $pid.
732								if ($recordAccess)	{
733									$this->addDefaultPermittedLanguageIfNotSet($table,$incomingFieldArray);
734									$recordAccess = $this->BE_USER->recordEditAccessInternals($table,$incomingFieldArray,TRUE);
735									if (!$recordAccess)		{
736										$this->newlog("recordEditAccessInternals() check failed. [".$this->BE_USER->errorMsg."]",1);
737									} elseif(!$this->bypassWorkspaceRestrictions)	{
738											// Workspace related processing:
739										if ($res = $this->BE_USER->workspaceAllowLiveRecordsInPID($theRealPid,$table))	{	// If LIVE records cannot be created in the current PID due to workspace restrictions, prepare creation of placeholder-record
740											if ($res<0)	{
741												$recordAccess = FALSE;
742												$this->newlog('Stage for versioning root point and users access level did not allow for editing',1);
743											}
744										} else {	// So, if no live records were allowed, we have to create a new version of this record:
745											if ($TCA[$table]['ctrl']['versioningWS'])	{
746												$createNewVersion = TRUE;
747											} else {
748												$recordAccess = FALSE;
749												$this->newlog('Record could not be created in this workspace in this branch',1);
750											}
751										}
752									}
753								}
754							} else {
755								debug('Internal ERROR: pid should not be less than zero!');
756							}
757							$status = 'new';						// Yes new record, change $record_status to 'insert'
758						} else {	// Nope... $id is a number
759							$fieldArray = array();
760							$recordAccess = $this->checkRecordUpdateAccess($table, $id, $incomingFieldArray, $hookObjectsArr);
761							if (!$recordAccess)		{
762								$propArr = $this->getRecordProperties($table,$id);
763								$this->log($table,$id,2,0,1,"Attempt to modify record '%s' (%s) without permission. Or non-existing page.",2,array($propArr['header'],$table.':'.$id),$propArr['event_pid']);
764							} else {	// Next check of the record permissions (internals)
765								$recordAccess = $this->BE_USER->recordEditAccessInternals($table,$id);
766								if (!$recordAccess)		{
767									$propArr = $this->getRecordProperties($table,$id);
768									$this->newlog("recordEditAccessInternals() check failed. [".$this->BE_USER->errorMsg."]",1);
769								} else {	// Here we fetch the PID of the record that we point to...
770									$tempdata = $this->recordInfo($table,$id,'pid'.($TCA[$table]['ctrl']['versioningWS']?',t3ver_wsid,t3ver_stage':''));
771									$theRealPid = $tempdata['pid'];
772
773									// Use the new id of the versionized record we're trying to write to:
774										// (This record is a child record of a parent and has already been versionized.)
775									if ($this->autoVersionIdMap[$table][$id]) {
776											// For the reason that creating a new version of this record, automatically
777											// created related child records (e.g. "IRRE"), update the accordant field:
778										$this->getVersionizedIncomingFieldArray($table, $id, $incomingFieldArray, $registerDBList);
779
780											// Use the new id of the copied/versionized record:
781										$id = $this->autoVersionIdMap[$table][$id];
782										$recordAccess = TRUE;
783										$this->autoVersioningUpdate = TRUE;
784
785										// Checking access in case of offline workspace:
786									} elseif (!$this->bypassWorkspaceRestrictions && $errorCode = $this->BE_USER->workspaceCannotEditRecord($table,$tempdata)) {
787										$recordAccess = FALSE;		// Versioning is required and it must be offline version!
788
789											// Auto-creation of version: In offline workspace, test if versioning is enabled and look for workspace version of input record. If there is no versionized record found we will create one and save to that.
790										if ($this->BE_USER->workspaceAllowAutoCreation($table,$id,$theRealPid))	{
791											$tce = t3lib_div::makeInstance('t3lib_TCEmain');
792											/* @var $tce t3lib_TCEmain  */
793											$tce->stripslashes_values = 0;
794
795												// Setting up command for creating a new version of the record:
796											$cmd = array();
797											$cmd[$table][$id]['version'] = array(
798												'action' => 'new',
799												'treeLevels' => -1,	// Default is to create a version of the individual records... element versioning that is.
800												'label' => 'Auto-created for WS #'.$this->BE_USER->workspace
801											);
802											$tce->start(array(),$cmd);
803											$tce->process_cmdmap();
804											$this->errorLog = array_merge($this->errorLog,$tce->errorLog);
805
806												// If copying was successful, share the new uids (also of related children):
807											if ($tce->copyMappingArray[$table][$id])	{
808												foreach ($tce->copyMappingArray as $origTable => $origIdArray) {
809													foreach ($origIdArray as $origId => $newId) {
810														$this->uploadedFileArray[$origTable][$newId] = $this->uploadedFileArray[$origTable][$origId];
811														$this->autoVersionIdMap[$origTable][$origId] = $newId;
812													}
813												}
814												$this->RTEmagic_copyIndex = t3lib_div::array_merge_recursive_overrule($this->RTEmagic_copyIndex, $tce->RTEmagic_copyIndex);		// See where RTEmagic_copyIndex is used inside fillInFieldArray() for more information...
815
816													// Update registerDBList, that holds the copied relations to child records:
817												$registerDBList = array_merge($registerDBList, $tce->registerDBList);
818													// For the reason that creating a new version of this record, automatically
819													// created related child records (e.g. "IRRE"), update the accordant field:
820												$this->getVersionizedIncomingFieldArray($table, $id, $incomingFieldArray, $registerDBList);
821
822													// Use the new id of the copied/versionized record:
823												$id = $this->autoVersionIdMap[$table][$id];
824												$recordAccess = TRUE;
825												$this->autoVersioningUpdate = TRUE;
826											} else $this->newlog("Could not be edited in offline workspace in the branch where found (failure state: '".$errorCode."'). Auto-creation of version failed!",1);
827										} else $this->newlog("Could not be edited in offline workspace in the branch where found (failure state: '".$errorCode."'). Auto-creation of version not allowed in workspace!",1);
828									}
829								}
830							}
831							$status = 'update';	// the default is 'update'
832						}
833
834							// If access was granted above, proceed to create or update record:
835						if ($recordAccess)	{
836
837							list($tscPID) = t3lib_BEfunc::getTSCpid($table,$id,$old_pid_value ? $old_pid_value : $fieldArray['pid']);	// Here the "pid" is set IF NOT the old pid was a string pointing to a place in the subst-id array.
838							$TSConfig = $this->getTCEMAIN_TSconfig($tscPID);
839							if ($status=='new' && $table=='pages' && is_array($TSConfig['permissions.']))	{
840								$fieldArray = $this->setTSconfigPermissions($fieldArray,$TSConfig['permissions.']);
841							}
842							if ($createNewVersion)	{
843								$newVersion_placeholderFieldArray = $fieldArray;
844							}
845
846								// Processing of all fields in incomingFieldArray and setting them in $fieldArray
847							$fieldArray = $this->fillInFieldArray($table,$id,$fieldArray,$incomingFieldArray,$theRealPid,$status,$tscPID);
848
849								// NOTICE! All manipulation beyond this point bypasses both "excludeFields" AND possible "MM" relations / file uploads to field!
850
851								// Forcing some values unto field array:
852							$fieldArray = $this->overrideFieldArray($table,$fieldArray);	// NOTICE: This overriding is potentially dangerous; permissions per field is not checked!!!
853							if ($createNewVersion)	{
854								$newVersion_placeholderFieldArray = $this->overrideFieldArray($table,$newVersion_placeholderFieldArray);
855							}
856
857								// Setting system fields
858							if ($status=='new')	{
859								if ($TCA[$table]['ctrl']['crdate'])	{
860									$fieldArray[$TCA[$table]['ctrl']['crdate']] = $GLOBALS['EXEC_TIME'];
861									if ($createNewVersion) {
862										$newVersion_placeholderFieldArray[$TCA[$table]['ctrl']['crdate']] = $GLOBALS['EXEC_TIME'];
863									}
864								}
865								if ($TCA[$table]['ctrl']['cruser_id'])	{
866									$fieldArray[$TCA[$table]['ctrl']['cruser_id']]=$this->userid;
867									if ($createNewVersion)	$newVersion_placeholderFieldArray[$TCA[$table]['ctrl']['cruser_id']]=$this->userid;
868								}
869							} elseif ($this->checkSimilar) {	// Removing fields which are equal to the current value:
870								$fieldArray = $this->compareFieldArrayWithCurrentAndUnset($table,$id,$fieldArray);
871							}
872							if ($TCA[$table]['ctrl']['tstamp'] && count($fieldArray))	{
873								$fieldArray[$TCA[$table]['ctrl']['tstamp']] = $GLOBALS['EXEC_TIME'];
874								if ($createNewVersion) {
875									$newVersion_placeholderFieldArray[$TCA[$table]['ctrl']['tstamp']] = $GLOBALS['EXEC_TIME'];
876								}
877							}
878							if ($TCA[$table]['ctrl']['versioningWS']) {
879								$fieldArray['t3ver_stage'] = 0;
880							}
881
882								// Hook: processDatamap_postProcessFieldArray
883							foreach($hookObjectsArr as $hookObj)	{
884								if (method_exists($hookObj, 'processDatamap_postProcessFieldArray')) {
885									$hookObj->processDatamap_postProcessFieldArray($status, $table, $id, $fieldArray, $this);
886								}
887							}
888
889								// Performing insert/update. If fieldArray has been unset by some userfunction (see hook above), don't do anything
890								// Kasper: Unsetting the fieldArray is dangerous; MM relations might be saved already and files could have been uploaded that are now "lost"
891							if (is_array($fieldArray)) {
892								if ($status=='new')	{
893									if ($createNewVersion)	{	// This creates a new version of the record with online placeholder and offline version
894										$versioningType = $table==='pages' ? $this->BE_USER->workspaceVersioningTypeGetClosest(t3lib_div::intInRange($TYPO3_CONF_VARS['BE']['newPagesVersioningType'],-1,1)) : -1;
895										if ($this->BE_USER->workspaceVersioningTypeAccess($versioningType))	{
896											$newVersion_placeholderFieldArray['t3ver_label'] = 'INITIAL PLACEHOLDER';
897											$newVersion_placeholderFieldArray['t3ver_state'] = 1;	// Setting placeholder state value for temporary record
898											$newVersion_placeholderFieldArray['t3ver_wsid'] = $this->BE_USER->workspace;	// Setting workspace - only so display of place holders can filter out those from other workspaces.
899											$newVersion_placeholderFieldArray[$TCA[$table]['ctrl']['label']] = '[PLACEHOLDER, WS#'.$this->BE_USER->workspace.']';
900											$this->insertDB($table,$id,$newVersion_placeholderFieldArray,FALSE);	// Saving placeholder as 'original'
901
902												// For the actual new offline version, set versioning values to point to placeholder:
903											$fieldArray['pid'] = -1;
904											$fieldArray['t3ver_oid'] = $this->substNEWwithIDs[$id];
905											$fieldArray['t3ver_id'] = 1;
906											$fieldArray['t3ver_state'] = -1;	// Setting placeholder state value for version (so it can know it is currently a new version...)
907											$fieldArray['t3ver_label'] = 'First draft version';
908											$fieldArray['t3ver_wsid'] = $this->BE_USER->workspace;
909											if ($table==='pages') {		// Swap mode set to "branch" so we can build branches for pages.
910												$fieldArray['t3ver_swapmode'] = $versioningType;
911											}
912											$phShadowId = $this->insertDB($table,$id,$fieldArray,TRUE,0,TRUE);	// When inserted, $this->substNEWwithIDs[$id] will be changed to the uid of THIS version and so the interface will pick it up just nice!
913											if ($phShadowId)	{
914												$this->placeholderShadowing($table,$phShadowId);
915													// Hold auto-versionized ids of placeholders:
916												$this->autoVersionIdMap[$table][$this->substNEWwithIDs[$id]] = $phShadowId;
917											}
918										} else $this->newlog('Versioning type "'.$versioningType.'" was not allowed, so could not create new record.',1);
919									} else {
920										$this->insertDB($table,$id,$fieldArray,FALSE,$incomingFieldArray['uid']);
921									}
922								} else {
923									$this->updateDB($table,$id,$fieldArray);
924									$this->placeholderShadowing($table,$id);
925								}
926							}
927
928								/*
929								 * Hook: processDatamap_afterDatabaseOperations
930								 *
931								 * Note: When using the hook after INSERT operations, you will only get the temporary NEW... id passed to your hook as $id,
932								 *		 but you can easily translate it to the real uid of the inserted record using the $this->substNEWwithIDs array.
933								 */
934							$this->hook_processDatamap_afterDatabaseOperations($hookObjectsArr, $status, $table, $id, $fieldArray);
935						}	// if ($recordAccess)	{
936					}	// if (is_array($incomingFieldArray))	{
937				}
938			}
939		}
940
941			// Process the stack of relations to remap/correct
942		$this->processRemapStack();
943		$this->dbAnalysisStoreExec();
944		$this->removeRegisteredFiles();
945
946		/*
947		 * Hook: processDatamap_afterAllOperations
948		 *
949		 * Note: When this hook gets called, all operations on the submitted data have been finished.
950		 */
951		foreach($hookObjectsArr as $hookObj) {
952			if (method_exists($hookObj, 'processDatamap_afterAllOperations')) {
953				$hookObj->processDatamap_afterAllOperations($this);
954			}
955		}
956	}
957
958	/**
959	 * Fix shadowing of data in case we are editing a offline version of a live "New" placeholder record:
960	 *
961	 * @param	string		Table name
962	 * @param	integer		Record uid
963	 * @return	void
964	 */
965	function placeholderShadowing($table,$id)	{
966		global $TCA;
967
968		t3lib_div::loadTCA($table);
969		if ($liveRec = t3lib_BEf…

Large files files are truncated, but you can click here to view the full file