notificationEmailInfo = array();
}
/**
* hook that is called when no prepared command was found
*
* @param $command the command to be executed
* @param $table the table of the record
* @param $id the ID of the record
* @param $value the value containing the data
* @param $commandIsProcessed can be set so that other hooks or
* TCEmain knows that the default cmd doesn't have to be called
* @param $tcemainObj reference to the main tcemain object
* @return void
*/
public function processCmdmap($command, $table, $id, $value, &$commandIsProcessed, &$tcemainObj) {
// custom command "version"
if ($command == 'version') {
$commandWasProcessed = TRUE;
$action = (string) $value['action'];
switch ($action) {
case 'new':
// check if page / branch versioning is needed,
// or if "element" version can be used
$versionizeTree = -1;
if (isset($value['treeLevels'])) {
$versionizeTree = t3lib_div::intInRange($value['treeLevels'], -1, 100);
}
if ($table == 'pages' && $versionizeTree >= 0) {
$this->versionizePages($id, $value['label'], $versionizeTree, $tcemainObj);
} else {
$tcemainObj->versionizeRecord($table, $id, $value['label']);
}
break;
case 'swap':
$swapMode = $tcemainObj->BE_USER->getTSConfigVal('options.workspaces.swapMode');
$elementList = array();
if ($swapMode == 'any' || ($swapMode == 'page' && $table == 'pages')) {
// check if we are allowed to do synchronios publish.
// We must have a single element in the cmdmap to be allowed
if (count($tcemainObj->cmdmap) == 1 && count($tcemainObj->cmdmap[$table]) == 1) {
$elementList = $this->findPageElementsForVersionSwap($table, $id, $value['swapWith']);
}
}
if (count($elementList) == 0) {
$elementList[$table][] = array($id, $value['swapWith']);
}
foreach ($elementList as $tbl => $idList) {
foreach ($idList as $idKey => $idSet) {
$this->version_swap($tbl, $idSet[0], $idSet[1], $value['swapIntoWS'], $tcemainObj);
}
}
break;
case 'clearWSID':
$this->version_clearWSID($table, $id, FALSE, $tcemainObj);
break;
case 'flush':
$this->version_clearWSID($table, $id, TRUE, $tcemainObj);
break;
case 'setStage':
$elementList = array();
$idList = $elementList[$table] = t3lib_div::trimExplode(',', $id, 1);
$setStageMode = $tcemainObj->BE_USER->getTSConfigVal('options.workspaces.changeStageMode');
if ($setStageMode == 'any' || $setStageMode == 'page') {
if (count($idList) == 1) {
$rec = t3lib_BEfunc::getRecord($table, $idList[0], 't3ver_wsid');
$workspaceId = $rec['t3ver_wsid'];
} else {
$workspaceId = $tcemainObj->BE_USER->workspace;
}
if ($table !== 'pages') {
if ($setStageMode == 'any') {
// (1) Find page to change stage and (2)
// find other elements from the same ws to change stage
$pageIdList = array();
$this->findPageIdsForVersionStateChange($table, $idList, $workspaceId, $pageIdList, $elementList);
$this->findPageElementsForVersionStageChange($pageIdList, $workspaceId, $elementList);
}
} else {
// Find all elements from the same ws to change stage
$this->findRealPageIds($idList);
$this->findPageElementsForVersionStageChange($idList, $workspaceId, $elementList);
}
}
foreach ($elementList as $tbl => $elementIdList) {
foreach ($elementIdList as $elementId) {
$this->version_setStage($tbl, $elementId, $value['stageId'], ($value['comment'] ? $value['comment'] : $this->generalComment), TRUE, $tcemainObj);
}
}
break;
}
}
}
/**
* hook that is called AFTER all commands of the commandmap was
* executed
* @param $tcemainObj reference to the main tcemain object
* @return void
*/
public function processCmdmap_afterFinish(&$tcemainObj) {
// Empty accumulation array:
foreach ($this->notificationEmailInfo as $notifItem) {
$this->notifyStageChange($notifItem['shared'][0], $notifItem['shared'][1], implode(', ', $notifItem['elements']), 0, $notifItem['shared'][2], $tcemainObj);
}
// Reset notification array
$this->notificationEmailInfo = array();
}
/**
* hook that is called AFTER all commands of the commandmap was
* executed
* @param $tcemainObj reference to the main tcemain object
* @return void
*/
public function processCmdmap_deleteAction($table, $id, $record, &$recordWasDeleted, &$tcemainObj) {
// only process the hook if it wasn't processed
// by someone else before
if (!$recordWasDeleted) {
$recordWasDeleted = TRUE;
$id = $record['uid'];
// For Live version, try if there is a workspace version because if so, rather "delete" that instead
// Look, if record is an offline version, then delete directly:
if ($record['pid'] != -1) {
if ($wsVersion = t3lib_BEfunc::getWorkspaceVersionOfRecord($tcemainObj->BE_USER->workspace, $table, $id)) {
$record = $wsVersion;
$id = $record['uid'];
}
}
// Look, if record is an offline version, then delete directly:
if ($record['pid'] == -1) {
if ($TCA[$table]['ctrl']['versioningWS']) {
// In Live workspace, delete any. In other workspaces there must be match.
if ($tcemainObj->BE_USER->workspace == 0 || (int) $record['t3ver_wsid'] == $tcemainObj->BE_USER->workspace) {
$liveRec = t3lib_BEfunc::getLiveVersionOfRecord($table, $id, 'uid,t3ver_state');
// Delete those in WS 0 + if their live records state was not "Placeholder".
if ($record['t3ver_wsid']==0 || (int) $liveRec['t3ver_state'] <= 0) {
$tcemainObj->deleteEl($table, $id);
} else {
// If live record was placeholder (new/deleted), rather clear
// it from workspace (because it clears both version and placeholder).
$this->version_clearWSID($table, $id, FALSE, $tcemainObj);
}
} else $tcemainObj->newlog('Tried to delete record from another workspace',1);
} else $tcemainObj->newlog('Versioning not enabled for record with PID = -1!',2);
} elseif ($res = $tcemainObj->BE_USER->workspaceAllowLiveRecordsInPID($record['pid'], $table)) {
// Look, if record is "online" or in a versionized branch, then delete directly.
if ($res>0) {
$tcemainObj->deleteEl($table, $id);
} else {
$tcemainObj->newlog('Stage of root point did not allow for deletion',1);
}
} elseif ((int)$record['t3ver_state']===3) {
// Placeholders for moving operations are deletable directly.
// Get record which its a placeholder for and reset the t3ver_state of that:
if ($wsRec = t3lib_BEfunc::getWorkspaceVersionOfRecord($record['t3ver_wsid'], $table, $record['t3ver_move_id'], 'uid')) {
// Clear the state flag of the workspace version of the record
// Setting placeholder state value for version (so it can know it is currently a new version...)
$updateFields = array(
't3ver_state' => 0
);
$GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid=' . intval($wsRec['uid']), $updateFields);
}
$tcemainObj->deleteEl($table, $id);
} else {
// Otherwise, try to delete by versioning:
$tcemainObj->versionizeRecord($table, $id, 'DELETED!', TRUE);
$tcemainObj->deleteL10nOverlayRecords($table, $id);
}
}
}
/**
* hook for t3lib_TCEmain::moveRecord that cares about moving records that
* are *not* in the live workspace
* @param $table the table
*/
public function moveRecord($table, $uid, $destPid, $propArr, $moveRec, $resolvedPid, &$recordWasMoved, &$tcemainObj) {
global $TCA;
// Only do something in Draft workspace
if ($tcemainObj->BE_USER->workspace !== 0) {
$recordWasMoved = TRUE;
// Get workspace version of the source record, if any:
$WSversion = t3lib_BEfunc::getWorkspaceVersionOfRecord($tcemainObj->BE_USER->workspace, $table, $uid, 'uid,t3ver_oid');
// If no version exists and versioningWS is in version 2, a new placeholder is made automatically:
if (!$WSversion['uid'] && (int)$TCA[$table]['ctrl']['versioningWS']>=2 && (int)$moveRec['t3ver_state']!=3) {
$tcemainObj->versionizeRecord($table, $uid, 'Placeholder version for moving record');
$WSversion = t3lib_BEfunc::getWorkspaceVersionOfRecord($tcemainObj->BE_USER->workspace, $table, $uid, 'uid,t3ver_oid'); // Will not create new versions in live workspace though...
}
// Check workspace permissions:
$workspaceAccessBlocked = array();
// Element was in "New/Deleted/Moved" so it can be moved...
$recIsNewVersion = (int)$moveRec['t3ver_state']>0;
$destRes = $tcemainObj->BE_USER->workspaceAllowLiveRecordsInPID($resolvedPid, $table);
$canMoveRecord = $recIsNewVersion || (int)$TCA[$table]['ctrl']['versioningWS'] >= 2;
// Workspace source check:
if (!$recIsNewVersion) {
$errorCode = $tcemainObj->BE_USER->workspaceCannotEditRecord($table, $WSversion['uid'] ? $WSversion['uid'] : $uid);
if ($errorCode) {
$workspaceAccessBlocked['src1'] = 'Record could not be edited in workspace: ' . $errorCode . ' ';
} elseif (!$canMoveRecord && $tcemainObj->BE_USER->workspaceAllowLiveRecordsInPID($moveRec['pid'], $table) <= 0) {
$workspaceAccessBlocked['src2'] = 'Could not remove record from table "' . $table . '" from its page "'.$moveRec['pid'].'" ';
}
}
// Workspace destination check:
// All records can be inserted if $destRes is greater than zero.
// Only new versions can be inserted if $destRes is false.
// NO RECORDS can be inserted if $destRes is negative which indicates a stage
// not allowed for use. If "versioningWS" is version 2, moving can take place of versions.
if (!($destRes > 0 || ($canMoveRecord && !$destRes))) {
$workspaceAccessBlocked['dest1'] = 'Could not insert record from table "' . $table . '" in destination PID "' . $resolvedPid . '" ';
} elseif ($destRes == 1 && $WSversion['uid']) {
$workspaceAccessBlocked['dest2'] = 'Could not insert other versions in destination PID ';
}
if (!count($workspaceAccessBlocked)) {
// If the move operation is done on a versioned record, which is
// NOT new/deleted placeholder and versioningWS is in version 2, then...
if ($WSversion['uid'] && !$recIsNewVersion && (int)$TCA[$table]['ctrl']['versioningWS'] >= 2) {
$this->moveRecord_wsPlaceholders($table, $uid, $destPid, $WSversion['uid'], $tcemainObj);
} else {
// moving not needed, just behave like in live workspace
$recordWasMoved = FALSE;
}
} else {
$tcemainObj->newlog("Move attempt failed due to workspace restrictions: " . implode(' // ', $workspaceAccessBlocked), 1);
}
}
}
/****************************
***** Notifications ******
****************************/
/**
* Send an email notification to users in workspace
*
* @param array Workspace access array (from t3lib_userauthgroup::checkWorkspace())
* @param integer New Stage number: 0 = editing, 1= just ready for review, 10 = ready for publication, -1 = rejected!
* @param string Table name of element (or list of element names if $id is zero)
* @param integer Record uid of element (if zero, then $table is used as reference to element(s) alone)
* @param string User comment sent along with action
* @return void
*/
protected function notifyStageChange($stat, $stageId, $table, $id, $comment, $tcemainObj) {
$workspaceRec = t3lib_BEfunc::getRecord('sys_workspace', $stat['uid']);
// So, if $id is not set, then $table is taken to be the complete element name!
$elementName = $id ? $table . ':' . $id : $table;
if (is_array($workspaceRec)) {
// Compile label:
switch ((int)$stageId) {
case 1:
$newStage = 'Ready for review';
break;
case 10:
$newStage = 'Ready for publishing';
break;
case -1:
$newStage = 'Element was rejected!';
break;
case 0:
$newStage = 'Rejected element was noticed and edited';
break;
default:
$newStage = 'Unknown state change!?';
break;
}
// Compile list of recipients:
$emails = array();
switch((int)$stat['stagechg_notification']) {
case 1:
switch((int)$stageId) {
case 1:
$emails = $this->getEmailsForStageChangeNotification($workspaceRec['reviewers']);
break;
case 10:
$emails = $this->getEmailsForStageChangeNotification($workspaceRec['adminusers'], TRUE);
break;
case -1:
# $emails = $this->getEmailsForStageChangeNotification($workspaceRec['reviewers']);
# $emails = array_merge($emails,$this->getEmailsForStageChangeNotification($workspaceRec['members']));
// List of elements to reject:
$allElements = explode(',', $elementName);
// Traverse them, and find the history of each
foreach ($allElements as $elRef) {
list($eTable, $eUid) = explode(':', $elRef);
$rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
'log_data,tstamp,userid',
'sys_log',
'action=6 and details_nr=30
AND tablename=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($eTable, 'sys_log') . '
AND recuid=' . intval($eUid),
'',
'uid DESC'
);
// Find all implicated since the last stage-raise from editing to review:
foreach ($rows as $dat) {
$data = unserialize($dat['log_data']);
$emails = array_merge($emails, $this->getEmailsForStageChangeNotification($dat['userid'], TRUE));
if ($data['stage'] == 1) {
break;
}
}
}
break;
case 0:
$emails = $this->getEmailsForStageChangeNotification($workspaceRec['members']);
break;
default:
$emails = $this->getEmailsForStageChangeNotification($workspaceRec['adminusers'], TRUE);
break;
}
break;
case 10:
$emails = $this->getEmailsForStageChangeNotification($workspaceRec['adminusers'], TRUE);
$emails = array_merge($emails, $this->getEmailsForStageChangeNotification($workspaceRec['reviewers']));
$emails = array_merge($emails, $this->getEmailsForStageChangeNotification($workspaceRec['members']));
break;
}
$emails = array_unique($emails);
// Path to record is found:
list($eTable,$eUid) = explode(':', $elementName);
$eUid = intval($eUid);
$rr = t3lib_BEfunc::getRecord($eTable, $eUid);
$recTitle = t3lib_BEfunc::getRecordTitle($eTable, $rr);
if ($eTable != 'pages') {
t3lib_BEfunc::fixVersioningPid($eTable, $rr);
$eUid = $rr['pid'];
}
$path = t3lib_BEfunc::getRecordPath($eUid, '', 20);
// ALternative messages:
$TSConfig = $tcemainObj->getTCEMAIN_TSconfig($eUid);
$body = trim($TSConfig['notificationEmail_body']) ? trim($TSConfig['notificationEmail_body']) : '
At the TYPO3 site "%s" (%s)
in workspace "%s" (#%s)
the stage has changed for the element(s) "%11$s" (%s) at location "%10$s" in the page tree:
==> %s
User Comment:
"%s"
State was change by %s (username: %s)
';
$subject = trim($TSConfig['notificationEmail_subject']) ? trim($TSConfig['notificationEmail_subject']) : 'TYPO3 Workspace Note: Stage Change for %s';
// Send email:
if (count($emails)) {
$message = sprintf($body,
$GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'],
t3lib_div::getIndpEnv('TYPO3_SITE_URL').TYPO3_mainDir,
$workspaceRec['title'],
$workspaceRec['uid'],
$elementName,
$newStage,
$comment,
$this->BE_USER->user['realName'],
$this->BE_USER->user['username'],
$path,
$recTitle);
t3lib_div::plainMailEncoded(
implode(',', $emails),
sprintf($subject, $elementName),
trim($message)
);
$tcemainObj->newlog2('Notification email for stage change was sent to "' . implode(', ', $emails) . '"', $table, $id);
}
}
}
/**
* Return emails addresses of be_users from input list.
* previously called notifyStageChange_getEmails() in tcemain
*
* @param string List of backend users, on the form "be_users_10,be_users_2" or "10,2" in case noTablePrefix is set.
* @param boolean If set, the input list are integers and not strings.
* @return array Array of emails
*/
protected function getEmailsForStageChangeNotification($listOfUsers, $noTablePrefix = FALSE) {
$users = t3lib_div::trimExplode(',', $listOfUsers, 1);
$emails = array();
foreach ($users as $userIdent) {
if ($noTablePrefix) {
$id = intval($userIdent);
} else {
list($table, $id) = t3lib_div::revExplode('_', $userIdent, 2);
}
if ($table === 'be_users' || $noTablePrefix) {
if ($userRecord = t3lib_BEfunc::getRecord('be_users', $id, 'email')) {
if (strlen(trim($userRecord['email']))) {
$emails[$id] = $userRecord['email'];
}
}
}
}
return $emails;
}
/****************************
***** Stage Changes ******
****************************/
/**
* Setting stage of record
*
* @param string Table name
* @param integer Record UID
* @param integer Stage ID to set
* @param string Comment that goes into log
* @param boolean Accumulate state changes in memory for compiled notification email?
* @return void
*/
protected function version_setStage($table, $id, $stageId, $comment = '', $notificationEmailInfo = FALSE, $tcemainObj) {
if ($errorCode = $tcemainObj->BE_USER->workspaceCannotEditOfflineVersion($table, $id)) {
$tcemainObj->newlog('Attempt to set stage for record failed: ' . $errorCode, 1);
} elseif ($tcemainObj->checkRecordUpdateAccess($table, $id)) {
$record = t3lib_BEfunc::getRecord($table, $id);
$stat = $tcemainObj->BE_USER->checkWorkspace($record['t3ver_wsid']);
if (t3lib_div::inList('admin,online,offline,reviewer,owner', $stat['_ACCESS']) || ($stageId <= 1 && $stat['_ACCESS'] === 'member')) {
// Set stage of record:
$updateData = array(
't3ver_stage' => $stageId
);
$GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid=' . intval($id), $updateData);
$tcemainObj->newlog2('Stage for record was changed to ' . $stageId . '. Comment was: "' . substr($comment, 0, 100) . '"', $table, $id);
// TEMPORARY, except 6-30 as action/detail number which is observed elsewhere!
$tcemainObj->log($table, $id, 6, 0, 0, 'Stage raised...', 30, array('comment' => $comment, 'stage' => $stageId));
if ((int)$stat['stagechg_notification'] > 0) {
if ($notificationEmailInfo) {
$this->notificationEmailInfo[$stat['uid'] . ':' . $stageId . ':' . $comment]['shared'] = array($stat, $stageId, $comment);
$this->notificationEmailInfo[$stat['uid'] . ':' . $stageId . ':' . $comment]['elements'][] = $table . ':' . $id;
} else {
$this->notifyStageChange($stat, $stageId, $table, $id, $comment, $tcemainObj);
}
}
} else $tcemainObj->newlog('The member user tried to set a stage value "' . $stageId . '" that was not allowed', 1);
} else $tcemainObj->newlog('Attempt to set stage for record failed because you do not have edit access', 1);
}
/*****************************
***** CMD versioning ******
*****************************/
/**
* Creates a new version of a page including content and possible subpages.
*
* @param integer Page uid to create new version of.
* @param string Version label
* @param integer Indicating "treeLevel" - "page" (0) or "branch" (>=1) ["element" type must call versionizeRecord() directly]
* @return void
* @see copyPages()
*/
protected function versionizePages($uid, $label, $versionizeTree, &$tcemainObj) {
global $TCA;
$uid = intval($uid);
// returns the branch
$brExist = $tcemainObj->doesBranchExist('', $uid, $tcemainObj->pMap['show'], 1);
// Checks if we had permissions
if ($brExist != -1) {
// Make list of tables that should come along with a new version of the page:
$verTablesArray = array();
$allTables = array_keys($TCA);
foreach ($allTables as $tableName) {
if ($tableName != 'pages' && ($versionizeTree > 0 || $TCA[$tableName]['ctrl']['versioning_followPages'])) {
$verTablesArray[] = $tableName;
}
}
// Begin to copy pages if we're allowed to:
if ($tcemainObj->BE_USER->workspaceVersioningTypeAccess($versionizeTree)) {
// Versionize this page:
$theNewRootID = $tcemainObj->versionizeRecord('pages', $uid, $label, FALSE, $versionizeTree);
if ($theNewRootID) {
$tcemainObj->rawCopyPageContent($uid, $theNewRootID, $verTablesArray, $tcemainObj);
// If we're going to copy recursively...:
if ($versionizeTree > 0) {
// Get ALL subpages to copy (read permissions respected - they should NOT be...):
$CPtable = $tcemainObj->int_pageTreeInfo(array(), $uid, intval($versionizeTree), $theNewRootID);
// Now copying the subpages
foreach ($CPtable as $thePageUid => $thePagePid) {
$newPid = $tcemainObj->copyMappingArray['pages'][$thePagePid];
if (isset($newPid)) {
$theNewRootID = $tcemainObj->copyRecord_raw('pages', $thePageUid, $newPid);
$tcemainObj->rawCopyPageContent($thePageUid, $theNewRootID, $verTablesArray, $tcemainObj);
} else {
$tcemainObj->newlog('Something went wrong during copying branch (for versioning)', 1);
break;
}
}
} // else the page was not copied. Too bad...
} else $tcemainObj->newlog('The root version could not be created!',1);
} else $tcemainObj->newlog('Versioning type "'.$versionizeTree.'" was not allowed in workspace',1);
} else $tcemainObj->newlog('Could not read all subpages to versionize.',1);
}
/**
* Swapping versions of a record
* Version from archive (future/past, called "swap version") will get the uid of the "t3ver_oid", the official element with uid = "t3ver_oid" will get the new versions old uid. PIDs are swapped also
*
* @param string Table name
* @param integer UID of the online record to swap
* @param integer UID of the archived version to swap with!
* @param boolean If set, swaps online into workspace instead of publishing out of workspace.
* @return void
*/
protected function version_swap($table, $id, $swapWith, $swapIntoWS=0, &$tcemainObj) {
global $TCA;
// First, check if we may actually edit the online record
if ($tcemainObj->checkRecordUpdateAccess($table, $id)) {
// Select the two versions:
$curVersion = t3lib_BEfunc::getRecord($table, $id, '*');
$swapVersion = t3lib_BEfunc::getRecord($table, $swapWith, '*');
$movePlh = array();
$movePlhID = 0;
if (is_array($curVersion) && is_array($swapVersion)) {
if ($tcemainObj->BE_USER->workspacePublishAccess($swapVersion['t3ver_wsid'])) {
$wsAccess = $tcemainObj->BE_USER->checkWorkspace($swapVersion['t3ver_wsid']);
if ($swapVersion['t3ver_wsid'] <= 0 || !($wsAccess['publish_access'] & 1) || (int)$swapVersion['t3ver_stage'] === 10) {
if ($tcemainObj->doesRecordExist($table,$swapWith,'show') && $tcemainObj->checkRecordUpdateAccess($table,$swapWith)) {
if (!$swapIntoWS || $tcemainObj->BE_USER->workspaceSwapAccess()) {
// Check if the swapWith record really IS a version of the original!
if ((int)$swapVersion['pid'] == -1 && (int)$curVersion['pid'] >= 0 && !strcmp($swapVersion['t3ver_oid'], $id)) {
// Lock file name:
$lockFileName = PATH_site.'typo3temp/swap_locking/' . $table . ':' . $id . '.ser';
if (!@is_file($lockFileName)) {
// Write lock-file:
t3lib_div::writeFileToTypo3tempDir($lockFileName, serialize(array(
'tstamp' => $GLOBALS['EXEC_TIME'],
'user' => $tcemainObj->BE_USER->user['username'],
'curVersion' => $curVersion,
'swapVersion' => $swapVersion
)));
// Find fields to keep
$keepFields = $tcemainObj->getUniqueFields($table);
if ($TCA[$table]['ctrl']['sortby']) {
$keepFields[] = $TCA[$table]['ctrl']['sortby'];
}
// l10n-fields must be kept otherwise the localization
// will be lost during the publishing
if (!isset($TCA[$table]['ctrl']['transOrigPointerTable']) && $TCA[$table]['ctrl']['transOrigPointerField']) {
$keepFields[] = $TCA[$table]['ctrl']['transOrigPointerField'];
}
// Swap "keepfields"
foreach ($keepFields as $fN) {
$tmp = $swapVersion[$fN];
$swapVersion[$fN] = $curVersion[$fN];
$curVersion[$fN] = $tmp;
}
// Preserve states:
$t3ver_state = array();
$t3ver_state['swapVersion'] = $swapVersion['t3ver_state'];
$t3ver_state['curVersion'] = $curVersion['t3ver_state'];
// Modify offline version to become online:
$tmp_wsid = $swapVersion['t3ver_wsid'];
// Set pid for ONLINE
$swapVersion['pid'] = intval($curVersion['pid']);
// We clear this because t3ver_oid only make sense for offline versions
// and we want to prevent unintentional misuse of this
// value for online records.
$swapVersion['t3ver_oid'] = 0;
// In case of swapping and the offline record has a state
// (like 2 or 4 for deleting or move-pointer) we set the
// current workspace ID so the record is not deselected
// in the interface by t3lib_BEfunc::versioningPlaceholderClause()
$swapVersion['t3ver_wsid'] = 0;
if ($swapIntoWS) {
if ($t3ver_state['swapVersion'] > 0) {
$swapVersion['t3ver_wsid'] = $tcemainObj->BE_USER->workspace;
} else {
$swapVersion['t3ver_wsid'] = intval($curVersion['t3ver_wsid']);
}
}
$swapVersion['t3ver_tstamp'] = $GLOBALS['EXEC_TIME'];
$swapVersion['t3ver_stage'] = 0;
if (!$swapIntoWS) {
$swapVersion['t3ver_state'] = 0;
}
// Moving element.
if ((int)$TCA[$table]['ctrl']['versioningWS']>=2) { // && $t3ver_state['swapVersion']==4 // Maybe we don't need this?
if ($plhRec = t3lib_BEfunc::getMovePlaceholder($table, $id, 't3ver_state,pid,uid' . ($TCA[$table]['ctrl']['sortby'] ? ',' . $TCA[$table]['ctrl']['sortby'] : ''))) {
$movePlhID = $plhRec['uid'];
$movePlh['pid'] = $swapVersion['pid'];
$swapVersion['pid'] = intval($plhRec['pid']);
$curVersion['t3ver_state'] = intval($swapVersion['t3ver_state']);
$swapVersion['t3ver_state'] = 0;
if ($TCA[$table]['ctrl']['sortby']) {
// sortby is a "keepFields" which is why this will work...
$movePlh[$TCA[$table]['ctrl']['sortby']] = $swapVersion[$TCA[$table]['ctrl']['sortby']];
$swapVersion[$TCA[$table]['ctrl']['sortby']] = $plhRec[$TCA[$table]['ctrl']['sortby']];
}
}
}
// Take care of relations in each field (e.g. IRRE):
if (is_array($GLOBALS['TCA'][$table]['columns'])) {
foreach ($GLOBALS['TCA'][$table]['columns'] as $field => $fieldConf) {
$this->version_swap_procBasedOnFieldType(
$table, $field, $fieldConf['config'], $curVersion, $swapVersion, $tcemainObj
);
}
}
unset($swapVersion['uid']);
// Modify online version to become offline:
unset($curVersion['uid']);
// Set pid for OFFLINE
$curVersion['pid'] = -1;
$curVersion['t3ver_oid'] = intval($id);
$curVersion['t3ver_wsid'] = ($swapIntoWS ? intval($tmp_wsid) : 0);
$curVersion['t3ver_tstamp'] = $GLOBALS['EXEC_TIME'];
$curVersion['t3ver_count'] = $curVersion['t3ver_count']+1; // Increment lifecycle counter
$curVersion['t3ver_stage'] = 0;
if (!$swapIntoWS) {
$curVersion['t3ver_state'] = 0;
}
// Keeping the swapmode state
if ($table === 'pages') {
$curVersion['t3ver_swapmode'] = $swapVersion['t3ver_swapmode'];
}
// Registering and swapping MM relations in current and swap records:
$tcemainObj->version_remapMMForVersionSwap($table, $id, $swapWith);
// Generating proper history data to prepare logging
$tcemainObj->compareFieldArrayWithCurrentAndUnset($table, $id, $swapVersion);
$tcemainObj->compareFieldArrayWithCurrentAndUnset($table, $swapWith, $curVersion);
// Execute swapping:
$sqlErrors = array();
$GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid=' . intval($id), $swapVersion);
if ($GLOBALS['TYPO3_DB']->sql_error()) {
$sqlErrors[] = $GLOBALS['TYPO3_DB']->sql_error();
} else {
$GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid=' . intval($swapWith), $curVersion);
if ($GLOBALS['TYPO3_DB']->sql_error()) {
$sqlErrors[] = $GLOBALS['TYPO3_DB']->sql_error();
} else {
unlink($lockFileName);
}
}
if (!count($sqlErrors)) {
// If a moving operation took place...:
if ($movePlhID) {
// Remove, if normal publishing:
if (!$swapIntoWS) {
// For delete + completely delete!
$tcemainObj->deleteEl($table, $movePlhID, TRUE, TRUE);
} else {
// Otherwise update the movePlaceholder:
$GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid=' . intval($movePlhID), $movePlh);
$tcemainObj->updateRefIndex($table, $movePlhID);
}
}
// Checking for delete:
// Delete only if new/deleted placeholders are there.
if (!$swapIntoWS && ((int)$t3ver_state['swapVersion'] === 1 || (int)$t3ver_state['swapVersion'] === 2)) {
// Force delete
$tcemainObj->deleteEl($table, $id, TRUE);
}
$tcemainObj->newlog2(($swapIntoWS ? 'Swapping' : 'Publishing') . ' successful for table "' . $table . '" uid ' . $id . '=>' . $swapWith, $table, $id, $swapVersion['pid']);
// Update reference index of the live record:
$tcemainObj->updateRefIndex($table, $id);
// Set log entry for live record:
$propArr = $tcemainObj->getRecordPropertiesFromRow($table, $swapVersion);
if ($propArr['_ORIG_pid'] == -1) {
$label = $GLOBALS['LANG']->sL ('LLL:EXT:lang/locallang_tcemain.xml:version_swap.offline_record_updated');
} else {
$label = $GLOBALS['LANG']->sL ('LLL:EXT:lang/locallang_tcemain.xml:version_swap.online_record_updated');
}
$theLogId = $tcemainObj->log($table, $id, 2, $propArr['pid'], 0, $label , 10, array($propArr['header'], $table . ':' . $id), $propArr['event_pid']);
$tcemainObj->setHistory($table, $id, $theLogId);
// Update reference index of the offline record:
$tcemainObj->updateRefIndex($table, $swapWith);
// Set log entry for offline record:
$propArr = $tcemainObj->getRecordPropertiesFromRow($table, $curVersion);
if ($propArr['_ORIG_pid'] == -1) {
$label = $GLOBALS['LANG']->sL ('LLL:EXT:lang/locallang_tcemain.xml:version_swap.offline_record_updated');
} else {
$label = $GLOBALS['LANG']->sL ('LLL:EXT:lang/locallang_tcemain.xml:version_swap.online_record_updated');
}
$theLogId = $tcemainObj->log($table, $swapWith, 2, $propArr['pid'], 0, $label, 10, array($propArr['header'], $table . ':' . $swapWith), $propArr['event_pid']);
$tcemainObj->setHistory($table, $swapWith, $theLogId);
// SWAPPING pids for subrecords:
if ($table=='pages' && $swapVersion['t3ver_swapmode'] >= 0) {
// Collect table names that should be copied along with the tables:
foreach ($TCA as $tN => $tCfg) {
// For "Branch" publishing swap ALL,
// otherwise for "page" publishing, swap only "versioning_followPages" tables
if ($swapVersion['t3ver_swapmode'] > 0 || $TCA[$tN]['ctrl']['versioning_followPages']) {
$temporaryPid = -($id+1000000);
$GLOBALS['TYPO3_DB']->exec_UPDATEquery($tN, 'pid=' . intval($id), array('pid' => $temporaryPid));
if ($GLOBALS['TYPO3_DB']->sql_error()) {
$sqlErrors[] = $GLOBALS['TYPO3_DB']->sql_error();
}
$GLOBALS['TYPO3_DB']->exec_UPDATEquery($tN, 'pid=' . intval($swapWith), array('pid' => $id));
if ($GLOBALS['TYPO3_DB']->sql_error()) {
$sqlErrors[] = $GLOBALS['TYPO3_DB']->sql_error();
}
$GLOBALS['TYPO3_DB']->exec_UPDATEquery($tN, 'pid=' . intval($temporaryPid), array('pid' => $swapWith));
if ($GLOBALS['TYPO3_DB']->sql_error()) {
$sqlErrors[] = $GLOBALS['TYPO3_DB']->sql_error();
}
if (count($sqlErrors)) {
$tcemainObj->newlog('During Swapping: SQL errors happened: ' . implode('; ', $sqlErrors), 2);
}
}
}
}
// Clear cache:
$tcemainObj->clear_cache($table, $id);
// Checking for "new-placeholder" and if found, delete it (BUT FIRST after swapping!):
if (!$swapIntoWS && $t3ver_state['curVersion']>0) {
// For delete + completely delete!
$tcemainObj->deleteEl($table, $swapWith, TRUE, TRUE);
}
} else $tcemainObj->newlog('During Swapping: SQL errors happened: ' . implode('; ', $sqlErrors), 2);
} else $tcemainObj->newlog('A swapping lock file was present. Either another swap process is already running or a previous swap process failed. Ask your administrator to handle the situation.', 2);
} else $tcemainObj->newlog('In swap version, either pid was not -1 or the t3ver_oid didn\'t match the id of the online version as it must!', 2);
} else $tcemainObj->newlog('Workspace #' . $swapVersion['t3ver_wsid'] . ' does not support swapping.', 1);
} else $tcemainObj->newlog('You cannot publish a record you do not have edit and show permissions for', 1);
} else $tcemainObj->newlog('Records in workspace #' . $swapVersion['t3ver_wsid'] . ' can only be published when in "Publish" stage.', 1);
} else $tcemainObj->newlog('User could not publish records from workspace #' . $swapVersion['t3ver_wsid'], 1);
} else $tcemainObj->newlog('Error: Either online or swap version could not be selected!', 2);
} else $tcemainObj->newlog('Error: You cannot swap versions for a record you do not have access to edit!', 1);
}
/**
* Update relations on version/workspace swapping.
*
* @param string $table: Record Table
* @param string $field: Record field
* @param array $conf: TCA configuration of current field
* @param string $curVersion: Reference to the current (original) record
* @param string $swapVersion: Reference to the record (workspace/versionized) to publish in or swap with
* @return void
*/
protected function version_swap_procBasedOnFieldType($table, $field, $conf, &$curVersion, &$swapVersion, $tcemainObj) {
$inlineType = $tcemainObj->getInlineFieldType($conf);
// Process pointer fields on normalized database:
if ($inlineType == 'field') {
// Read relations that point to the current record (e.g. live record):
$dbAnalysisCur = t3lib_div::makeInstance('t3lib_loadDBGroup');
$dbAnalysisCur->start('', $conf['foreign_table'], '', $curVersion['uid'], $table, $conf);
// Read relations that point to the record to be swapped with e.g. draft record):
$dbAnalysisSwap = t3lib_div::makeInstance('t3lib_loadDBGroup');
$dbAnalysisSwap->start('', $conf['foreign_table'], '', $swapVersion['uid'], $table, $conf);
// Update relations for both (workspace/versioning) sites:
$dbAnalysisCur->writeForeignField($conf, $curVersion['uid'], $swapVersion['uid']);
$dbAnalysisSwap->writeForeignField($conf, $swapVersion['uid'], $curVersion['uid']);
// Swap field values (CSV):
// BUT: These values will be swapped back in the next steps, when the *CHILD RECORD ITSELF* is swapped!
} elseif ($inlineType == 'list') {
$tempValue = $curVersion[$field];
$curVersion[$field] = $swapVersion[$field];
$swapVersion[$field] = $tempValue;
}
}
/**
* Release version from this workspace (and into "Live" workspace but as an offline version).
*
* @param string Table name
* @param integer Record UID
* @param boolean If set, will completely delete element
* @return void
*/
protected function version_clearWSID($table, $id, $flush = FALSE, &$tcemainObj) {
global $TCA;
if ($errorCode = $tcemainObj->BE_USER->workspaceCannotEditOfflineVersion($table, $id)) {
$tcemainObj->newlog('Attempt to reset workspace for record failed: ' . $errorCode, 1);
} elseif ($tcemainObj->checkRecordUpdateAccess($table, $id)) {
if ($liveRec = t3lib_BEfunc::getLiveVersionOfRecord($table, $id, 'uid,t3ver_state')) {
// Clear workspace ID:
$updateData = array(
't3ver_wsid' => 0
);
$GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid=' . intval($id), $updateData);
// Clear workspace ID for live version AND DELETE IT as well because it is a new record!
if ((int) $liveRec['t3ver_state'] == 1 || (int) $liveRec['t3ver_state'] == 2) {
$GLOBALS['TYPO3_DB']->exec_UPDATEquery($table,'uid=' . intval($liveRec['uid']), $updateData);
// THIS assumes that the record was placeholder ONLY for ONE record (namely $id)
$tcemainObj->deleteEl($table, $liveRec['uid'], TRUE);
}
// If "deleted" flag is set for the version that got released
// it doesn't make sense to keep that "placeholder" anymore and we delete it completly.
$wsRec = t3lib_BEfunc::getRecord($table, $id);
if ($flush || ((int) $wsRec['t3ver_state'] == 1 || (int) $wsRec['t3ver_state'] == 2)) {
$tcemainObj->deleteEl($table, $id, TRUE, TRUE);
}
// Remove the move-placeholder if found for live record.
if ((int)$TCA[$table]['ctrl']['versioningWS'] >= 2) {
if ($plhRec = t3lib_BEfunc::getMovePlaceholder($table, $liveRec['uid'], 'uid')) {
$tcemainObj->deleteEl($table, $plhRec['uid'], TRUE, TRUE);
}
}
}
} else $tcemainObj->newlog('Attempt to reset workspace for record failed because you do not have edit access',1);
}
/*******************************
***** helper functions ******
*******************************/
/**
* Copies all records from tables in $copyTablesArray from page with $old_pid to page with $new_pid
* Uses raw-copy for the operation (meant for versioning!)
*
* @param integer Current page id.
* @param integer New page id
* @param array Array of tables from which to copy
* @return void
* @see versionizePages()
*/
protected function rawCopyPageContent($oldPageId, $newPageId, $copyTablesArray, &$tcemainObj) {
global $TCA;
if ($newPageId) {
foreach ($copyTablesArray as $table) {
// all records under the page is copied.
if ($table && is_array($TCA[$table]) && $table != 'pages') {
$mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
'uid',
$table,
'pid=' . intval($oldPageId) . $tcemainObj->deleteClause($table)
);
while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres)) {
// Check, if this record has already been copied by a parent record as relation:
if (!$this->copyMappingArray[$table][$row['uid']]) {
// Copying each of the underlying records (method RAW)
$tcemainObj->copyRecord_raw($table, $row['uid'], $newPageId);
}
}
$GLOBALS['TYPO3_DB']->sql_free_result($mres);
}
}
}
}
/**
* Finds all elements for swapping versions in workspace
*
* @param string $table Table name of the original element to swap
* @param int $id UID of the original element to swap (online)
* @param int $offlineId As above but offline
* @return array Element data. Key is table name, values are array with first element as online UID, second - offline UID
*/
protected function findPageElementsForVersionSwap($table, $id, $offlineId) {
global $TCA;
$rec = t3lib_BEfunc::getRecord($table, $offlineId, 't3ver_wsid');
$workspaceId = $rec['t3ver_wsid'];
$elementData = array();
if ($workspaceId != 0) {
// Get page UID for LIVE and workspace
if ($table != 'pages') {
$rec = t3lib_BEfunc::getRecord($table, $id, 'pid');
$pageId = $rec['pid'];
$rec = t3lib_BEfunc::getRecord('pages', $pageId);
t3lib_BEfunc::workspaceOL('pages', $rec, $workspaceId);
$offlinePageId = $rec['_ORIG_uid'];
} else {
$pageId = $id;
$offlinePageId = $offlineId;
}
// Traversing all tables supporting versioning:
foreach ($TCA as $table => $cfg) {
if ($TCA[$table]['ctrl']['versioningWS'] && $table != 'pages') {
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('A.uid AS offlineUid, B.uid AS uid',
$table . ' A,' . $table . ' B',
'A.pid=-1 AND B.pid=' . $pageId . ' AND A.t3ver_wsid=' . $workspaceId .
' AND B.uid=A.t3ver_oid' .
t3lib_BEfunc::deleteClause($table, 'A') . t3lib_BEfunc::deleteClause($table, 'B'));
while (FALSE != ($row = $GLOBALS['TYPO3_DB']->sql_fetch_row($res))) {
$elementData[$table][] = array($row[1], $row[0]);
}
$GLOBALS['TYPO3_DB']->sql_free_result($res);
}
}
if ($offlinePageId && $offlinePageId != $pageId) {
$elementData['pages'][] = array($pageId, $offlinePageId);
}
}
return $elementData;
}
/**
* Searches for all elements from all tables on the given pages in the same workspace.
*
* @param array $pageIdList List of PIDs to search
* @param int $workspaceId Workspace ID
* @param array $elementList List of found elements. Key is table name, value is array of element UIDs
* @return void
*/
protected function findPageElementsForVersionStageChange($pageIdList, $workspaceId, &$elementList) {
global $TCA;
if ($workspaceId != 0) {
// Traversing all tables supporting versioning:
foreach ($TCA as $table => $cfg) {
if ($TCA[$table]['ctrl']['versioningWS'] && $table != 'pages') {
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('DISTINCT A.uid',
$table . ' A,' . $table . ' B',
'A.pid=-1' . // Offline version
' AND A.t3ver_wsid=' . $workspaceId .
' AND B.pid IN (' . implode(',', $pageIdList) . ') AND A.t3ver_oid=B.uid' .
t3lib_BEfunc::deleteClause($table,'A').
t3lib_BEfunc::deleteClause($table,'B')
);
while (FALSE !== ($row = $GLOBALS['TYPO3_DB']->sql_fetch_row($res))) {
$elementList[$table][] = $row[0];
}
$GLOBALS['TYPO3_DB']->sql_free_result($res);
if (is_array($elementList[$table])) {
// Yes, it is possible to get non-unique array even with DISTINCT above!
// It happens because several UIDs are passed in the array already.
$elementList[$table] = array_unique($elementList[$table]);
}
}
}
}
}
/**
* Finds page UIDs for the element from table $table
with UIDs from $idList
*
* @param array $table Table to search
* @param array $idList List of records' UIDs
* @param int $workspaceId Workspace ID. We need this parameter because user can be in LIVE but he still can publisg DRAFT from ws module!
* @param array $pageIdList List of found page UIDs
* @param array $elementList List of found element UIDs. Key is table name, value is list of UIDs
* @return void
*/
protected function findPageIdsForVersionStateChange($table, $idList, $workspaceId, &$pageIdList, &$elementList) {
if ($workspaceId != 0) {
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('DISTINCT B.pid',
$table . ' A,' . $table . ' B',
'A.pid=-1' . // Offline version
' AND A.t3ver_wsid=' . $workspaceId .
' AND A.uid IN (' . implode(',', $idList) . ') AND A.t3ver_oid=B.uid' .
t3lib_BEfunc::deleteClause($table,'A').
t3lib_BEfunc::deleteClause($table,'B')
);
while (FALSE !== ($row = $GLOBALS['TYPO3_DB']->sql_fetch_row($res))) {
$pageIdList[] = $row[0];
// Find ws version
// Note: cannot use t3lib_BEfunc::getRecordWSOL()
// here because it does not accept workspace id!
$rec = t3lib_BEfunc::getRecord('pages', $row[0]);
t3lib_BEfunc::workspaceOL('pages', $rec, $workspaceId);
if ($rec['_ORIG_uid']) {
$elementList['pages'][$row[0]] = $rec['_ORIG_uid'];
}
}
$GLOBALS['TYPO3_DB']->sql_free_result($res);
// The line below is necessary even with DISTINCT
// because several elements can be passed by caller
$pageIdList = array_unique($pageIdList);
}
}
/**
* Finds real page IDs for state change.
*
* @param array $idList List of page UIDs, possibly versioned
* @return void
*/
protected function findRealPageIds(&$idList) {
foreach ($idList as $key => $id) {
$rec = t3lib_BEfunc::getRecord('pages', $id, 't3ver_oid');
if ($rec['t3ver_oid'] > 0) {
$idList[$key] = $rec['t3ver_oid'];
}
}
}
/**
* Creates a move placeholder for workspaces.
* USE ONLY INTERNALLY
* Moving placeholder: Can be done because the system sees it as a placeholder for NEW elements like t3ver_state=1
* Moving original: Will either create the placeholder if it doesn't exist or move existing placeholder in workspace.
*
* @param string Table name to move
* @param integer Record uid to move (online record)
* @param integer Position to move to: $destPid: >=0 then it points to a page-id on which to insert the record (as the first element). <0 then it points to a uid from its own table after which to insert it (works if
* @param integer UID of offline version of online record
* @return void
* @see moveRecord()
*/
protected function moveRecord_wsPlaceholders($table, $uid, $destPid, $wsUid, &$tcemainObj) {
global $TCA;
if ($plh = t3lib_BEfunc::getMovePlaceholder($table, $uid, 'uid')) {
// If already a placeholder exists, move it:
$tcemainObj->moveRecord_raw($table, $plh['uid'], $destPid);
} else {
// First, we create a placeholder record in the Live workspace that
// represents the position to where the record is eventually moved to.
$newVersion_placeholderFieldArray = array();
if ($TCA[$table]['ctrl']['crdate']) {
$newVersion_placeholderFieldArray[$TCA[$table]['ctrl']['crdate']] = $GLOBALS['EXEC_TIME'];
}
if ($TCA[$table]['ctrl']['cruser_id']) {
$newVersion_placeholderFieldArray[$TCA[$table]['ctrl']['cruser_id']] = $tcemainObj->userid;
}
if ($TCA[$table]['ctrl']['tstamp'] && count($fieldArray)) {
$newVersion_placeholderFieldArray[$TCA[$table]['ctrl']['tstamp']] = $GLOBALS['EXEC_TIME'];
}
if ($table == 'pages') {
// Copy page access settings from original page to placeholder
$perms_clause = $tcemainObj->BE_USER->getPagePermsClause(1);
$access = t3lib_BEfunc::readPageAccess($uid, $perms_clause);
$newVersion_placeholderFieldArray['perms_userid'] = $access['perms_userid'];
$newVersion_placeholderFieldArray['perms_groupid'] = $access['perms_groupid'];
$newVersion_placeholderFieldArray['perms_user'] = $access['perms_user'];
$newVersion_placeholderFieldArray['perms_group'] = $access['perms_group'];
$newVersion_placeholderFieldArray['perms_everybody'] = $access['perms_everybody'];
}
$newVersion_placeholderFieldArray['t3ver_label'] = 'MOVE-TO PLACEHOLDER for #' . $uid;
$newVersion_placeholderFieldArray['t3ver_move_id'] = $uid;
// Setting placeholder state value for temporary record
$newVersion_placeholderFieldArray['t3ver_state'] = 3;
// Setting workspace - only so display of place holders can filter out those from other workspaces.
$newVersion_placeholderFieldArray['t3ver_wsid'] = $tcemainObj->BE_USER->workspace;
$newVersion_placeholderFieldArray[$TCA[$table]['ctrl']['label']] = '[MOVE-TO PLACEHOLDER for #' . $uid . ', WS#' . $tcemainObj->BE_USER->workspace . ']';
// moving localized records requires to keep localization-settings for the placeholder too
if (array_key_exists('languageField', $GLOBALS['TCA'][$table]['ctrl']) && array_key_exists('transOrigPointerField', $GLOBALS['TCA'][$table]['ctrl'])) {
$l10nParentRec = t3lib_BEfunc::getRecord($table, $uid);
$newVersion_placeholderFieldArray[$GLOBALS['TCA'][$table]['ctrl']['languageField']] = $l10nParentRec[$GLOBALS['TCA'][$table]['ctrl']['languageField']];
$newVersion_placeholderFieldArray[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] = $l10nParentRec[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']];
unset($l10nParentRec);
}
// Initially, create at root level.
$newVersion_placeholderFieldArray['pid'] = 0;
$id = 'NEW_MOVE_PLH';
// Saving placeholder as 'original'
$tcemainObj->insertDB($table, $id, $newVersion_placeholderFieldArray, FALSE);
// Move the new placeholder from temporary root-level to location:
$tcemainObj->moveRecord_raw($table, $tcemainObj->substNEWwithIDs[$id], $destPid);
// Move the workspace-version of the original to be the version of the move-to-placeholder:
// Setting placeholder state value for version (so it can know it is currently a new version...)
$updateFields = array(
't3ver_state' => 4
);
$GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid=' . intval($wsUid), $updateFields);
}
// Check for the localizations of that element and move them as well
$tcemainObj->moveL10nOverlayRecords($table, $uid, $destPid);
}
}
?>