/** * Processing/Preparing content for copyRecord() function * * @param string Table name * @param integer Record uid * @param string Field name being processed * @param string Input value to be processed. * @param array Record array * @param array TCA field configuration * @param integer Real page id (pid) the record is copied to * @param integer Language ID (from sys_language table) used in the duplicated record * @return mixed Processed value. Normally a string/integer, but can be an array for flexforms! * @access private * @see copyRecord() */ function copyRecord_procBasedOnFieldType($table, $uid, $field, $value, $row, $conf, $realDestPid, $language = 0) { global $TCA; // Process references and files, currently that means only the files, prepending absolute paths (so the TCEmain engine will detect the file as new and one that should be made into a copy) $value = $this->copyRecord_procFilesRefs($conf, $uid, $value); $inlineSubType = $this->getInlineFieldType($conf); // Register if there are references to take care of or MM is used on an inline field (no change to value): if ($this->isReferenceField($conf) || $inlineSubType == 'mm') { $allowedTables = $conf['type'] == 'group' ? $conf['allowed'] : $conf['foreign_table'] . ',' . $conf['neg_foreign_table']; $prependName = $conf['type'] == 'group' ? $conf['prepend_tname'] : $conf['neg_foreign_table']; $localizeReferences = isset($conf['foreign_table']) && t3lib_BEfunc::isTableLocalizable($conf['foreign_table']) && isset($conf['localizeReferencesAtParentLocalization']) && $conf['localizeReferencesAtParentLocalization']; if ($conf['MM'] || $language > 0 && $localizeReferences) { $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup'); /* @var $dbAnalysis t3lib_loadDBGroup */ $dbAnalysis->start($value, $allowedTables, $conf['MM'], $uid, $table, $conf); if (!$conf['MM']) { // Localize referenced records of select fields: foreach ($dbAnalysis->itemArray as $index => $item) { // Since select fields can reference many records, check whether there's already a localization: $recordLocalization = t3lib_BEfunc::getRecordLocalization($item['table'], $item['id'], $language); if (!$recordLocalization) { $dbAnalysis->itemArray[$index]['id'] = $this->localize($item['table'], $item['id'], $language); } else { $dbAnalysis->itemArray[$index]['id'] = $recordLocalization[0]['uid']; } } } $value = implode(',', $dbAnalysis->getValueArray($prependName)); } if ($value) { // Setting the value in this array will notify the remapListedDBRecords() function that this field MAY need references to be corrected $this->registerDBList[$table][$uid][$field] = $value; } // If another inline subtype is used (comma-separated-values or the foreign_field property): } elseif ($inlineSubType !== FALSE) { // Get the localization mode for the current (parent) record (keep|select|all): $localizationMode = t3lib_BEfunc::getInlineLocalizationMode($table, $field); // Localization in mode 'keep', isn't a real localization, but keeps the children of the original parent record: if ($language > 0 && $localizationMode == 'keep') { $value = $inlineSubType == 'field' ? 0 : ''; // Execute copy or localization actions: } else { /* * Fetch the related child records by using t3lib_loadDBGroup: * @var $dbAnalysis t3lib_loadDBGroup */ $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup'); $dbAnalysis->start($value, $conf['foreign_table'], '', $uid, $table, $conf); // Walk through the items, copy them and remember the new id: foreach ($dbAnalysis->itemArray as $k => $v) { // If language is set and differs from original record, this isn't a copy action but a localization of our parent/ancestor: if ($language > 0 && t3lib_BEfunc::isTableLocalizable($table) && $language != $row[$TCA[$table]['ctrl']['languageField']]) { // If children should be localized when the parent gets localized the first time, just do it: if ($localizationMode != FALSE && isset($conf['behaviour']['localizeChildrenAtParentLocalization']) && $conf['behaviour']['localizeChildrenAtParentLocalization']) { $newId = $this->localize($v['table'], $v['id'], $language); } // If no language it set, this is a regular copy action: } else { if (!t3lib_div::testInt($realDestPid)) { $newId = $this->copyRecord($v['table'], $v['id'], -$v['id']); } elseif ($realDestPid == -1 && t3lib_BEfunc::isTableWorkspaceEnabled($v['table'])) { $workspaceVersion = t3lib_BEfunc::getWorkspaceVersionOfRecord($this->BE_USER->workspace, $v['table'], $v['id'], 'uid'); // If workspace version does not exist, create a new one: if ($workspaceVersion === FALSE) { $newId = $this->versionizeRecord($v['table'], $v['id'], 'Auto-created for WS #' . $this->BE_USER->workspace); // If workspace version already exists, use it: } else { $newId = $workspaceVersion['uid']; } } else { $newId = $this->copyRecord_raw($v['table'], $v['id'], $realDestPid); } } // If the current field is set on a page record, update the pid of related child records: if ($table == 'pages') { $this->registerDBPids[$v['table']][$v['id']] = $uid; // If the current field has ancestors that have a field on a page record, update the pid of related child records: } elseif (isset($this->registerDBPids[$table][$uid])) { $this->registerDBPids[$v['table']][$v['id']] = $this->registerDBPids[$table][$uid]; } $dbAnalysis->itemArray[$k]['id'] = $newId; } // Store the new values, we will set up the uids for the subtype later on (exception keep localization from original record): $value = implode(',', $dbAnalysis->getValueArray()); $this->registerDBList[$table][$uid][$field] = $value; } } // For "flex" fieldtypes we need to traverse the structure for two reasons: If there are file references they have to be prepended with absolute paths and if there are database reference they MIGHT need to be remapped (still done in remapListedDBRecords()) if ($conf['type'] == 'flex') { // Get current value array: $dataStructArray = t3lib_BEfunc::getFlexFormDS($conf, $row, $table); $currentValueArray = t3lib_div::xml2array($value); // Traversing the XML structure, processing files: if (is_array($currentValueArray)) { $currentValueArray['data'] = $this->checkValue_flex_procInData($currentValueArray['data'], array(), array(), $dataStructArray, array($table, $uid, $field, $realDestPid), 'copyRecord_flexFormCallBack'); $value = $currentValueArray; // Setting value as an array! -> which means the input will be processed according to the 'flex' type when the new copy is created. } } return $value; }
/** * Write the sorting values to a foreign_table, that has a foreign_field (uid of the parent record) * * @param array $conf: TCA configuration for current field * @param integer $parentUid: The uid of the parent record * @param boolean $updateToUid: Whether to update the foreign field with the $parentUid (on Copy) * @param boolean $skipSorting: Do not update the sorting columns, this could happen for imported values * @return void */ function writeForeignField($conf, $parentUid, $updateToUid = 0, $skipSorting = FALSE) { $c = 0; $foreign_table = $conf['foreign_table']; $foreign_field = $conf['foreign_field']; $symmetric_field = $conf['symmetric_field']; $foreign_table_field = $conf['foreign_table_field']; // if there are table items and we have a proper $parentUid if (t3lib_div::testInt($parentUid) && count($this->tableArray)) { // if updateToUid is not a positive integer, set it to '0', so it will be ignored if (!(t3lib_div::testInt($updateToUid) && $updateToUid > 0)) { $updateToUid = 0; } $considerWorkspaces = $GLOBALS['BE_USER']->workspace !== 0 && t3lib_BEfunc::isTableWorkspaceEnabled($foreign_table); $fields = 'uid,' . $foreign_field; // Consider the symmetric field if defined: if ($symmetric_field) { $fields .= ',' . $symmetric_field; } // Consider workspaces if defined and currently used: if ($considerWorkspaces) { $fields .= ',' . 't3ver_state,t3ver_oid'; } // update all items foreach ($this->itemArray as $val) { $uid = $val['id']; $table = $val['table']; // fetch the current (not overwritten) relation record if we should handle symmetric relations if ($symmetric_field || $considerWorkspaces) { $row = t3lib_BEfunc::getRecord($table, $uid, $fields, '', FALSE); } if ($symmetric_field) { $isOnSymmetricSide = t3lib_loadDBGroup::isOnSymmetricSide($parentUid, $conf, $row); } $updateValues = array(); $workspaceValues = array(); // no update to the uid is requested, so this is the normal behaviour // just update the fields and care about sorting if (!$updateToUid) { // Always add the pointer to the parent uid if ($isOnSymmetricSide) { $updateValues[$symmetric_field] = $parentUid; } else { $updateValues[$foreign_field] = $parentUid; } // if it is configured in TCA also to store the parent table in the child record, just do it if ($foreign_table_field && $this->currentTable) { $updateValues[$foreign_table_field] = $this->currentTable; } // update sorting columns if not to be skipped if (!$skipSorting) { // get the correct sorting field if ($conf['foreign_sortby']) { // specific manual sortby for data handled by this field $sortby = $conf['foreign_sortby']; } elseif ($GLOBALS['TCA'][$foreign_table]['ctrl']['sortby']) { // manual sortby for all table records $sortby = $GLOBALS['TCA'][$foreign_table]['ctrl']['sortby']; } // Apply sorting on the symmetric side (it depends on who created the relation, so what uid is in the symmetric_field): if ($isOnSymmetricSide && isset($conf['symmetric_sortby']) && $conf['symmetric_sortby']) { $sortby = $conf['symmetric_sortby']; // Strip a possible "ORDER BY" in front of the $sortby value: } else { $sortby = $GLOBALS['TYPO3_DB']->stripOrderBy($sortby); } if ($sortby) { $updateValues[$sortby] = $workspaceValues[$sortby] = ++$c; } } // update to a foreign_field/symmetric_field pointer is requested, normally used on record copies // only update the fields, if the old uid is found somewhere - for select fields, TCEmain is doing this already! } else { if ($isOnSymmetricSide) { $updateValues[$symmetric_field] = $updateToUid; } else { $updateValues[$foreign_field] = $updateToUid; } } // Update accordant fields in the database: if (count($updateValues)) { $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid=' . intval($uid), $updateValues); $this->updateRefIndex($table, $uid); } // Update accordant fields in the database for workspaces overlays/placeholders: if (count($workspaceValues) && $considerWorkspaces) { if (isset($row['t3ver_oid']) && $row['t3ver_oid'] && $row['t3ver_state'] == -1) { $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid=' . intval($row['t3ver_oid']), $workspaceValues); } } } } }
/** * Check if record ($table, $uid) is a workspace record * * @param string $table The table the record belongs to * @param integer $uid The record's uid * @return boolean TRUE if the record is in a draft workspace, FALSE if it's a LIVE record */ public static function isDraftRecord($table, $uid) { $isWorkspaceRecord = FALSE; if (t3lib_BEfunc::isTableWorkspaceEnabled($table)) { $record = t3lib_BEfunc::getRecord($table, $uid); if ($record['pid'] == '-1' || $record['t3ver_state'] > 0) { $isWorkspaceRecord = TRUE; } } return $isWorkspaceRecord; }
/** * Flushes elements of a particular workspace to avoid orphan records. * * @param integer $workspaceId The workspace to be flushed * @return void */ protected function flushWorkspaceElements($workspaceId) { $command = array(); foreach ($this->getTcaTables() as $tcaTable) { if (t3lib_BEfunc::isTableWorkspaceEnabled($tcaTable)) { $where = '1=1'; $where .= t3lib_BEfunc::getWorkspaceWhereClause($tcaTable, $workspaceId); $where .= t3lib_BEfunc::deleteClause($tcaTable); $records = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid', $tcaTable, $where, '', '', '', 'uid'); if (is_array($records)) { foreach (array_keys($records) as $recordId) { $command[$tcaTable][$recordId]['version']['action'] = 'flush'; } } } } if (count($command)) { $tceMain = $this->getTceMain(); $tceMain->start(array(), $command); $tceMain->process_cmdmap(); } }