17 use Doctrine\DBAL\DBALException;
18 use Doctrine\DBAL\Driver\Statement;
19 use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
20 use Doctrine\DBAL\Platforms\SqlitePlatform;
21 use Doctrine\DBAL\Platforms\SQLServerPlatform;
22 use Doctrine\DBAL\Types\IntegerType;
23 use Psr\Log\LoggerAwareInterface;
24 use Psr\Log\LoggerAwareTrait;
89 'updateModeL10NdiffData' =>
'Using updateModeL10NdiffData is deprecated and will not be possible anymore in TYPO3 v10.0.',
90 'updateModeL10NdiffDataClear' =>
'Using updateModeL10NdiffDataClear is deprecated and will not be possible anymore in TYPO3 v10.0.',
372 public $pagetreeRefreshFieldsFromPages = [
'pid',
'sorting',
'deleted',
'hidden',
'title',
'doktype',
'is_siteroot',
'fe_group',
'nav_hide',
'nav_title',
'module',
'starttime',
'endtime',
'content_from_pid',
'extendToSubpages'];
421 'user' =>
'show,edit,delete,new,editcontent',
422 'group' =>
'show,edit,new,editcontent',
713 $this->checkStoredRecords = (bool)
$GLOBALS[
'TYPO3_CONF_VARS'][
'BE'][
'checkStoredRecords'];
714 $this->checkStoredRecords_loose = (bool)
$GLOBALS[
'TYPO3_CONF_VARS'][
'BE'][
'checkStoredRecordsLoose'];
735 public function start($data, $cmd, $altUserObject =
null)
738 $this->BE_USER = is_object($altUserObject) ? $altUserObject :
$GLOBALS[
'BE_USER'];
739 $this->userid = $this->BE_USER->user[
'uid'] ?? 0;
740 $this->username = $this->BE_USER->user[
'username'] ??
'';
741 $this->admin = $this->BE_USER->user[
'admin'] ??
false;
742 if ($this->BE_USER->uc[
'recursiveDelete'] ??
false) {
743 $this->deleteTree = 1;
747 $tcaDefaultOverride = $this->BE_USER->getTSConfig()[
'TCAdefaults.'] ??
null;
748 if (is_array($tcaDefaultOverride)) {
768 if (is_array($data)) {
770 $this->datamap = $data;
772 if (is_array($cmd)) {
774 $this->cmdmap = $cmd;
786 if (!is_array($mirror)) {
790 foreach ($mirror as $table => $uid_array) {
791 if (!isset($this->datamap[$table])) {
795 foreach ($uid_array as $id => $uidList) {
796 if (!isset($this->datamap[$table][$id])) {
800 $theIdsInArray = GeneralUtility::trimExplode(
',', $uidList,
true);
801 foreach ($theIdsInArray as $copyToUid) {
802 $this->datamap[$table][$copyToUid] = $this->datamap[$table][$id];
815 if (!is_array($userTS)) {
819 foreach ($userTS as $k => $v) {
820 $k = mb_substr($k, 0, -1);
821 if (!$k || !is_array($v) || !isset(
$GLOBALS[
'TCA'][$k])) {
825 if (is_array($this->defaultValues[$k])) {
826 $this->defaultValues[$k] = array_merge($this->defaultValues[$k], $v);
828 $this->defaultValues[$k] = $v;
850 if (isset($prepopulatedFieldArray[
'pid'])) {
851 $cleanFieldArray[
'pid'] = $prepopulatedFieldArray[
'pid'];
853 $sortColumn =
$GLOBALS[
'TCA'][$table][
'ctrl'][
'sortby'] ??
null;
854 if ($sortColumn !==
null && isset($prepopulatedFieldArray[$sortColumn])) {
855 $cleanFieldArray[$sortColumn] = $prepopulatedFieldArray[$sortColumn];
857 return $cleanFieldArray;
868 if (!is_array($postFiles)) {
873 if ($this->BE_USER->workspace !== 0 && $this->BE_USER->workspaceRec[
'freeze']) {
874 $this->
newlog(
'All editing in this workspace has been frozen!', 1);
877 $subA = reset($postFiles);
878 if (is_array($subA)) {
879 if (is_array($subA[
'name']) && is_array($subA[
'type']) && is_array($subA[
'tmp_name']) && is_array($subA[
'size'])) {
881 $this->uploadedFileArray = [];
883 foreach ($subA as $key => $values) {
887 $this->uploadedFileArray = $subA;
903 if (is_array($inputArr)) {
904 foreach ($inputArr as $key => $value) {
908 $outputArr[$keyToSet] = $inputArr;
933 if (!isset($this->remapStackRecords[$table][$id])) {
934 foreach ($hookObjectsArr as $hookObj) {
935 if (method_exists($hookObj,
'processDatamap_afterDatabaseOperations')) {
936 $hookObj->processDatamap_afterDatabaseOperations($status, $table, $id, $fieldArray, $this);
940 $this->remapStackRecords[$table][$id][
'processDatamap_afterDatabaseOperations'] = [
942 'fieldArray' => $fieldArray,
943 'hookObjectsArr' => $hookObjectsArr
957 if (!isset($this->checkModifyAccessListHookObjects)) {
958 $this->checkModifyAccessListHookObjects = [];
959 foreach (
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
't3lib/class.t3lib_tcemain.php'][
'checkModifyAccessList'] ?? [] as $className) {
960 $hookObject = GeneralUtility::makeInstance($className);
961 if (!$hookObject instanceof DataHandlerCheckModifyAccessListHookInterface) {
962 throw new \UnexpectedValueException($className .
' must implement interface ' . DataHandlerCheckModifyAccessListHookInterface::class, 1251892472);
964 $this->checkModifyAccessListHookObjects[] = $hookObject;
986 $registerDBList = [];
990 if ($this->BE_USER->workspace !== 0 && $this->BE_USER->workspaceRec[
'freeze']) {
991 $this->
newlog(
'All editing in this workspace has been frozen!', 1);
995 $hookObjectsArr = [];
996 foreach (
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
't3lib/class.t3lib_tcemain.php'][
'processDatamapClass'] ?? [] as $className) {
997 $hookObject = GeneralUtility::makeInstance($className);
998 if (method_exists($hookObject,
'processDatamap_beforeStart')) {
999 $hookObject->processDatamap_beforeStart($this);
1001 $hookObjectsArr[] = $hookObject;
1004 $this->datamap = GeneralUtility::makeInstance(SlugEnricher::class)->enrichDataMap($this->datamap);
1007 $orderOfTables = [];
1009 if (isset($this->datamap[
'pages'])) {
1010 $orderOfTables[] =
'pages';
1012 $orderOfTables = array_unique(array_merge($orderOfTables, array_keys($this->datamap)));
1014 foreach ($orderOfTables as $table) {
1021 if (!$modifyAccessList) {
1022 $this->
log($table, 0, 2, 0, 1,
'Attempt to modify table \'%s\' without permission', 1, [$table]);
1024 if (!isset(
$GLOBALS[
'TCA'][$table]) || $this->
tableReadOnly($table) || !is_array($this->datamap[$table]) || !$modifyAccessList) {
1028 if ($this->reverseOrder) {
1029 $this->datamap[$table] = array_reverse($this->datamap[$table], 1);
1034 foreach ($this->datamap[$table] as $id => $incomingFieldArray) {
1035 if (!is_array($incomingFieldArray)) {
1041 foreach ($hookObjectsArr as $hookObj) {
1042 if (method_exists($hookObj,
'processDatamap_preProcessFieldArray')) {
1043 $hookObj->processDatamap_preProcessFieldArray($incomingFieldArray, $table, $id, $this);
1049 $createNewVersion =
false;
1050 $recordAccess =
false;
1051 $old_pid_value =
'';
1052 $this->autoVersioningUpdate =
false;
1058 if (isset($incomingFieldArray[
'pid'])) {
1059 $pid_value = $incomingFieldArray[
'pid'];
1063 if (strpos($pid_value,
'NEW') !==
false) {
1064 if ($pid_value[0] ===
'-') {
1066 $pid_value = substr($pid_value, 1);
1071 if (isset($this->substNEWwithIDs[$pid_value])) {
1072 if ($negFlag === 1) {
1073 $old_pid_value = $this->substNEWwithIDs[$pid_value];
1075 $pid_value = (int)($negFlag * $this->substNEWwithIDs[$pid_value]);
1077 $canProceed =
false;
1080 $pid_value = (int)$pid_value;
1085 $theRealPid = $fieldArray[
'pid'];
1087 if ($theRealPid >= 0) {
1090 if ($table ===
'pages' && $incomingFieldArray[
$GLOBALS[
'TCA'][$table][
'ctrl'][
'languageField']] > 0 && $incomingFieldArray[
$GLOBALS[
'TCA'][$table][
'ctrl'][
'transOrigPointerField']] > 0) {
1095 if ($recordAccess) {
1097 $recordAccess = $this->BE_USER->recordEditAccessInternals($table, $incomingFieldArray,
true);
1098 if (!$recordAccess) {
1099 $this->
newlog(
'recordEditAccessInternals() check failed. [' . $this->BE_USER->errorMsg .
']', 1);
1100 } elseif (!$this->bypassWorkspaceRestrictions) {
1103 if ($res = $this->BE_USER->workspaceAllowLiveRecordsInPID($theRealPid, $table)) {
1105 $recordAccess =
false;
1106 $this->
newlog(
'Stage for versioning root point and users access level did not allow for editing', 1);
1110 if (
$GLOBALS[
'TCA'][$table][
'ctrl'][
'versioningWS']) {
1111 $createNewVersion =
true;
1113 $recordAccess =
false;
1114 $this->
newlog(
'Record could not be created in this workspace in this branch', 1);
1120 $this->logger->debug(
'Internal ERROR: pid should not be less than zero!');
1128 if (!$recordAccess) {
1129 if ($this->enableLogging) {
1131 $this->
log($table, $id, 2, 0, 1,
'Attempt to modify record \'%s\' (%s) without permission. Or non-existing page.', 2, [$propArr[
'header'], $table .
':' . $id], $propArr[
'event_pid']);
1136 $recordAccess = $this->BE_USER->recordEditAccessInternals($table, $id);
1137 if (!$recordAccess) {
1138 $this->
newlog(
'recordEditAccessInternals() check failed. [' . $this->BE_USER->errorMsg .
']', 1);
1141 $tempdata = $this->
recordInfo($table, $id,
'pid' . (!empty(
$GLOBALS[
'TCA'][$table][
'ctrl'][
'versioningWS']) ?
',t3ver_wsid,t3ver_stage' :
''));
1142 $theRealPid = $tempdata[
'pid'] ??
null;
1145 if (!empty($this->autoVersionIdMap[$table][$id])) {
1150 $id = $this->autoVersionIdMap[$table][$id];
1151 $recordAccess =
true;
1152 $this->autoVersioningUpdate =
true;
1153 } elseif (!$this->bypassWorkspaceRestrictions && ($errorCode = $this->BE_USER->workspaceCannotEditRecord($table, $tempdata))) {
1154 $recordAccess =
false;
1159 $id = $WSversion[
'uid'];
1160 $recordAccess =
true;
1161 } elseif ($this->BE_USER->workspaceAllowAutoCreation($table, $id, $theRealPid)) {
1163 $this->pagetreeNeedsRefresh =
true;
1166 $tce = GeneralUtility::makeInstance(__CLASS__);
1170 $cmd[$table][$id][
'version'] = [
1173 'label' =>
'Auto-created for WS #' . $this->BE_USER->workspace
1175 $tce->start([], $cmd, $this->BE_USER);
1176 $tce->process_cmdmap();
1177 $this->errorLog = array_merge($this->errorLog, $tce->errorLog);
1179 if (!empty($tce->copyMappingArray[$table][$id])) {
1180 foreach ($tce->copyMappingArray as $origTable => $origIdArray) {
1181 foreach ($origIdArray as $origId => $newId) {
1182 $this->uploadedFileArray[$origTable][$newId] = $this->uploadedFileArray[$origTable][$origId];
1183 $this->autoVersionIdMap[$origTable][$origId] = $newId;
1194 $id = $this->autoVersionIdMap[$table][$id];
1195 $recordAccess =
true;
1196 $this->autoVersioningUpdate =
true;
1198 $this->
newlog(
'Could not be edited in offline workspace in the branch where found (failure state: \'' . $errorCode .
'\'). Auto-creation of version failed!
', 1);
1201 $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);
1205 // The default is 'update
'
1208 // If access was granted above, proceed to create or update record:
1209 if (!$recordAccess) {
1213 // Here the "pid" is set IF NOT the old pid was a string pointing to a place in the subst-id array.
1214 list($tscPID) = BackendUtility::getTSCpid($table, $id, $old_pid_value ? $old_pid_value : $fieldArray['pid
']);
1215 if ($status === 'new') {
1216 // Apply TCAdefaults from pageTS
1217 $TSConfig = BackendUtility::getPagesTSconfig($tscPID);
1218 $fieldArray = $this->applyDefaultsForFieldArray($table, $TSConfig['TCAdefaults.
'] ?? null, $fieldArray);
1219 $TSConfig = $TSConfig['TCEMAIN.
'] ?? [];
1220 if ($table === 'pages
' && isset($TSConfig['permissions.
']) && is_array($TSConfig['permissions.
'])) {
1221 $fieldArray = $this->setTSconfigPermissions($fieldArray, $TSConfig['permissions.
']);
1224 // Processing of all fields in incomingFieldArray and setting them in $fieldArray
1225 $fieldArray = $this->fillInFieldArray($table, $id, $fieldArray, $incomingFieldArray, $theRealPid, $status, $tscPID);
1226 $newVersion_placeholderFieldArray = [];
1227 if ($createNewVersion) {
1228 // create a placeholder array with already processed field content
1229 $newVersion_placeholderFieldArray = $fieldArray;
1231 // NOTICE! All manipulation beyond this point bypasses both "excludeFields" AND possible "MM" relations / file uploads to field!
1232 // Forcing some values unto field array:
1233 // NOTICE: This overriding is potentially dangerous; permissions per field is not checked!!!
1234 $fieldArray = $this->overrideFieldArray($table, $fieldArray);
1235 if ($createNewVersion) {
1236 $newVersion_placeholderFieldArray = $this->overrideFieldArray($table, $newVersion_placeholderFieldArray);
1238 // Setting system fields
1239 if ($status === 'new
') {
1240 if ($GLOBALS['TCA
'][$table]['ctrl
']['crdate
']) {
1241 $fieldArray[$GLOBALS['TCA
'][$table]['ctrl
']['crdate
']] = $GLOBALS['EXEC_TIME
'];
1242 if ($createNewVersion) {
1243 $newVersion_placeholderFieldArray[$GLOBALS['TCA
'][$table]['ctrl
']['crdate
']] = $GLOBALS['EXEC_TIME
'];
1246 if ($GLOBALS['TCA
'][$table]['ctrl
']['cruser_id
']) {
1247 $fieldArray[$GLOBALS['TCA
'][$table]['ctrl
']['cruser_id
']] = $this->userid;
1248 if ($createNewVersion) {
1249 $newVersion_placeholderFieldArray[$GLOBALS['TCA
'][$table]['ctrl
']['cruser_id
']] = $this->userid;
1252 } elseif ($this->checkSimilar) {
1253 // Removing fields which are equal to the current value:
1254 $fieldArray = $this->compareFieldArrayWithCurrentAndUnset($table, $id, $fieldArray);
1256 if ($GLOBALS['TCA
'][$table]['ctrl
']['tstamp
'] && !empty($fieldArray)) {
1257 $fieldArray[$GLOBALS['TCA
'][$table]['ctrl
']['tstamp
']] = $GLOBALS['EXEC_TIME
'];
1258 if ($createNewVersion) {
1259 $newVersion_placeholderFieldArray[$GLOBALS['TCA
'][$table]['ctrl
']['tstamp
']] = $GLOBALS['EXEC_TIME
'];
1262 // Set stage to "Editing" to make sure we restart the workflow
1263 if ($GLOBALS['TCA
'][$table]['ctrl
']['versioningWS
']) {
1264 $fieldArray['t3ver_stage
'] = 0;
1266 // Hook: processDatamap_postProcessFieldArray
1267 foreach ($hookObjectsArr as $hookObj) {
1268 if (method_exists($hookObj, 'processDatamap_postProcessFieldArray
')) {
1269 $hookObj->processDatamap_postProcessFieldArray($status, $table, $id, $fieldArray, $this);
1272 // Performing insert/update. If fieldArray has been unset by some userfunction (see hook above), don't
do anything
1274 if (is_array($fieldArray)) {
1275 if ($status ===
'new') {
1276 if ($table ===
'pages') {
1278 $this->pagetreeNeedsRefresh =
true;
1282 if ($createNewVersion) {
1284 $this->pagetreeNeedsRefresh =
true;
1286 $newVersion_placeholderFieldArray[
't3ver_label'] =
'INITIAL PLACEHOLDER';
1290 $newVersion_placeholderFieldArray[
't3ver_wsid'] = $this->BE_USER->workspace;
1293 $this->
insertDB($table, $id, $newVersion_placeholderFieldArray,
false, (
int)($incomingFieldArray[
'uid'] ?? 0));
1295 $fieldArray[
'pid'] = -1;
1296 $fieldArray[
't3ver_oid'] = $this->substNEWwithIDs[$id];
1297 $fieldArray[
't3ver_id'] = 1;
1300 $fieldArray[
't3ver_label'] =
'First draft version';
1301 $fieldArray[
't3ver_wsid'] = $this->BE_USER->workspace;
1303 $phShadowId = $this->
insertDB($table, $id, $fieldArray,
true, 0,
true);
1306 $this->
triggerRemapAction($table, $id, [$this,
'placeholderShadowing'], [$table, $phShadowId]);
1308 $this->autoVersionIdMap[$table][$this->substNEWwithIDs[$id]] = $phShadowId;
1311 $this->
insertDB($table, $id, $fieldArray,
false, (
int)($incomingFieldArray[
'uid'] ?? 0));
1314 if ($table ===
'pages') {
1317 $fieldsToCheck = array_intersect($this->pagetreeRefreshFieldsFromPages, array_keys($fieldArray));
1318 if (!empty($fieldsToCheck)) {
1319 $this->pagetreeNeedsRefresh =
true;
1322 $this->
updateDB($table, $id, $fieldArray);
1338 foreach ($hookObjectsArr as $hookObj) {
1339 if (method_exists($hookObj,
'processDatamap_afterAllOperations')) {
1340 $hookObj->processDatamap_afterAllOperations($this);
1357 $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($table);
1358 $platform = $connection->getDatabasePlatform();
1359 if ($platform instanceof SQLServerPlatform) {
1364 strlen($defaultLength)
1383 $sortColumn =
$GLOBALS[
'TCA'][$table][
'ctrl'][
'sortby'] ??
'';
1389 $fieldArray[
'pid'] = $pid;
1392 $fieldArray[$sortColumn] = $this->
getSortNumber($table, 0, $pid);
1394 } elseif ($sortColumn) {
1399 $fieldArray[
'pid'] = $sortingInfo[
'pid'];
1400 $fieldArray[$sortColumn] = $sortingInfo[
'sortNumber'];
1403 $record = $this->
recordInfo($table, abs($pid),
'pid');
1419 if (empty($liveRecord)) {
1427 if (!$liveState->indicatesPlaceholder() && !$versionState->indicatesPlaceholder()) {
1430 $factory = GeneralUtility::makeInstance(
1431 PlaceholderShadowColumnsResolver::class,
1438 $shadowColumns = $factory->forMovePlaceholder();
1439 } elseif ($liveState->indicatesPlaceholder()) {
1440 $placeholderRecord = $liveRecord;
1441 $shadowColumns = $factory->forNewPlaceholder();
1445 if (empty($shadowColumns)) {
1449 $placeholderValues = [];
1450 foreach ($shadowColumns as $fieldName) {
1451 if ((
string)$versionRecord[$fieldName] !== (
string)$placeholderRecord[$fieldName]) {
1452 $placeholderValues[$fieldName] = $versionRecord[$fieldName];
1455 if (empty($placeholderValues)) {
1459 if ($this->enableLogging) {
1460 $this->
log($table, $placeholderRecord[
'uid'], 0, 0, 0,
'Shadowing done on fields <i>' . implode(
',', array_keys($placeholderRecord)) .
'</i> in placeholder record ' . $table .
':' . $liveRecord[
'uid'] .
' (offline version UID=' . $id .
')', -1, [], $this->
eventPid($table, $liveRecord[
'uid'], $liveRecord[
'pid']));
1462 $this->
updateDB($table, $placeholderRecord[
'uid'], $placeholderValues);
1474 if ($placeholderContent ===
null) {
1475 $placeholderContent =
'PLACEHOLDER';
1478 $labelPlaceholder =
'[' . $placeholderContent .
', WS#' . $this->BE_USER->workspace .
']';
1479 $labelField =
$GLOBALS[
'TCA'][$table][
'ctrl'][
'label'];
1480 if (!isset(
$GLOBALS[
'TCA'][$table][
'columns'][$labelField][
'config'][
'eval'])) {
1481 return $labelPlaceholder;
1483 $evalCodesArray = GeneralUtility::trimExplode(
',',
$GLOBALS[
'TCA'][$table][
'columns'][$labelField][
'config'][
'eval'],
true);
1485 return $transformedLabel[
'value'] ?? $labelPlaceholder;
1501 public function fillInFieldArray($table, $id, $fieldArray, $incomingFieldArray, $realPid, $status, $tscPID)
1504 $originalLanguageRecord =
null;
1505 $originalLanguage_diffStorage =
null;
1506 $diffStorageFlag =
false;
1508 if (strpos($id,
'NEW') !==
false) {
1510 $checkValueRecord = $fieldArray;
1513 if (is_array($incomingFieldArray) && is_array($checkValueRecord)) {
1516 $currentRecord = $checkValueRecord;
1519 $currentRecord = ($checkValueRecord = $this->
recordInfo($table, $id,
'*'));
1525 if (is_array($currentRecord)
1526 &&
$GLOBALS[
'TCA'][$table][
'ctrl'][
'transOrigDiffSourceField']
1527 &&
$GLOBALS[
'TCA'][$table][
'ctrl'][
'languageField']
1528 && $currentRecord[
$GLOBALS[
'TCA'][$table][
'ctrl'][
'languageField']] > 0
1529 &&
$GLOBALS[
'TCA'][$table][
'ctrl'][
'transOrigPointerField']
1530 && (
int)$currentRecord[
$GLOBALS[
'TCA'][$table][
'ctrl'][
'transOrigPointerField']] > 0
1532 $originalLanguageRecord = $this->
recordInfo($table, $currentRecord[
$GLOBALS[
'TCA'][$table][
'ctrl'][
'transOrigPointerField']],
'*');
1534 $originalLanguage_diffStorage = unserialize(
1535 $currentRecord[
$GLOBALS[
'TCA'][$table][
'ctrl'][
'transOrigDiffSourceField']],
1536 [
'allowed_classes' =>
false]
1540 $this->checkValue_currentRecord = $checkValueRecord;
1547 foreach ($incomingFieldArray as $field => $fieldValue) {
1548 if (isset($this->excludedTablesAndFields[$table .
'-' . $field]) || $this->data_disableFields[$table][$id][$field]) {
1554 $languageDeny =
$GLOBALS[
'TCA'][$table][
'ctrl'][
'languageField'] && (string)
$GLOBALS[
'TCA'][$table][
'ctrl'][
'languageField'] === (
string)$field && !$this->BE_USER->checkLanguageAccess($fieldValue);
1555 if ($languageDeny) {
1564 case 'perms_userid':
1565 case 'perms_groupid':
1568 case 'perms_everybody':
1570 if ($table ===
'pages' && ($this->admin || $status ===
'new' || $this->
pageInfo($id,
'perms_userid') == $this->userid)) {
1571 $value = (int)$fieldValue;
1573 case 'perms_userid':
1574 case 'perms_groupid':
1575 $fieldArray[$field] = $value;
1578 if ($value >= 0 && $value < (2 ** 5)) {
1579 $fieldArray[$field] = $value;
1590 case 't3ver_tstamp':
1594 $fieldArray[$field] = $fieldValue;
1597 if (isset(
$GLOBALS[
'TCA'][$table][
'columns'][$field])) {
1599 $res = $this->
checkValue($table, $field, $fieldValue, $id, $status, $realPid, $tscPID, $incomingFieldArray);
1600 if (array_key_exists(
'value', $res)) {
1601 $fieldArray[$field] = $res[
'value'];
1604 if (
$GLOBALS[
'TCA'][$table][
'ctrl'][
'transOrigDiffSourceField']) {
1605 $originalLanguage_diffStorage[$field] = $this->updateModeL10NdiffDataClear ?
'' : $originalLanguageRecord[$field];
1606 $diffStorageFlag =
true;
1613 if ($this->autoVersioningUpdate ===
true) {
1614 if (is_array($this->RTEmagic_copyIndex[$table][$id][$field])) {
1615 foreach ($this->RTEmagic_copyIndex[$table][$id][$field] as $oldRTEmagicName => $newRTEmagicName) {
1616 $fieldArray[$field] = str_replace(
' src="' . $oldRTEmagicName .
'"',
' src="' . $newRTEmagicName .
'"', $fieldArray[$field]);
1620 } elseif (
$GLOBALS[
'TCA'][$table][
'ctrl'][
'origUid'] === $field) {
1622 $fieldArray[$field] = $fieldValue;
1628 if ($table ===
'pages' && is_array($originalLanguageRecord)) {
1629 $fieldArray[
'sorting'] = $originalLanguageRecord[
'sorting'];
1630 $fieldArray[
'perms_userid'] = $originalLanguageRecord[
'perms_userid'];
1631 $fieldArray[
'perms_groupid'] = $originalLanguageRecord[
'perms_groupid'];
1632 $fieldArray[
'perms_user'] = $originalLanguageRecord[
'perms_user'];
1633 $fieldArray[
'perms_group'] = $originalLanguageRecord[
'perms_group'];
1634 $fieldArray[
'perms_everybody'] = $originalLanguageRecord[
'perms_everybody'];
1638 if ($diffStorageFlag
1639 && !array_key_exists(
$GLOBALS[
'TCA'][$table][
'ctrl'][
'transOrigDiffSourceField'], $fieldArray)
1642 $fieldArray[
$GLOBALS[
'TCA'][$table][
'ctrl'][
'transOrigDiffSourceField']] = serialize($originalLanguage_diffStorage);
1668 public function checkValue($table, $field, $value, $id, $status, $realPid, $tscPID, $incomingFieldArray = [])
1674 if ($table ===
'pages' && $field ===
'doktype') {
1676 if (!($this->admin || GeneralUtility::inList($this->BE_USER->groupData[
'pagetypes_select'], $value))) {
1677 if ($this->enableLogging) {
1679 $this->
log($table, $id, 5, 0, 1,
'You cannot change the \'doktype\' of page \'%s\' to the desired value.', 1, [$propArr[
'header']], $propArr[
'event_pid']);
1683 if ($status ===
'update') {
1685 $onlyAllowedTables =
$GLOBALS[
'PAGES_TYPES'][$value][
'onlyAllowedTables'] ??
$GLOBALS[
'PAGES_TYPES'][
'default'][
'onlyAllowedTables'];
1686 if ($onlyAllowedTables) {
1690 if ($theWrongTables) {
1691 if ($this->enableLogging) {
1693 $this->
log($table, $id, 5, 0, 1,
'\'doktype\
' of page \'%s\' could not be changed because the page contains records from disallowed tables; %s', 2, [$propArr[
'header'], $theWrongTables], $propArr[
'event_pid']);
1702 if ((
int)$id !== 0) {
1704 $curValueRec = $this->
recordInfo($table, $id, $field);
1706 if ($curValueRec !==
null && array_key_exists($field, $curValueRec)) {
1707 $curValue = $curValueRec[$field];
1711 if ($table ===
'be_users'
1712 && ($field ===
'admin' || $field ===
'password')
1713 && $status ===
'update'
1716 $systemMaintainers = array_map(
'intval',
$GLOBALS[
'TYPO3_CONF_VARS'][
'SYS'][
'systemMaintainers'] ?? []);
1718 $isCurrentUserSystemMaintainer = $this->BE_USER->isSystemMaintainer();
1719 $isTargetUserInSystemMaintainerList = in_array((
int)$id, $systemMaintainers,
true);
1720 if ($field ===
'admin') {
1721 $isFieldChanged = (int)$curValueRec[$field] !== (
int)$value;
1723 $isFieldChanged = $curValueRec[$field] !== $value;
1725 if (!$isCurrentUserSystemMaintainer && $isTargetUserInSystemMaintainerList && $isFieldChanged) {
1726 $value = $curValueRec[$field];
1727 $message = GeneralUtility::makeInstance(
1728 FlashMessage::class,
1729 $this->
getLanguageService()->sL(
'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:error.adminCanNotChangeSystemMaintainer'),
1734 $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
1735 $flashMessageService->getMessageQueueByIdentifier()->enqueue($message);
1744 $tcaFieldConf[
'type'] ===
'flex'
1745 || $tcaFieldConf[
'type'] ===
'group' && ($tcaFieldConf[
'internal_type'] ===
'file' || $tcaFieldConf[
'internal_type'] ===
'file_reference')
1748 $recFID = $table .
':' . $id .
':' . $field;
1754 $res = $this->
checkValue_SW($res, $value, $tcaFieldConf, $table, $id, $curValue, $status, $realPid, $recFID, $field, $this->uploadedFileArray[$table][$id][$field], $tscPID, [
'incomingFieldArray' => $incomingFieldArray]);
1770 $tcaFieldConf =
$GLOBALS[
'TCA'][$table][
'columns'][$field][
'config'];
1772 $columnsOverridesConfigOfField =
$GLOBALS[
'TCA'][$table][
'types'][$recordType][
'columnsOverrides'][$field][
'config'] ??
null;
1773 if ($columnsOverridesConfigOfField) {
1776 return $tcaFieldConf;
1798 public function checkValue_SW($res, $value, $tcaFieldConf, $table, $id, $curValue, $status, $realPid, $recFID, $field, $uploadedFiles, $tscPID, array $additionalData =
null)
1801 if ($value ===
null && !empty($tcaFieldConf[
'eval']) && GeneralUtility::inList($tcaFieldConf[
'eval'],
'null')) {
1802 $res = [
'value' =>
null];
1806 switch ($tcaFieldConf[
'type']) {
1808 $res = $this->
checkValueForText($value, $tcaFieldConf, $table, $id, $realPid, $field);
1811 case 'imageManipulation':
1813 $res[
'value'] = $value;
1819 $res = $this->
checkValueForSlug((
string)$value, $tcaFieldConf, $table, $id, (
int)$realPid, $field, $additionalData[
'incomingFieldArray'] ?? []);
1822 $res = $this->
checkValueForCheck($res, $value, $tcaFieldConf, $table, $id, $realPid, $field);
1825 $res = $this->
checkValueForRadio($res, $value, $tcaFieldConf, $table, $id, $realPid, $field);
1829 $res = $this->
checkValueForGroupSelect($res, $value, $tcaFieldConf, $table, $id, $curValue, $status, $recFID, $uploadedFiles, $field);
1832 $res = $this->
checkValueForInline($res, $value, $tcaFieldConf, $table, $id, $status, $field, $additionalData);
1837 $res = $this->
checkValueForFlex($res, $value, $tcaFieldConf, $table, $id, $curValue, $status, $realPid, $recFID, $tscPID, $uploadedFiles, $field);
1867 $relevantFieldNames = [
1868 $GLOBALS[
'TCA'][$table][
'ctrl'][
'transOrigPointerField'] ??
null,
1869 $GLOBALS[
'TCA'][$table][
'ctrl'][
'translationSource'] ??
null,
1876 || !in_array($field, $relevantFieldNames)
1878 || !array_key_exists(
'value', $res)
1880 || strpos($value,
'NEW') ===
false
1885 $valueArray = [$value];
1886 $this->remapStackRecords[$table][$id] = [
'remapStackIndex' => count($this->remapStack)];
1888 $this->remapStack[] = [
1889 'args' => [$valueArray, $tcaFieldConf, $id, $table, $field],
1890 'pos' => [
'valueArray' => 0,
'tcaFieldConf' => 1,
'id' => 2,
'table' => 3],
1893 unset($res[
'value']);
1909 protected function checkValueForText($value, $tcaFieldConf, $table, $id, $realPid, $field)
1911 if (isset($tcaFieldConf[
'eval']) && $tcaFieldConf[
'eval'] !==
'') {
1913 $evalCodesArray = $this->runtimeCache->get($cacheId);
1914 if (!is_array($evalCodesArray)) {
1915 $evalCodesArray = GeneralUtility::trimExplode(
',', $tcaFieldConf[
'eval'],
true);
1916 $this->runtimeCache->set($cacheId, $evalCodesArray);
1920 $valueArray = [
'value' => $value];
1924 if ($this->dontProcessTransformations) {
1927 if (isset($tcaFieldConf[
'enableRichtext']) && (
bool)$tcaFieldConf[
'enableRichtext'] ===
true) {
1929 $richtextConfigurationProvider = GeneralUtility::makeInstance(Richtext::class);
1930 $richtextConfiguration = $richtextConfigurationProvider->getConfiguration($table, $field, $realPid, $recordType, $tcaFieldConf);
1931 $parseHTML = GeneralUtility::makeInstance(RteHtmlParser::class);
1932 $parseHTML->init($table .
':' . $field, $realPid);
1933 $valueArray[
'value'] = $parseHTML->RTE_transform($value, [],
'db', $richtextConfiguration);
1950 protected function checkValueForInput($value, $tcaFieldConf, $table, $id, $realPid, $field)
1953 $isDateOrDateTimeField =
false;
1958 if (isset($tcaFieldConf[
'dbType']) && in_array($tcaFieldConf[
'dbType'], $dateTimeTypes,
true)) {
1959 if (empty($value)) {
1962 $isDateOrDateTimeField =
true;
1964 $format = $dateTimeFormats[$tcaFieldConf[
'dbType']][
'format'];
1967 $emptyValue = $dateTimeFormats[$tcaFieldConf[
'dbType']][
'empty'];
1970 $dateTime = new \DateTime($value,
new \DateTimeZone(
'UTC'));
1973 $value = $value === $emptyValue ? null : $dateTime->getTimestamp();
1977 if (isset($tcaFieldConf[
'max']) && (
int)$tcaFieldConf[
'max'] > 0) {
1978 $value = mb_substr((
string)$value, 0, (
int)$tcaFieldConf[
'max'],
'utf-8');
1981 if (empty($tcaFieldConf[
'eval'])) {
1982 $res = [
'value' => $value];
1986 $evalCodesArray = $this->runtimeCache->get($cacheId);
1987 if (!is_array($evalCodesArray)) {
1988 $evalCodesArray = GeneralUtility::trimExplode(
',', $tcaFieldConf[
'eval'],
true);
1989 $this->runtimeCache->set($cacheId, $evalCodesArray);
1993 if (isset($tcaFieldConf[
'dbType']) && isset($res[
'value']) && !$res[
'value']) {
1995 $res[
'value'] =
null;
2000 if ($field && $realPid >= 0 && !empty($res[
'value'])) {
2001 if (in_array(
'uniqueInPid', $evalCodesArray,
true)) {
2002 $res[
'value'] = $this->
getUnique($table, $field, $res[
'value'], $id, $realPid);
2004 if ($res[
'value'] && in_array(
'unique', $evalCodesArray,
true)) {
2005 $res[
'value'] = $this->
getUnique($table, $field, $res[
'value'], $id);
2013 isset($tcaFieldConf[
'range']) && $tcaFieldConf[
'range']
2014 && (!isset($tcaFieldConf[
'checkbox']) || $res[
'value'] != $tcaFieldConf[
'checkbox'])
2015 && (!isset($tcaFieldConf[
'default']) || (
int)$res[
'value'] !== (
int)$tcaFieldConf[
'default'])
2017 if (isset($tcaFieldConf[
'range'][
'upper']) && (
int)$res[
'value'] > (
int)$tcaFieldConf[
'range'][
'upper']) {
2018 $res[
'value'] = (int)$tcaFieldConf[
'range'][
'upper'];
2020 if (isset($tcaFieldConf[
'range'][
'lower']) && (int)$res[
'value'] < (
int)$tcaFieldConf[
'range'][
'lower']) {
2021 $res[
'value'] = (int)$tcaFieldConf[
'range'][
'lower'];
2026 if ($isDateOrDateTimeField) {
2028 $res[
'value'] = $res[
'value'] ? gmdate($format, $res[
'value']) : $emptyValue;
2046 protected function checkValueForSlug(
string $value, array $tcaFieldConf,
string $table, $id,
int $realPid,
string $field, array $incomingFieldArray = []): array
2048 $workspaceId = $this->BE_USER->workspace;
2049 $helper = GeneralUtility::makeInstance(SlugHelper::class, $table, $field, $tcaFieldConf, $workspaceId);
2050 $fullRecord = array_replace_recursive($this->checkValue_currentRecord, $incomingFieldArray ?? []);
2052 if ($value ===
'') {
2053 $value = $helper->generate($fullRecord, $realPid);
2055 $value = $helper->sanitize($value);
2063 if ($workspaceId > 0 && $realPid === -1
2066 return [
'value' => $value];
2070 if (empty($tcaFieldConf[
'eval'])) {
2071 return [
'value' => $value];
2075 ->fromArray($fullRecord, $realPid, $id);
2076 $evalCodesArray = GeneralUtility::trimExplode(
',', $tcaFieldConf[
'eval'],
true);
2077 if (in_array(
'unique', $evalCodesArray,
true)) {
2078 $value = $helper->buildSlugForUniqueInTable($value, $state);
2080 if (in_array(
'uniqueInSite', $evalCodesArray,
true)) {
2081 $value = $helper->buildSlugForUniqueInSite($value, $state);
2083 if (in_array(
'uniqueInPid', $evalCodesArray,
true)) {
2084 $value = $helper->buildSlugForUniqueInPid($value, $state);
2087 return [
'value' => $value];
2102 protected function checkValueForCheck($res, $value, $tcaFieldConf, $table, $id, $realPid, $field)
2104 $items = $tcaFieldConf[
'items'];
2105 if (!empty($tcaFieldConf[
'itemsProcFunc'])) {
2107 $processingService = GeneralUtility::makeInstance(ItemProcessingService::class);
2108 $items = $processingService->getProcessingItems(
2112 $this->checkValue_currentRecord,
2114 $tcaFieldConf[
'items']
2119 if ($items !==
null) {
2120 $itemC = count($items);
2125 $maxV = (2 ** $itemC) - 1;
2130 if ($value > $maxV) {
2136 $value = $value & $maxV;
2138 if ($field && $realPid >= 0 && $value > 0 && !empty($tcaFieldConf[
'eval'])) {
2139 $evalCodesArray = GeneralUtility::trimExplode(
',', $tcaFieldConf[
'eval'],
true);
2140 $otherRecordsWithSameValue = [];
2141 $maxCheckedRecords = 0;
2142 if (in_array(
'maximumRecordsCheckedInPid', $evalCodesArray,
true)) {
2144 $maxCheckedRecords = (int)$tcaFieldConf[
'validation'][
'maximumRecordsCheckedInPid'];
2146 if (in_array(
'maximumRecordsChecked', $evalCodesArray,
true)) {
2148 $maxCheckedRecords = (int)$tcaFieldConf[
'validation'][
'maximumRecordsChecked'];
2153 if ($maxCheckedRecords && count($otherRecordsWithSameValue) >= $maxCheckedRecords) {
2155 $this->
log($table, $id, 5, 0, 1,
'Could not activate checkbox for field "%s". A total of %s record(s) can have this checkbox activated. Uncheck other records first in order to activate the checkbox of this record.', -1, [$this->
getLanguageService()->sL(
BackendUtility::getItemLabel($table, $field)), $maxCheckedRecords]);
2158 $res[
'value'] = $value;
2174 protected function checkValueForRadio($res, $value, $tcaFieldConf, $table, $id, $pid, $field)
2176 if (is_array($tcaFieldConf[
'items'])) {
2177 foreach ($tcaFieldConf[
'items'] as $set) {
2178 if ((
string)$set[1] === (
string)$value) {
2179 $res[
'value'] = $value;
2186 if ($tcaFieldConf[
'itemsProcFunc'] && empty($res[
'value'])) {
2187 $processingService = GeneralUtility::makeInstance(ItemProcessingService::class);
2188 $processedItems = $processingService->getProcessingItems(
2192 $this->checkValue_currentRecord,
2194 $tcaFieldConf[
'items']
2197 foreach ($processedItems as $set) {
2198 if ((
string)$set[1] === (
string)$value) {
2199 $res[
'value'] = $value;
2223 protected function checkValueForGroupSelect($res, $value, $tcaFieldConf, $table, $id, $curValue, $status, $recFID, $uploadedFiles, $field)
2226 if (is_array($value)) {
2227 $value = implode(
',', $value);
2235 if (!$tcaFieldConf[
'multiple']) {
2236 $valueArray = array_unique($valueArray);
2239 if ($tcaFieldConf[
'type'] ===
'select' && $tcaFieldConf[
'exclusiveKeys']) {
2240 $exclusiveKeys = GeneralUtility::trimExplode(
',', $tcaFieldConf[
'exclusiveKeys']);
2241 foreach ($valueArray as $index => $key) {
2242 if (in_array($key, $exclusiveKeys,
true)) {
2243 $valueArray = [$index => $key];
2252 if ($tcaFieldConf[
'type'] ===
'select' && $tcaFieldConf[
'authMode']) {
2253 $preCount = count($valueArray);
2254 foreach ($valueArray as $index => $key) {
2255 if (!$this->BE_USER->checkAuthMode($table, $field, $key, $tcaFieldConf[
'authMode'])) {
2256 unset($valueArray[$index]);
2260 if ($preCount && empty($valueArray)) {
2265 if ($tcaFieldConf[
'type'] ===
'group'
2266 && in_array($tcaFieldConf[
'internal_type'], [
'file',
'file_reference'],
true)) {
2271 $unsetResult =
false;
2273 $tcaFieldConf[
'type'] ===
'group' && $tcaFieldConf[
'internal_type'] ===
'db'
2274 || $tcaFieldConf[
'type'] ===
'select' && ($tcaFieldConf[
'foreign_table'] || isset($tcaFieldConf[
'special']) && $tcaFieldConf[
'special'] ===
'languages')
2277 if (strpos($value,
'NEW') !==
false) {
2278 $this->remapStackRecords[$table][$id] = [
'remapStackIndex' => count($this->remapStack)];
2280 $this->remapStack[] = [
2281 'func' =>
'checkValue_group_select_processDBdata',
2282 'args' => [$valueArray, $tcaFieldConf, $id, $status, $tcaFieldConf[
'type'], $table, $field],
2283 'pos' => [
'valueArray' => 0,
'tcaFieldConf' => 1,
'id' => 2,
'table' => 5],
2286 $unsetResult =
true;
2291 if (!$unsetResult) {
2295 unset($res[
'value']);
2310 if (empty($tcaFieldConfiguration[
'filter']) || !is_array($tcaFieldConfiguration[
'filter'])) {
2313 foreach ($tcaFieldConfiguration[
'filter'] as $filter) {
2314 if (empty($filter[
'userFunc'])) {
2317 $parameters = $filter[
'parameters'] ?: [];
2318 $parameters[
'values'] = $values;
2319 $parameters[
'tcaFieldConfig'] = $tcaFieldConfiguration;
2320 $values = GeneralUtility::callUserFunction($filter[
'userFunc'], $parameters, $this);
2321 if (!is_array($values)) {
2322 throw new \RuntimeException(
'Failed calling filter userFunc.', 1336051942);
2347 if (!$this->bypassFileHandling) {
2363 if (!$this->fileFunc) {
2364 $this->fileFunc = GeneralUtility::makeInstance(BasicFileUtility::class);
2367 $this->fileFunc->setFileExtensionPermissions($tcaFieldConf[
'allowed'], $tcaFieldConf[
'disallowed'] ?:
'*');
2370 if ($tcaFieldConf[
'uploadfolder'] && $tcaFieldConf[
'internal_type'] ===
'file') {
2371 $currentFilesForHistory =
null;
2373 if (!$this->bypassFileHandling) {
2379 if ($status ===
'update') {
2389 if ($this->autoVersioningUpdate ===
true) {
2390 foreach ($valueArray as $key => $theFile) {
2398 $theFileValues = [];
2400 if ($tcaFieldConf[
'MM']) {
2403 $dbAnalysis->start(
'',
'files', $tcaFieldConf[
'MM'], $id);
2404 foreach ($dbAnalysis->itemArray as $item) {
2406 $theFileValues[] = $item[
'id'];
2410 $theFileValues = GeneralUtility::trimExplode(
',', $curValue,
true);
2412 $currentFilesForHistory = implode(
',', $theFileValues);
2414 if (!empty($theFileValues)) {
2416 foreach ($valueArray as $key => $theFile) {
2417 if ($theFile && strpos(GeneralUtility::fixWindowsFilePath($theFile),
'/') ===
false) {
2422 foreach ($theFileValues as $key => $theFile) {
2423 $theFile = trim($theFile);
2424 if (@is_file($dest .
'/' . $theFile)) {
2425 $this->removeFilesStore[] = $dest .
'/' . $theFile;
2426 } elseif ($theFile) {
2427 $this->
log($table, $id, 5, 0, 1,
'Could not delete file \'%s\' (does not exist). (%s)', 10, [$dest .
'/' . $theFile, $recFID], $propArr[
'event_pid']);
2433 foreach ($valueArray as $key => $theFile) {
2435 $maxSize = (int)$tcaFieldConf[
'max_size'];
2446 if (strpos(GeneralUtility::fixWindowsFilePath($theFile),
'/') !==
false) {
2449 if (@is_dir($dest) && (@is_file($theFile) || @is_uploaded_file($theFile))) {
2454 $fileSize = filesize($theFile);
2457 if (!$maxSize || $fileSize <= $maxSize * 1024) {
2459 $theEndFileName = $this->alternativeFileName[$theFile] ?? $theFile;
2460 $fI = GeneralUtility::split_fileref($theEndFileName);
2462 if ($this->fileFunc->checkIfAllowed($fI[
'fileext'], $dest, $theEndFileName)) {
2463 $theDestFile = $this->fileFunc->getUniqueName($this->fileFunc->cleanFileName($fI[
'file']), $dest);
2466 GeneralUtility::upload_copy_move($theFile, $theDestFile);
2468 foreach (
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
't3lib/class.t3lib_tcemain.php'][
'processUpload'] ?? [] as $className) {
2469 $hookObject = GeneralUtility::makeInstance($className);
2470 if (!$hookObject instanceof DataHandlerProcessUploadHookInterface) {
2471 throw new \UnexpectedValueException($className .
' must implement interface ' . DataHandlerProcessUploadHookInterface::class, 1279962349);
2473 $hookObject->processUpload_postProcessAction($theDestFile, $this);
2475 $this->copiedFileMap[$theFile] = $theDestFile;
2477 if (!@is_file($theDestFile)) {
2478 $this->
log($table, $id, 5, 0, 1,
'Copying file \'%s\' failed!: The destination path (%s) may be write protected. Please make it write enabled!. (%s)', 16, [$theFile,
PathUtility::dirname($theDestFile), $recFID], $propArr[
'event_pid']);
2481 $this->
log($table, $id, 5, 0, 1,
'Copying file \'%s\' failed!: No destination file (%s) possible!. (%s)', 11, [$theFile, $theDestFile, $recFID], $propArr[
'event_pid']);
2484 $this->
log($table, $id, 5, 0, 1,
'File extension \'%s\' not allowed. (%s)', 12, [$fI[
'fileext'], $recFID], $propArr[
'event_pid']);
2487 $this->
log($table, $id, 5, 0, 1,
'Filesize (%s) of file \'%s\' exceeds limit (%s). (%s)', 13, [GeneralUtility::formatSize($fileSize), $theFile, GeneralUtility::formatSize($maxSize * 1024), $recFID], $propArr[
'event_pid']);
2490 $this->
log($table, $id, 5, 0, 1,
'The destination (%s) or the source file (%s) does not exist. (%s)', 14, [$dest, $theFile, $recFID], $propArr[
'event_pid']);
2493 if (@is_file($theDestFile)) {
2494 $info = GeneralUtility::split_fileref($theDestFile);
2496 $valueArray[$key] = $info[
'file'];
2499 unset($valueArray[$key]);
2505 if ($tcaFieldConf[
'MM']) {
2509 $dbAnalysis->tableArray[
'files'] = [];
2510 foreach ($valueArray as $key => $theFile) {
2512 $dbAnalysis->itemArray[][
'id'] = $theFile;
2514 if ($status ===
'update') {
2515 $dbAnalysis->writeMM($tcaFieldConf[
'MM'], $id, 0);
2516 $newFiles = implode(
',', $dbAnalysis->getValueArray());
2517 list(, , $recFieldName) = explode(
':', $recFID);
2518 if ($currentFilesForHistory != $newFiles) {
2519 $this->mmHistoryRecords[$table .
':' . $id][
'oldRecord'][$recFieldName] = $currentFilesForHistory;
2520 $this->mmHistoryRecords[$table .
':' . $id][
'newRecord'][$recFieldName] = $newFiles;
2522 $this->mmHistoryRecords[$table .
':' . $id][
'oldRecord'][$recFieldName] =
'';
2523 $this->mmHistoryRecords[$table .
':' . $id][
'newRecord'][$recFieldName] =
'';
2526 $this->dbAnalysisStore[] = [$dbAnalysis, $tcaFieldConf[
'MM'], $id, 0];
2528 $valueArray = $dbAnalysis->countItems();
2531 if (!empty($valueArray)) {
2533 if (!$this->bypassFileHandling) {
2536 foreach ($valueArray as &$theFile) {
2542 if ($this->alternativeFilePath[$theFile]) {
2547 } elseif (@is_file($theFile)) {
2549 if (!@is_dir($dest)) {
2550 GeneralUtility::mkdir_deep($dest);
2553 $maxSize = (int)$tcaFieldConf[
'max_size'];
2556 $fileSize = filesize($theFile);
2558 if (!$maxSize || $fileSize <= $maxSize * 1024) {
2560 $theEndFileName = $this->alternativeFileName[$theFile] ?? $theFile;
2561 $fI = GeneralUtility::split_fileref($theEndFileName);
2563 if ($this->fileFunc->checkIfAllowed($fI[
'fileext'], $dest, $theEndFileName)) {
2567 GeneralUtility::upload_copy_move($theFile, $theDestFile);
2568 $this->copiedFileMap[$theFile] = $theDestFile;
2570 if (!@is_file($theDestFile)) {
2571 $this->
log($table, $id, 5, 0, 1,
'Copying file \'%s\' failed!: The destination path (%s) may be write protected. Please make it write enabled!. (%s)', 16, [$theFile,
PathUtility::dirname($theDestFile), $recFID], $propArr[
'event_pid']);
2574 $this->
log($table, $id, 5, 0, 1,
'Copying file \'%s\' failed!: No destination file (%s) possible!. (%s)', 11, [$theFile, $theDestFile, $recFID], $propArr[
'event_pid']);
2577 $this->
log($table, $id, 5, 0, 1,
'File extension \'%s\' not allowed. (%s)', 12, [$fI[
'fileext'], $recFID], $propArr[
'event_pid']);
2580 $this->
log($table, $id, 5, 0, 1,
'Filesize (%s) of file \'%s\' exceeds limit (%s). (%s)', 13, [GeneralUtility::formatSize($fileSize), $theFile, GeneralUtility::formatSize($maxSize * 1024), $recFID], $propArr[
'event_pid']);
2583 if (@is_file($theDestFile)) {
2585 $theFile = $theDestFile;
2592 if (!empty($theFile)) {
2593 $theFile = GeneralUtility::fixWindowsFilePath($theFile);
2623 protected function checkValueForFlex($res, $value, $tcaFieldConf, $table, $id, $curValue, $status, $realPid, $recFID, $tscPID, $uploadedFiles, $field)
2625 if (is_array($value)) {
2631 if ($status ===
'new') {
2632 $row[
'pid'] = $realPid;
2635 $flexFormTools = GeneralUtility::makeInstance(FlexFormTools::class);
2640 $dataStructureArray = [
'sheets' => [
'sDEF' => []]];
2642 $dataStructureIdentifier = $flexFormTools->getDataStructureIdentifier(
2643 [
'config' => $tcaFieldConf],
2649 $dataStructureArray = $flexFormTools->parseDataStructureByIdentifier($dataStructureIdentifier);
2651 }
catch (InvalidParentRowLoopException $e) {
2652 }
catch (InvalidParentRowRootException $e) {
2653 }
catch (InvalidPointerFieldValueException $e) {
2654 }
catch (InvalidIdentifierException $e) {
2658 $currentValueArray = (string)$curValue !==
'' ? GeneralUtility::xml2array($curValue) : [];
2659 if (!is_array($currentValueArray)) {
2660 $currentValueArray = [];
2664 $value[
'data'] = $this->
checkValue_flex_procInData($value[
'data'] ?? [], $currentValueArray[
'data'] ?? [], $uploadedFiles[
'data'] ?? [], $dataStructureArray, [$table, $id, $curValue, $status, $realPid, $recFID, $tscPID]);
2670 $arrValue = GeneralUtility::xml2array($xmlValue);
2672 foreach (
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
't3lib/class.t3lib_tcemain.php'][
'checkFlexFormValue'] ?? [] as $className) {
2673 $hookObject = GeneralUtility::makeInstance($className);
2674 if (method_exists($hookObject,
'checkFlexFormValue_beforeMerge')) {
2675 $hookObject->checkFlexFormValue_beforeMerge($this, $currentValueArray, $arrValue);
2684 $actionCMDs = GeneralUtility::_GP(
'_ACTION_FLEX_FORMdata');
2685 if (is_array($actionCMDs[$table][$id][$field][
'data'] ??
null)) {
2686 $arrValue = GeneralUtility::xml2array($xmlValue);
2692 $res[
'value'] .= $xmlValue;
2695 $res[
'value'] = $value;
2711 $flexObj = GeneralUtility::makeInstance(FlexFormTools::class);
2712 return $flexObj->flexArray2Xml($array, $addPrologue);
2724 if (!is_array($valueArray) || !is_array($actionCMDs)) {
2728 foreach ($actionCMDs as $key => $value) {
2729 if ($key ===
'_ACTION') {
2731 if (current($actionCMDs[$key]) ===
'') {
2735 asort($actionCMDs[$key]);
2736 $newValueArray = [];
2737 foreach ($actionCMDs[$key] as $idx => $order) {
2740 if ($order !==
'DELETE') {
2741 $newValueArray[$idx] = $valueArray[$idx];
2743 unset($valueArray[$idx]);
2745 $valueArray += $newValueArray;
2746 } elseif (is_array($actionCMDs[$key]) && isset($valueArray[$key])) {
2763 public function checkValue_inline($res, $value, $tcaFieldConf, $PP, $field, array $additionalData =
null)
2765 list($table, $id, , $status) = $PP;
2766 $this->
checkValueForInline($res, $value, $tcaFieldConf, $table, $id, $status, $field, $additionalData);
2783 public function checkValueForInline($res, $value, $tcaFieldConf, $table, $id, $status, $field, array $additionalData =
null)
2785 if (!$tcaFieldConf[
'foreign_table']) {
2790 $valueArray = GeneralUtility::trimExplode(
',', $value);
2792 $valueArray = array_unique($valueArray);
2797 $this->remapStackRecords[$table][$id] = [
'remapStackIndex' => count($this->remapStack)];
2799 $this->remapStack[] = [
2800 'func' =>
'checkValue_inline_processDBdata',
2801 'args' => [$valueArray, $tcaFieldConf, $id, $status, $table, $field, $additionalData],
2802 'pos' => [
'valueArray' => 0,
'tcaFieldConf' => 1,
'id' => 2,
'table' => 4],
2803 'additionalData' => $additionalData,
2806 unset($res[
'value']);
2828 $maxitems = isset($tcaFieldConf[
'maxitems']) ? (int)$tcaFieldConf[
'maxitems'] : 99999;
2829 return array_slice($valueArray, 0, $maxitems);
2847 public function getUnique($table, $field, $value, $id, $newPid = 0)
2849 if (!is_array(
$GLOBALS[
'TCA'][$table]) || !is_array(
$GLOBALS[
'TCA'][$table][
'columns'][$field])) {
2854 if ((
string)
$GLOBALS[
'TCA'][$table][
'columns'][$field][
'l10n_mode'] ===
'exclude') {
2855 $transOrigPointerField =
$GLOBALS[
'TCA'][$table][
'ctrl'][
'transOrigPointerField'];
2856 $l10nParent = (int)$this->checkValue_currentRecord[$transOrigPointerField];
2857 if ($l10nParent > 0) {
2866 if ($statement->fetchColumn()) {
2867 for ($counter = 0; $counter <= 100; $counter++) {
2868 $newValue = $value . $counter;
2869 $statement->bindValue(1, $newValue);
2870 $statement->execute();
2871 if (!$statement->fetchColumn()) {
2897 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
2903 $queryBuilder->expr()->eq($field, $queryBuilder->createPositionalParameter($value, \PDO::PARAM_STR)),
2904 $queryBuilder->expr()->neq(
'uid', $queryBuilder->createPositionalParameter($uid, \PDO::PARAM_INT))
2907 $queryBuilder->andWhere(
2908 $queryBuilder->expr()->eq(
'pid', $queryBuilder->createPositionalParameter($pid, \PDO::PARAM_INT))
2912 $queryBuilder->andWhere(
2913 $queryBuilder->expr()->gte(
'pid', $queryBuilder->createPositionalParameter(0, \PDO::PARAM_INT))
2917 return $queryBuilder->execute();
2934 if (empty(
$GLOBALS[
'TCA'][$tableName][
'columns'][$fieldName])) {
2939 $pageId = (int)$pageId;
2941 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($tableName);
2942 $queryBuilder->getRestrictions()
2944 ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
2945 ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
2947 $queryBuilder->select(
'*')
2950 $queryBuilder->expr()->eq(
2952 $queryBuilder->createNamedParameter($value, \PDO::PARAM_STR)
2954 $queryBuilder->expr()->neq(
2956 $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)
2961 $queryBuilder->andWhere(
2962 $queryBuilder->expr()->eq(
'pid', $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT))
2965 $queryBuilder->andWhere(
2966 $queryBuilder->expr()->gte(
'pid', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT))
2970 $result = $queryBuilder->execute()->fetchAll();
2985 foreach ($evalArray as $func) {
2988 $value = trim($value);
2996 if (isset(
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
'tce'][
'formevals'][$func])) {
2997 if (class_exists($func)) {
2998 $evalObj = GeneralUtility::makeInstance($func);
2999 if (method_exists($evalObj,
'evaluateFieldValue')) {
3000 $value = $evalObj->evaluateFieldValue($value, $is_in, $set);
3007 $res[
'value'] = $value;
3025 foreach ($evalArray as $func) {
3029 $value = (int)$value;
3036 $value = (new \DateTime($value))->getTimestamp();
3052 $value = (new \DateTime($value))->getTimestamp();
3053 }
catch (\Exception $e) {
3055 $value = (int)date(
'Z', 0);
3059 $value -= date(
'Z', $value);
3063 $value = preg_replace(
'/[^0-9,\\.-]/',
'', $value);
3064 $negative = $value[0] ===
'-';
3065 $value = strtr($value, [
',' =>
'.',
'-' =>
'']);
3066 if (strpos($value,
'.') ===
false) {
3069 $valueArray = explode(
'.', $value);
3070 $dec = array_pop($valueArray);
3071 $value = implode(
'', $valueArray) .
'.' . $dec;
3075 $value = number_format($value, 2,
'.',
'');
3078 if (strlen($value) !== 32) {
3083 $value = trim($value);
3086 $value = mb_strtoupper($value,
'utf-8');
3089 $value = mb_strtolower($value,
'utf-8');
3092 if (!isset($value) || $value ===
'') {
3097 $c = mb_strlen($value);
3100 for ($a = 0; $a < $c; $a++) {
3101 $char = mb_substr($value, $a, 1);
3102 if (mb_strpos($is_in, $char) !==
false) {
3110 $value = str_replace(
' ',
'', $value);
3113 $value = preg_replace(
'/[^a-zA-Z]/',
'', $value);
3116 $value = preg_replace(
'/[^0-9]/',
'', $value);
3119 $value = preg_replace(
'/[^a-zA-Z0-9]/',
'', $value);
3122 $value = preg_replace(
'/[^a-zA-Z0-9_-]/',
'', $value);
3125 if (!preg_match(
'/^[a-z0-9.\\-]*$/i', $value)) {
3126 $value = GeneralUtility::idnaEncode($value);
3130 if ((
string)$value !==
'') {
3134 case 'saltedPassword':
3140 $hashMethod = substr($value, 0, 2);
3146 $isDeprecatedSaltedHash = $hashMethod ===
'M$';
3147 $tempValue = $isDeprecatedSaltedHash ? substr($value, 1) : $value;
3148 $hashFactory = GeneralUtility::makeInstance(PasswordHashFactory::class);
3149 $mode = $table ===
'fe_users' ?
'FE' :
'BE';
3151 $hashFactory->get($tempValue, $mode);
3155 $newHashInstance = $hashFactory->getDefaultHashInstance($mode);
3156 $value = $newHashInstance->getHashedPassword($value);
3160 if (isset(
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
'tce'][
'formevals'][$func])) {
3161 if (class_exists($func)) {
3162 $evalObj = GeneralUtility::makeInstance($func);
3163 if (method_exists($evalObj,
'evaluateFieldValue')) {
3164 $value = $evalObj->evaluateFieldValue($value, $is_in, $set);
3171 $res[
'value'] = $value;
3188 if (GeneralUtility::validEmail($value)) {
3194 $message = GeneralUtility::makeInstance(
3195 FlashMessage::class,
3196 sprintf($this->
getLanguageService()->sL(
'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:error.invalidEmail'), $value),
3202 $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
3203 $flashMessageService->getMessageQueueByIdentifier()->enqueue($message);
3220 if ($type ===
'group') {
3221 $tables = $tcaFieldConf[
'allowed'];
3222 } elseif (!empty($tcaFieldConf[
'special']) && $tcaFieldConf[
'special'] ===
'languages') {
3223 $tables =
'sys_language';
3225 $tables = $tcaFieldConf[
'foreign_table'];
3227 $prep = $type ===
'group' ? $tcaFieldConf[
'prepend_tname'] :
'';
3228 $newRelations = implode(
',', $valueArray);
3231 $dbAnalysis->registerNonTableValues = !empty($tcaFieldConf[
'allowNonIdValues']);
3232 $dbAnalysis->start($newRelations, $tables,
'', 0, $currentTable, $tcaFieldConf);
3233 if ($tcaFieldConf[
'MM']) {
3236 $dbAnalysis->convertItemArray();
3237 if ($status ===
'update') {
3240 $oldRelations_dbAnalysis->registerNonTableValues = !empty($tcaFieldConf[
'allowNonIdValues']);
3242 $oldRelations_dbAnalysis->start(
'', $tables, $tcaFieldConf[
'MM'], $id, $currentTable, $tcaFieldConf);
3243 $oldRelations = implode(
',', $oldRelations_dbAnalysis->getValueArray());
3244 $dbAnalysis->writeMM($tcaFieldConf[
'MM'], $id, $prep);
3245 if ($oldRelations != $newRelations) {
3246 $this->mmHistoryRecords[$currentTable .
':' . $id][
'oldRecord'][$currentField] = $oldRelations;
3247 $this->mmHistoryRecords[$currentTable .
':' . $id][
'newRecord'][$currentField] = $newRelations;
3249 $this->mmHistoryRecords[$currentTable .
':' . $id][
'oldRecord'][$currentField] =
'';
3250 $this->mmHistoryRecords[$currentTable .
':' . $id][
'newRecord'][$currentField] =
'';
3253 $this->dbAnalysisStore[] = [$dbAnalysis, $tcaFieldConf[
'MM'], $id, $prep, $currentTable];
3255 $valueArray = $dbAnalysis->countItems();
3257 $valueArray = $dbAnalysis->getValueArray($prep);
3271 $valueArray = GeneralUtility::trimExplode(
',', $value,
true);
3272 foreach ($valueArray as &$newVal) {
3273 $temp = explode(
'|', $newVal, 2);
3274 $newVal = str_replace([
'|',
','],
'', rawurldecode($temp[0]));
3295 public function checkValue_flex_procInData($dataPart, $dataPart_current, $uploadedFiles, $dataStructure, $pParams, $callBackFunc =
'', array $workspaceOptions = [])
3297 if (is_array($dataPart)) {
3298 foreach ($dataPart as $sKey => $sheetDef) {
3299 if (isset($dataStructure[
'sheets'][$sKey]) && is_array($dataStructure[
'sheets'][$sKey]) && is_array($sheetDef)) {
3300 foreach ($sheetDef as $lKey => $lData) {
3302 $dataPart[$sKey][$lKey],
3303 $dataPart_current[$sKey][$lKey],
3304 $uploadedFiles[$sKey][$lKey],
3305 $dataStructure[
'sheets'][$sKey][
'ROOT'][
'el'],
3308 $sKey .
'/' . $lKey .
'/',
3332 public function checkValue_flex_procInData_travDS(&$dataValues, $dataValues_current, $uploadedFiles, $DSelements, $pParams, $callBackFunc, $structurePath, array $workspaceOptions = [])
3334 if (!is_array($DSelements)) {
3339 foreach ($DSelements as $key => $dsConf) {
3341 if ($DSelements[$key][
'type'] ===
'array') {
3342 if (!is_array($dataValues[$key][
'el'])) {
3346 if ($DSelements[$key][
'section']) {
3347 foreach ($dataValues[$key][
'el'] as $ik => $el) {
3348 if (!is_array($el)) {
3352 if (!is_array($dataValues_current[$key][
'el'])) {
3353 $dataValues_current[$key][
'el'] = [];
3356 if (!is_array($dataValues[$key][
'el'][$ik][$theKey][
'el'])) {
3360 $this->
checkValue_flex_procInData_travDS($dataValues[$key][
'el'][$ik][$theKey][
'el'], is_array($dataValues_current[$key][
'el'][$ik]) ? $dataValues_current[$key][
'el'][$ik][$theKey][
'el'] : [], $uploadedFiles[$key][
'el'][$ik][$theKey][
'el'], $DSelements[$key][
'el'][$theKey][
'el'], $pParams, $callBackFunc, $structurePath . $key .
'/el/' . $ik .
'/' . $theKey .
'/el/', $workspaceOptions);
3363 if (!isset($dataValues[$key][
'el'])) {
3364 $dataValues[$key][
'el'] = [];
3366 $this->
checkValue_flex_procInData_travDS($dataValues[$key][
'el'], $dataValues_current[$key][
'el'], $uploadedFiles[$key][
'el'], $DSelements[$key][
'el'], $pParams, $callBackFunc, $structurePath . $key .
'/el/', $workspaceOptions);
3370 $fieldConfiguration = $dsConf[
'TCEforms'][
'config'] ?? $dsConf[
'config'] ??
null;
3372 if (!empty($fieldConfiguration[
'type']) && $fieldConfiguration[
'type'] ===
'passthrough') {
3373 if (!empty($dataValues_current[$key][
'vDEF'])) {
3375 $dataValues[$key][
'vDEF'] = $dataValues_current[$key][
'vDEF'];
3377 !empty($fieldConfiguration[
'default'])
3378 && isset($pParams[1])
3382 $dataValues[$key][
'vDEF'] = $fieldConfiguration[
'default'];
3385 if (!is_array($fieldConfiguration) || !is_array($dataValues[$key])) {
3389 foreach ($dataValues[$key] as $vKey => $data) {
3390 if ($callBackFunc) {
3391 if (is_object($this->callBackObj)) {
3392 $res = $this->callBackObj->{$callBackFunc}($pParams, $fieldConfiguration, $dataValues[$key][$vKey], $dataValues_current[$key][$vKey], $uploadedFiles[$key][$vKey], $structurePath . $key .
'/' . $vKey .
'/', $workspaceOptions);
3394 $res = $this->{$callBackFunc}($pParams, $fieldConfiguration, $dataValues[$key][$vKey], $dataValues_current[$key][$vKey], $uploadedFiles[$key][$vKey], $structurePath . $key .
'/' . $vKey .
'/', $workspaceOptions);
3398 list($CVtable, $CVid, $CVcurValue, $CVstatus, $CVrealPid, $CVrecFID, $CVtscPID) = $pParams;
3401 'flexFormId' => $CVrecFID,
3402 'flexFormPath' => trim(rtrim($structurePath,
'/') .
'/' . $key .
'/' . $vKey,
'/'),
3405 $res = $this->
checkValue_SW([], $dataValues[$key][$vKey], $fieldConfiguration, $CVtable, $CVid, $dataValues_current[$key][$vKey], $CVstatus, $CVrealPid, $CVrecFID,
'', $uploadedFiles[$key][$vKey], $CVtscPID, $additionalData);
3408 if (isset($res[
'value'])) {
3409 $dataValues[$key][$vKey] = $res[
'value'];
3413 if (mb_substr($vKey, -9) !==
'.vDEFbase') {
3414 if (
$GLOBALS[
'TYPO3_CONF_VARS'][
'BE'][
'flexFormXMLincludeDiffBase'] && $vKey !==
'vDEF' && ((
string)$dataValues[$key][$vKey] !== (
string)$dataValues_current[$key][$vKey] || !isset($dataValues_current[$key][$vKey .
'.vDEFbase']))) {
3416 if (isset($dataValues[$key][
'vDEF'])) {
3417 $diffValue = $dataValues[$key][
'vDEF'];
3420 $diffValue = $dataValues_current[$key][
'vDEF'];
3423 $dataValues[$key][$vKey .
'.vDEFbase'] = $this->updateModeL10NdiffDataClear ?
'' : $diffValue;
3445 $foreignTable = $tcaFieldConf[
'foreign_table'];
3450 $dbAnalysis->start(implode(
',', $valueArray), $foreignTable,
'', 0, $table, $tcaFieldConf);
3452 if ($tcaFieldConf[
'foreign_field']) {
3454 $skipSorting = (bool)$this->callFromImpExp;
3456 $dbAnalysis->writeForeignField($tcaFieldConf, $id, 0, $skipSorting);
3457 $newValue = $dbAnalysis->countItems(
false);
3461 $newValue = $valueArray[0];
3463 $valueArray = $dbAnalysis->getValueArray();
3485 if ($this->BE_USER->workspace !== 0 && $this->BE_USER->workspaceRec[
'freeze']) {
3486 $this->
newlog(
'All editing in this workspace has been frozen!', 1);
3490 $hookObjectsArr = [];
3491 foreach (
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
't3lib/class.t3lib_tcemain.php'][
'processCmdmapClass'] ?? [] as $className) {
3492 $hookObj = GeneralUtility::makeInstance($className);
3493 if (method_exists($hookObj,
'processCmdmap_beforeStart')) {
3494 $hookObj->processCmdmap_beforeStart($this);
3496 $hookObjectsArr[] = $hookObj;
3500 foreach ($this->cmdmap as $table => $_) {
3503 if (!$modifyAccessList) {
3504 $this->
log($table, 0, 2, 0, 1,
'Attempt to modify table \'%s\' without permission', 1, [$table]);
3507 if (!isset(
$GLOBALS[
'TCA'][$table]) || $this->
tableReadOnly($table) || !is_array($this->cmdmap[$table]) || !$modifyAccessList) {
3512 foreach ($this->cmdmap[$table] as $id => $incomingCmdArray) {
3513 if (!is_array($incomingCmdArray)) {
3517 if ($table ===
'pages') {
3519 $this->pagetreeNeedsRefresh =
true;
3522 foreach ($incomingCmdArray as $command => $value) {
3523 $pasteUpdate =
false;
3524 if (is_array($value) && isset($value[
'action']) && $value[
'action'] ===
'paste') {
3528 $pasteUpdate = $value[
'update'];
3529 $value = $value[
'target'];
3531 foreach ($hookObjectsArr as $hookObj) {
3532 if (method_exists($hookObj,
'processCmdmap_preProcess')) {
3533 $hookObj->processCmdmap_preProcess($command, $table, $id, $value, $this, $pasteUpdate);
3539 $this->copyMappingArray = [];
3541 $commandIsProcessed =
false;
3542 foreach ($hookObjectsArr as $hookObj) {
3543 if (method_exists($hookObj,
'processCmdmap')) {
3544 $hookObj->processCmdmap($command, $table, $id, $value, $commandIsProcessed, $this, $pasteUpdate);
3548 if (!$commandIsProcessed) {
3557 $target = $value[
'target'] ?? $value;
3558 $ignoreLocalization = (bool)($value[
'ignoreLocalization'] ??
false);
3559 if ($table ===
'pages') {
3562 $this->
copyRecord($table, $id, $target,
true, [],
'', 0, $ignoreLocalization);
3564 $procId = $this->copyMappingArray[$table][$id];
3567 $this->useTransOrigPointerField =
true;
3570 case 'copyToLanguage':
3571 $this->useTransOrigPointerField =
false;
3574 case 'inlineLocalizeSynchronize':
3584 $this->useTransOrigPointerField = $backupUseTransOrigPointerField;
3585 if (is_array($pasteUpdate)) {
3586 $pasteDatamap[$table][$procId] = $pasteUpdate;
3589 foreach ($hookObjectsArr as $hookObj) {
3590 if (method_exists($hookObj,
'processCmdmap_postProcess')) {
3591 $hookObj->processCmdmap_postProcess($command, $table, $id, $value, $this, $pasteUpdate, $pasteDatamap);
3601 $copyTCE->start($pasteDatamap, [], $this->BE_USER);
3602 $copyTCE->process_datamap();
3603 $this->errorLog = array_merge($this->errorLog, $copyTCE->errorLog);
3610 foreach ($hookObjectsArr as $hookObj) {
3611 if (method_exists($hookObj,
'processCmdmap_afterFinish')) {
3612 $hookObj->processCmdmap_afterFinish($this);
3639 public function copyRecord($table, $uid, $destPid, $first =
false,
$overrideValues = [], $excludeFields =
'', $language = 0, $ignoreLocalization =
false)
3641 $uid = ($origUid = (int)$uid);
3643 if (empty(
$GLOBALS[
'TCA'][$table]) || $uid === 0) {
3654 if ($row ===
false) {
3655 $this->
log($table, $uid, 1, 0, 1,
'Attempt to copy record "%s:%s" which does not exist or you do not have permission to read', -1, [$table, $uid]);
3661 $this->
log($table, $uid, 1, 0, 1,
'Attempt to insert record "%s:%s" on a page (%s) that can\'t store record type.', -1, [$table, $uid, $destPid]);
3665 $fullLanguageCheckNeeded = $table !==
'pages';
3667 if (!$ignoreLocalization && ($language <= 0 || !$this->BE_USER->checkLanguageAccess($language)) && !$this->BE_USER->recordEditAccessInternals($table, $uid,
false,
false, $fullLanguageCheckNeeded)) {
3668 $this->
log($table, $uid, 1, 0, 1,
'Attempt to copy record "%s:%s" without having permissions to do so. [' . $this->BE_USER->errorMsg .
'].', -1, [$table, $uid]);
3673 $nonFields = array_unique(GeneralUtility::trimExplode(
',',
'uid,perms_userid,perms_groupid,perms_user,perms_group,perms_everybody,t3ver_oid,t3ver_wsid,t3ver_id,t3ver_label,t3ver_state,t3ver_count,t3ver_stage,t3ver_tstamp,' . $excludeFields,
true));
3679 $enableField = isset(
$GLOBALS[
'TCA'][$table][
'ctrl'][
'enablecolumns']) ?
$GLOBALS[
'TCA'][$table][
'ctrl'][
'enablecolumns'][
'disabled'] :
'';
3680 $headerField =
$GLOBALS[
'TCA'][$table][
'ctrl'][
'label'];
3691 $setDefaultOnCopyArray = array_flip(GeneralUtility::trimExplode(
',',
$GLOBALS[
'TCA'][$table][
'ctrl'][
'setToDefaultOnCopy']));
3692 foreach ($row as $field => $value) {
3693 if (!in_array($field, $nonFields,
true)) {
3695 $conf =
$GLOBALS[
'TCA'][$table][
'columns'][$field][
'config'];
3700 if ($field ===
'pid') {
3705 } elseif (array_key_exists($field, $copyAfterFields)) {
3707 $value = $copyAfterFields[$field];
3708 } elseif (
$GLOBALS[
'TCA'][$table][
'ctrl'][
'setToDefaultOnCopy'] && isset($setDefaultOnCopyArray[$field])) {
3709 $value = $defaultData[$field];
3712 if ($first && $field == $enableField &&
$GLOBALS[
'TCA'][$table][
'ctrl'][
'hideAtCopy'] && !$this->neverHideAtCopy && !$tE[
'disableHideAtCopy']) {
3716 if ($first && $field == $headerField &&
$GLOBALS[
'TCA'][$table][
'ctrl'][
'prependAtCopy'] && !$tE[
'disablePrependAtCopy']) {
3723 $data[$table][$theNewID][$field] = $value;
3727 if (
$GLOBALS[
'TCA'][$table][
'ctrl'][
'editlock']) {
3728 $data[$table][$theNewID][
$GLOBALS[
'TCA'][$table][
'ctrl'][
'editlock']] = 0;
3731 if (
$GLOBALS[
'TCA'][$table][
'ctrl'][
'origUid']) {
3732 $data[$table][$theNewID][
$GLOBALS[
'TCA'][$table][
'ctrl'][
'origUid']] = $uid;
3737 $copyTCE->start($data, [], $this->BE_USER);
3738 $copyTCE->process_datamap();
3740 $theNewSQLID = $copyTCE->substNEWwithIDs[$theNewID];
3743 $this->copyMappingArray[$table][$origUid] = $theNewSQLID;
3745 if (isset($copyTCE->autoVersionIdMap[$table][$theNewSQLID])) {
3746 $this->autoVersionIdMap[$table][$theNewSQLID] = $copyTCE->autoVersionIdMap[$table][$theNewSQLID];
3749 $this->errorLog = array_merge($this->errorLog, $copyTCE->errorLog);
3751 if (!$ignoreLocalization && $language == 0) {
3754 if (isset(
$GLOBALS[
'TCA'][$table][
'ctrl'][
'translationSource'])) {
3760 return $theNewSQLID;
3774 $destPid = (int)$destPid;
3778 if ($this->admin || in_array(
'pages', $copyTablesAlongWithPage,
true)) {
3781 $theNewRootID = $this->
copySpecificPage($uid, $destPid, $copyTablesAlongWithPage,
true);
3783 if ($theNewRootID && $this->copyTree) {
3785 $CPtable = $this->
int_pageTreeInfo([], $uid, (
int)$this->copyTree, $theNewRootID);
3787 foreach ($CPtable as $thePageUid => $thePagePid) {
3788 $newPid = $this->copyMappingArray[
'pages'][$thePagePid];
3789 if (isset($newPid)) {
3792 $this->
log(
'pages', $uid, 5, 0, 1,
'Something went wrong during copying branch');
3798 $this->
log(
'pages', $uid, 5, 0, 1,
'Attempt to copy page without permission to this table');
3815 $copyTablesArray = $this->admin ? $this->
compileAdminTables() : explode(
',', $this->BE_USER->groupData[
'tables_modify']);
3818 if (strpos($this->copyWhichTables,
'*') ===
false) {
3819 $definedTablesToCopy = GeneralUtility::trimExplode(
',', $this->copyWhichTables,
true);
3821 $definedTablesToCopy[] =
'pages';
3822 $definedTablesToCopy = array_flip($definedTablesToCopy);
3823 foreach ($copyTablesArray as $k => $table) {
3824 if (!$table || !isset($definedTablesToCopy[$table])) {
3825 unset($copyTablesArray[$k]);
3829 $copyTablesArray = array_unique($copyTablesArray);
3830 return $copyTablesArray;
3841 public function copySpecificPage($uid, $destPid, $copyTablesArray, $first =
false)
3844 $theNewRootID = $this->
copyRecord(
'pages', $uid, $destPid, $first);
3846 if ($theNewRootID) {
3847 foreach ($copyTablesArray as $table) {
3849 if ($table && is_array(
$GLOBALS[
'TCA'][$table]) && $table !==
'pages') {
3851 $languageField =
null;
3852 $transOrigPointerField =
null;
3853 $translationSourceField =
null;
3855 $languageField =
$GLOBALS[
'TCA'][$table][
'ctrl'][
'languageField'];
3856 $transOrigPointerField =
$GLOBALS[
'TCA'][$table][
'ctrl'][
'transOrigPointerField'];
3858 $fields[] = $transOrigPointerField;
3859 if (isset(
$GLOBALS[
'TCA'][$table][
'ctrl'][
'translationSource'])) {
3860 $translationSourceField =
$GLOBALS[
'TCA'][$table][
'ctrl'][
'translationSource'];
3861 $fields[] = $translationSourceField;
3865 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
3871 $queryBuilder->expr()->eq(
3873 $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)
3876 if ($isTableWorkspaceEnabled && (
int)$this->BE_USER->workspace === 0) {
3878 $queryBuilder->andWhere(
3879 $queryBuilder->expr()->eq(
3881 $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
3884 } elseif ($isTableWorkspaceEnabled) {
3886 $queryBuilder->andWhere($queryBuilder->expr()->in(
3888 $queryBuilder->createNamedParameter(
3889 [0, $this->BE_USER->workspace],
3890 Connection::PARAM_INT_ARRAY
3894 if (!empty(
$GLOBALS[
'TCA'][$table][
'ctrl'][
'sortby'])) {
3895 $queryBuilder->orderBy(
$GLOBALS[
'TCA'][$table][
'ctrl'][
'sortby'],
'DESC');
3897 $queryBuilder->addOrderBy(
'uid');
3899 $result = $queryBuilder->execute();
3901 while ($row = $result->fetch()) {
3902 $rows[$row[
'uid']] = $row;
3905 if (!empty($rows) && (
int)$this->BE_USER->workspace !== 0 && $isTableWorkspaceEnabled) {
3906 $rows = array_reverse(
3910 $GLOBALS[
'TCA'][$table][
'ctrl'][
'sortby'],
3916 if (is_array($rows)) {
3917 $languageSourceMap = [];
3918 $overrideValues = $translationSourceField ? [$translationSourceField => 0] : [];
3920 foreach ($rows as $row) {
3923 $transOrigPointer = $row[$transOrigPointerField];
3924 if ($row[$languageField] > 0 && $transOrigPointer > 0 && isset($rows[$transOrigPointer])) {
3929 if ($translationSourceField) {
3930 $languageSourceMap[$row[
'uid']] = $newUid;
3931 if ($row[$languageField] > 0) {
3941 }
catch (DBALException $e) {
3942 $databaseErrorMessage = $e->getPrevious()->getMessage();
3943 $this->
log($table, $uid, 5, 0, 1,
'An SQL error occurred: ' . $databaseErrorMessage);
3948 return $theNewRootID;
3968 public function copyRecord_raw($table, $uid, $pid, $overrideArray = [], array $workspaceOptions = [])
3985 if ($row ===
false) {
3992 'Attempt to rawcopy/versionize record which either does not exist or you don\'t have permission to read'
3998 $nonFields = [
'uid',
'pid',
't3ver_id',
't3ver_oid',
't3ver_wsid',
't3ver_label',
't3ver_state',
't3ver_count',
't3ver_stage',
't3ver_tstamp',
'perms_userid',
'perms_groupid',
'perms_user',
'perms_group',
'perms_everybody'];
4001 $row = array_merge($row, $overrideArray);
4003 foreach ($row as $field => $value) {
4004 if (!in_array($field, $nonFields,
true)) {
4006 $conf =
$GLOBALS[
'TCA'][$table][
'columns'][$field][
'config'];
4007 if (is_array($conf)) {
4012 $row[$field] = $value;
4018 if (
$GLOBALS[
'TCA'][$table][
'ctrl'][
'origUid']) {
4019 $row[
$GLOBALS[
'TCA'][$table][
'ctrl'][
'origUid']] = $uid;
4025 $this->dbAnalysisStore = [];
4027 return $this->copyMappingArray[$table][$uid] = $theNewSQLID;
4046 $this->checkValue_currentRecord = $fieldArray;
4049 $this->dontProcessTransformations =
true;
4051 foreach ($fieldArray as $field => $fieldValue) {
4052 if (isset(
$GLOBALS[
'TCA'][$table][
'columns'][$field])) {
4054 $res = $this->
checkValue($table, $field, $fieldValue, $id,
'new', $realPid, 0, $fieldArray);
4055 if (isset($res[
'value'])) {
4056 $fieldArray[$field] = $res[
'value'];
4061 if (
$GLOBALS[
'TCA'][$table][
'ctrl'][
'crdate']) {
4064 if (
$GLOBALS[
'TCA'][$table][
'ctrl'][
'cruser_id']) {
4067 if (
$GLOBALS[
'TCA'][$table][
'ctrl'][
'tstamp']) {
4071 $this->
insertDB($table, $id, $fieldArray,
true);
4073 $this->dontProcessTransformations = $backupDontProcessTransformations;
4075 return $this->substNEWwithIDs[$id];
4103 } elseif ($inlineSubType !==
false) {
4104 $value = $this->
copyRecord_processInline($table, $uid, $field, $value, $row, $conf, $realDestPid, $language, $workspaceOptions);
4107 if ($conf[
'type'] ===
'flex') {
4109 $flexFormTools = GeneralUtility::makeInstance(FlexFormTools::class);
4110 $dataStructureIdentifier = $flexFormTools->getDataStructureIdentifier(
4111 [
'config' => $conf],
4116 $dataStructureArray = $flexFormTools->parseDataStructureByIdentifier($dataStructureIdentifier);
4117 $currentValueArray = GeneralUtility::xml2array($value);
4119 if (is_array($currentValueArray)) {
4120 $currentValueArray[
'data'] = $this->
checkValue_flex_procInData($currentValueArray[
'data'], [], [], $dataStructureArray, [$table, $uid, $field, $realDestPid],
'copyRecord_flexFormCallBack', $workspaceOptions);
4122 $value = $currentValueArray;
4141 $allowedTables = $conf[
'type'] ===
'group' ? $conf[
'allowed'] : $conf[
'foreign_table'];
4142 $prependName = $conf[
'type'] ===
'group' ? $conf[
'prepend_tname'] :
'';
4143 $mmTable = isset($conf[
'MM']) && $conf[
'MM'] ? $conf[
'MM'] :
'';
4146 $localizingNonManyToManyFieldReferences = empty($mmTable) && $localizeForeignTable && isset($conf[
'localizeReferencesAtParentLocalization']) && $conf[
'localizeReferencesAtParentLocalization'];
4149 $dbAnalysis->start($value, $allowedTables, $mmTable, $uid, $table, $conf);
4150 $purgeItems =
false;
4151 if ($language > 0 && $localizingNonManyToManyFieldReferences) {
4152 foreach ($dbAnalysis->itemArray as $index => $item) {
4155 if ($recordLocalization) {
4156 $dbAnalysis->itemArray[$index][
'id'] = $recordLocalization[0][
'uid'];
4158 $dbAnalysis->itemArray[$index][
'id'] = $this->
localize($item[
'table'], $item[
'id'], $language);
4164 if ($purgeItems || $mmTable) {
4165 $dbAnalysis->purgeItemArray();
4166 $value = implode(
',', $dbAnalysis->getValueArray($prependName));
4170 $this->registerDBList[$table][$uid][$field] = $value;
4199 array $workspaceOptions
4204 $dbAnalysis->start($value, $conf[
'foreign_table'],
'', $uid, $table, $conf);
4206 foreach ($dbAnalysis->itemArray as $k => $v) {
4211 $newId = $this->
localize($v[
'table'], $v[
'id'], $language);
4214 $newId = $this->
copyRecord($v[
'table'], $v[
'id'], -$v[
'id']);
4219 if (!empty($workspaceOptions)) {
4226 $workspaceOptions[
'label'] ??
'Auto-created for WS #' . $this->BE_USER->workspace,
4227 $workspaceOptions[
'delete'] ??
false
4233 if (isset($this->copyMappingArray[$v[
'table']][$v[
'id']])) {
4234 $newId = $this->copyMappingArray[$v[
'table']][$v[
'id']];
4236 $newId = $this->
copyRecord($v[
'table'], $v[
'id'], $realDestPid);
4246 if (isset($this->copyMappingArray[$v[
'table']][$v[
'id']])) {
4247 $newId = $this->copyMappingArray[$v[
'table']][$v[
'id']];
4249 $newId = $this->
copyRecord_raw($v[
'table'], $v[
'id'], $realDestPid, [], $workspaceOptions);
4254 if ($table ===
'pages') {
4255 $this->registerDBPids[$v[
'table']][$v[
'id']] = $uid;
4256 } elseif (isset($this->registerDBPids[$table][$uid])) {
4257 $this->registerDBPids[$v[
'table']][$v[
'id']] = $this->registerDBPids[$table][$uid];
4259 $dbAnalysis->itemArray[$k][
'id'] = $newId;
4262 $value = implode(
',', $dbAnalysis->getValueArray());
4263 $this->registerDBList[$table][$uid][$field] = $value;
4284 list($table, $uid, $field, $realDestPid) = $pParams;
4290 $this->registerDBList[$table][$uid][$field] =
'FlexForm_reference';
4293 return [
'value' => $dataValue];
4310 if ($conf[
'type'] !==
'group' || ($conf[
'internal_type'] !==
'file' && $conf[
'internal_type'] !==
'file_reference')) {
4316 $theFileValues = [];
4319 $dbAnalysis->start(
'',
'files', $conf[
'MM'], $uid);
4320 foreach ($dbAnalysis->itemArray as $somekey => $someval) {
4321 if ($someval[
'id']) {
4322 $theFileValues[] = $someval[
'id'];
4326 $theFileValues = GeneralUtility::trimExplode(
',', $value,
true);
4329 $uploadFolder = $conf[
'internal_type'] ===
'file' ? $conf[
'uploadfolder'] :
'';
4333 foreach ($theFileValues as $file) {
4335 $realFile = str_replace(
'//',
'/', $dest .
'/' . trim($file));
4336 if (@is_file($realFile)) {
4337 $newValue[] = $realFile;
4342 $value = implode(
',', $newValue);
4359 if (!$this->fileFunc) {
4360 $this->fileFunc = GeneralUtility::makeInstance(BasicFileUtility::class);
4363 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
'sys_refindex');
4364 $queryBuilder->getRestrictions()->removeAll();
4365 $rteFileRecords = $queryBuilder
4367 ->from(
'sys_refindex')
4369 $queryBuilder->expr()->eq(
4371 $queryBuilder->createNamedParameter(
'_FILE', \PDO::PARAM_STR)
4373 $queryBuilder->expr()->like(
4375 $queryBuilder->createNamedParameter(
'%/RTEmagic%', \PDO::PARAM_STR)
4377 $queryBuilder->expr()->eq(
4379 $queryBuilder->createNamedParameter(
'images', \PDO::PARAM_STR)
4381 $queryBuilder->expr()->eq(
4383 $queryBuilder->createNamedParameter($table, \PDO::PARAM_STR)
4385 $queryBuilder->expr()->eq(
4387 $queryBuilder->createNamedParameter($theNewSQLID, \PDO::PARAM_INT)
4390 ->orderBy(
'sorting',
'DESC')
4394 if (!is_array($rteFileRecords)) {
4397 foreach ($rteFileRecords as $rteFileRecord) {
4399 if (!GeneralUtility::isFirstPartOfStr($filename,
'RTEmagicC_')) {
4404 $fileInfo[
'original'] = mb_substr($rteFileRecord[
'ref_string'], 0, -mb_strlen($filename)) .
'RTEmagicP_' . preg_replace(
'/\\.[[:alnum:]]+$/',
'', mb_substr($filename, 10));
4407 if (!$fileInfo[
'exists'] || !$fileInfo[
'original_exists']) {
4408 $this->
newlog(
'Trying to copy RTEmagic files (' . $rteFileRecord[
'ref_string'] .
' / ' . $fileInfo[
'original'] .
') but one or both were missing', 1);
4415 if ($rteOrigName && GeneralUtility::isFirstPartOfStr($dirPrefix,
'uploads/') && @is_dir(
Environment::getPublicPath() .
'/' . $dirPrefix)) {
4420 $pI = pathinfo($rteFileRecord[
'ref_string']);
4422 if (!@is_file($copyDestName) && !@is_file($origDestName) && $origDestName === GeneralUtility::getFileAbsFileName($origDestName) && $copyDestName === GeneralUtility::getFileAbsFileName($copyDestName)) {
4428 $this->RTEmagic_copyIndex[$rteFileRecord[
'tablename']][$rteFileRecord[
'recuid']][$rteFileRecord[
'field']][$rteFileRecord[
'ref_string']] =
PathUtility::stripPathSitePrefix($copyDestName);
4430 if (@is_file($copyDestName)) {
4432 $sysRefObj = GeneralUtility::makeInstance(ReferenceIndex::class);
4433 $sysRefObj->enableRuntimeCache();
4436 $this->
newlog(ReferenceIndex::class .
'::setReferenceValue(): ' . $error, 1);
4439 $this->
newlog(
'File "' . $copyDestName .
'" was not created!', 1);
4442 $this->
newlog(
'Could not construct new unique names for file!', 1);
4445 $this->
newlog(
'Maybe directory of file was not within "uploads/"?', 1);
4467 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
4468 $queryBuilder->getRestrictions()
4470 ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
4471 ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
4473 $queryBuilder->select(
'*')
4476 $queryBuilder->expr()->eq(
4477 $GLOBALS[
'TCA'][$table][
'ctrl'][
'transOrigPointerField'],
4478 $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT,
':pointer')
4482 if (isset(
$GLOBALS[
'TCA'][$table][
'ctrl'][
'versioningWS']) &&
$GLOBALS[
'TCA'][$table][
'ctrl'][
'versioningWS']) {
4483 $queryBuilder->andWhere(
4484 $queryBuilder->expr()->eq(
't3ver_oid', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT))
4490 $l10nRecords = $queryBuilder->execute()->fetchAll();
4491 if (is_array($l10nRecords)) {
4492 $localizedDestPids = [];
4496 $queryBuilder->setParameter(
'pointer', abs($destPid), \PDO::PARAM_INT);
4497 $destL10nRecords = $queryBuilder->execute()->fetchAll();
4499 if (is_array($destL10nRecords)) {
4500 foreach ($destL10nRecords as $record) {
4501 $localizedDestPids[$record[
$GLOBALS[
'TCA'][$table][
'ctrl'][
'languageField']]] = -$record[
'uid'];
4505 $languageSourceMap = [
4509 foreach ($l10nRecords as $record) {
4510 $localizedDestPid = (int)$localizedDestPids[$record[
$GLOBALS[
'TCA'][$table][
'ctrl'][
'languageField']]];
4511 if ($localizedDestPid < 0) {
4514 $newUid = $this->
copyRecord($table, $record[
'uid'], $destPid < 0 ? $tscPID : $destPid, $first,
$overrideValues, $excludeFields, $record[
$GLOBALS[
'TCA'][$table][
'ctrl'][
'languageField']]);
4516 $languageSourceMap[$record[
'uid']] = $newUid;
4531 if (empty(
$GLOBALS[
'TCA'][$table][
'ctrl'][
'translationSource']) || empty(
$GLOBALS[
'TCA'][$table][
'ctrl'][
'transOrigPointerField'])) {
4534 $translationSourceFieldName =
$GLOBALS[
'TCA'][$table][
'ctrl'][
'translationSource'];
4535 $translationParentFieldName =
$GLOBALS[
'TCA'][$table][
'ctrl'][
'transOrigPointerField'];
4539 foreach ($l10nRecords as $record) {
4540 $oldSourceUid = $record[$translationSourceFieldName];
4541 if ($oldSourceUid <= 0 && $record[$translationParentFieldName] > 0) {
4543 $oldSourceUid = $record[$translationParentFieldName];
4545 if ($oldSourceUid > 0) {
4546 if (empty($languageSourceMap[$oldSourceUid])) {
4550 $newFieldValue = $languageSourceMap[$oldSourceUid];
4552 $translationSourceFieldName => $newFieldValue
4554 GeneralUtility::makeInstance(ConnectionPool::class)
4555 ->getConnectionForTable($table)
4556 ->update($table, $updateFields, [
'uid' => (
int)$languageSourceMap[$record[
'uid']]]);
4557 if ($this->BE_USER->workspace > 0) {
4558 GeneralUtility::makeInstance(ConnectionPool::class)
4559 ->getConnectionForTable($table)
4560 ->update($table, $updateFields, [
't3ver_oid' => (
int)$languageSourceMap[$record[
'uid']],
't3ver_wsid' => $this->BE_USER->workspace]);
4578 public function moveRecord($table, $uid, $destPid)
4587 $uid = $lookForLiveVersion[
'uid'];
4590 $destPid = (int)$destPid;
4595 $resolvedPid = $this->
resolvePid($table, $destPid);
4599 if ($table !==
'pages' || $resolvedPid == $moveRec[
'pid']) {
4607 if ($table !==
'pages' || $resolvedPid != $moveRec[
'pid']) {
4614 $fullLanguageCheckNeeded = $table !==
'pages';
4615 $mayEditAccess = $this->BE_USER->recordEditAccessInternals($table, $uid,
false,
false, $fullLanguageCheckNeeded);
4617 if (!$mayEditAccess) {
4618 $this->
log($table, $uid, 4, 0, 1,
'Attempt to move record "%s" (%s) without having permissions to do so. [' . $this->BE_USER->errorMsg .
']', 14, [$propArr[
'header'], $table .
':' . $uid], $propArr[
'event_pid']);
4622 if (!$mayMoveAccess) {
4623 $this->
log($table, $uid, 4, 0, 1,
'Attempt to move record \'%s\' (%s) without having permissions to do so.', 14, [$propArr[
'header'], $table .
':' . $uid], $propArr[
'event_pid']);
4627 if (!$mayInsertAccess) {
4628 $this->
log($table, $uid, 4, 0, 1,
'Attempt to move record \'%s\' (%s) without having permissions to insert.', 14, [$propArr[
'header'], $table .
':' . $uid], $propArr[
'event_pid']);
4632 $recordWasMoved =
false;
4634 foreach (
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
't3lib/class.t3lib_tcemain.php'][
'moveRecordClass'] ?? [] as $className) {
4635 $hookObj = GeneralUtility::makeInstance($className);
4636 if (method_exists($hookObj,
'moveRecord')) {
4637 $hookObj->moveRecord($table, $uid, $destPid, $propArr, $moveRec, $resolvedPid, $recordWasMoved, $this);
4641 if (!$recordWasMoved) {
4657 $sortColumn =
$GLOBALS[
'TCA'][$table][
'ctrl'][
'sortby'] ??
'';
4658 $origDestPid = $destPid;
4660 $resolvedPid = $this->
resolvePid($table, $destPid);
4663 if (($destPid < 0 && !$sortColumn) || $destPid >= 0) {
4664 $destPid = $resolvedPid;
4670 $hookObjectsArr = [];
4671 foreach (
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
't3lib/class.t3lib_tcemain.php'][
'moveRecordClass'] ?? [] as $className) {
4672 $hookObjectsArr[] = GeneralUtility::makeInstance($className);
4676 if (
$GLOBALS[
'TCA'][$table][
'ctrl'][
'tstamp']) {
4682 if ($table ===
'pages') {
4684 if ($defaultLanguagePageId !== (
int)$uid) {
4685 $originalTranslationRecord = $this->
recordInfo($table, $defaultLanguagePageId,
'pid,' . $sortColumn);
4686 $updateFields[$sortColumn] = $originalTranslationRecord[$sortColumn];
4688 $destPid = $originalTranslationRecord[
'pid'];
4693 if ($destPid >= 0) {
4699 $updateFields[
'pid'] = $destPid;
4701 if ($sortColumn && !isset($updateFields[$sortColumn])) {
4703 $updateFields[$sortColumn] = $sortNumber;
4708 GeneralUtility::makeInstance(ConnectionPool::class)
4709 ->getConnectionForTable($table)
4710 ->update($table, $updateFields, [
'uid' => (
int)$uid]);
4714 foreach ($hookObjectsArr as $hookObj) {
4715 if (method_exists($hookObj,
'moveRecord_firstElementPostProcess')) {
4716 $hookObj->moveRecord_firstElementPostProcess($table, $uid, $destPid, $moveRec, $updateFields, $this);
4720 $this->
getRecordHistoryStore()->
moveRecord($table, $uid, [
'oldPageId' => $propArr[
'pid'],
'newPageId' => $destPid,
'oldData' => $propArr,
'newData' => $updateFields]);
4721 if ($this->enableLogging) {
4724 if ($destPid != $propArr[
'pid']) {
4728 $this->
log($table, $uid, 4, $destPid, 0,
'Moved record \'%s\' (%s) to page \'%s\' (%s)', 2, [$propArr[
'header'], $table .
':' . $uid, $newpagePropArr[
'header'], $newPropArr[
'pid']], $propArr[
'pid']);
4730 $this->
log($table, $uid, 4, $destPid, 0,
'Moved record \'%s\' (%s) from page \'%s\' (%s)', 3, [$propArr[
'header'], $table .
':' . $uid, $oldpagePropArr[
'header'], $propArr[
'pid']], $destPid);
4733 $this->
log($table, $uid, 4, $destPid, 0,
'Moved record \'%s\' (%s) on page \'%s\' (%s)', 4, [$propArr[
'header'], $table .
':' . $uid, $oldpagePropArr[
'header'], $propArr[
'pid']], $destPid);
4740 if ($table ===
'pages') {
4743 } elseif ($this->enableLogging) {
4745 $this->
log($table, $uid, 4, 0, 1,
'Attempt to move page \'%s\' (%s) to inside of its own rootline (at page \'%s\' (%s))', 10, [$propArr[
'header'], $uid, $destPropArr[
'header'], $destPid], $propArr[
'pid']);
4747 } elseif ($sortColumn) {
4751 $originalRecordDestinationPid = $destPid;
4754 $destPid = $sortInfo[
'pid'];
4756 if (is_array($sortInfo)) {
4761 $updateFields[
'pid'] = $destPid;
4762 if (!isset($updateFields[$sortColumn])) {
4763 $updateFields[$sortColumn] = $sortInfo[
'sortNumber'];
4768 GeneralUtility::makeInstance(ConnectionPool::class)
4769 ->getConnectionForTable($table)
4770 ->update($table, $updateFields, [
'uid' => (
int)$uid]);
4774 foreach ($hookObjectsArr as $hookObj) {
4775 if (method_exists($hookObj,
'moveRecord_afterAnotherElementPostProcess')) {
4776 $hookObj->moveRecord_afterAnotherElementPostProcess($table, $uid, $destPid, $origDestPid, $moveRec, $updateFields, $this);
4779 $this->
getRecordHistoryStore()->
moveRecord($table, $uid, [
'oldPageId' => $propArr[
'pid'],
'newPageId' => $destPid,
'oldData' => $propArr,
'newData' => $updateFields]);
4780 if ($this->enableLogging) {
4783 if ($destPid != $propArr[
'pid']) {
4787 $this->
log($table, $uid, 4, 0, 0,
'Moved record \'%s\' (%s) to page \'%s\' (%s)', 2, [$propArr[
'header'], $table .
':' . $uid, $newpagePropArr[
'header'], $newPropArr[
'pid']], $propArr[
'pid']);
4789 $this->
log($table, $uid, 4, 0, 0,
'Moved record \'%s\' (%s) from page \'%s\' (%s)', 3, [$propArr[
'header'], $table .
':' . $uid, $oldpagePropArr[
'header'], $propArr[
'pid']], $destPid);
4792 $this->
log($table, $uid, 4, 0, 0,
'Moved record \'%s\' (%s) on page \'%s\' (%s)', 4, [$propArr[
'header'], $table .
':' . $uid, $oldpagePropArr[
'header'], $propArr[
'pid']], $destPid);
4799 if ($table ===
'pages') {
4802 } elseif ($this->enableLogging) {
4804 $this->
log($table, $uid, 4, 0, 1,
'Attempt to move page \'%s\' (%s) to inside of its own rootline (at page \'%s\' (%s))', 10, [$propArr[
'header'], $uid, $destPropArr[
'header'], $destPid], $propArr[
'pid']);
4807 $this->
log($table, $uid, 4, 0, 1,
'Attempt to move record \'%s\' (%s) to after another record, although the table has no sorting row.', 13, [$propArr[
'header'], $table .
':' . $uid], $propArr[
'event_pid']);
4823 if (is_array($row) && (
int)$destPid !== (
int)$row[
'pid']) {
4824 $conf =
$GLOBALS[
'TCA'][$table][
'columns'];
4825 foreach ($row as $field => $value) {
4843 if ($conf[
'type'] ===
'inline') {
4844 $foreign_table = $conf[
'foreign_table'];
4845 $moveChildrenWithParent = !isset($conf[
'behaviour'][
'disableMovingChildrenWithParent']) || !$conf[
'behaviour'][
'disableMovingChildrenWithParent'];
4846 if ($foreign_table && $moveChildrenWithParent) {
4848 if ($inlineType ===
'list' || $inlineType ===
'field') {
4849 if ($table ===
'pages') {
4855 $dbAnalysis->start($value, $conf[
'foreign_table'],
'', $uid, $table, $conf);
4860 if (isset($dbAnalysis)) {
4863 foreach (array_reverse($dbAnalysis->itemArray) as $v) {
4864 $this->
moveRecord($v[
'table'], $v[
'id'], $destPid);
4884 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
4885 $queryBuilder->getRestrictions()
4887 ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
4888 ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
4890 $queryBuilder->select(
'*')
4893 $queryBuilder->expr()->eq(
4894 $GLOBALS[
'TCA'][$table][
'ctrl'][
'transOrigPointerField'],
4895 $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT,
':pointer')
4899 if (isset(
$GLOBALS[
'TCA'][$table][
'ctrl'][
'versioningWS']) &&
$GLOBALS[
'TCA'][$table][
'ctrl'][
'versioningWS']) {
4900 $queryBuilder->andWhere(
4901 $queryBuilder->expr()->eq(
't3ver_oid', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT))
4905 $l10nRecords = $queryBuilder->execute()->fetchAll();
4906 if (is_array($l10nRecords)) {
4907 $localizedDestPids = [];
4909 if ($originalRecordDestinationPid < 0) {
4911 $queryBuilder->setParameter(
'pointer', abs($originalRecordDestinationPid), \PDO::PARAM_INT);
4912 $destL10nRecords = $queryBuilder->execute()->fetchAll();
4914 if (is_array($destL10nRecords)) {
4915 foreach ($destL10nRecords as $record) {
4916 $localizedDestPids[$record[
$GLOBALS[
'TCA'][$table][
'ctrl'][
'languageField']]] = -$record[
'uid'];
4921 foreach ($l10nRecords as $record) {
4922 $localizedDestPid = (int)$localizedDestPids[$record[
$GLOBALS[
'TCA'][$table][
'ctrl'][
'languageField']]];
4923 if ($localizedDestPid < 0) {
4924 $this->
moveRecord($table, $record[
'uid'], $localizedDestPid);
4926 $this->
moveRecord($table, $record[
'uid'], $destPid);
4940 public function localize($table, $uid, $language)
4949 if (!
$GLOBALS[
'TCA'][$table][
'ctrl'][
'languageField'] || !
$GLOBALS[
'TCA'][$table][
'ctrl'][
'transOrigPointerField']) {
4950 $this->
newlog(
'Localization failed; "languageField" and "transOrigPointerField" must be defined for the table ' . $table, 1);
4955 $this->
newlog(
'Sys language UID "' . $language .
'" not found valid!', 1);
4960 $this->
newlog(
'Attempt to localize record ' . $table .
':' . $uid .
' without permission.', 1);
4966 if (!is_array($row)) {
4967 $this->
newlog(
'Attempt to localize record ' . $table .
':' . $uid .
' that did not exist!', 1);
4973 if ((
int)$row[
$GLOBALS[
'TCA'][$table][
'ctrl'][
'transOrigPointerField']] !== 0
4974 && $row[
$GLOBALS[
'TCA'][$table][
'ctrl'][
'languageField']] > 0) {
4977 $row[
$GLOBALS[
'TCA'][$table][
'ctrl'][
'transOrigPointerField']]
4979 if ((
int)$localizationParentRecord[
$GLOBALS[
'TCA'][$table][
'ctrl'][
'languageField']] !== 0) {
4980 $this->
newlog(
'Localization failed; Source record ' . $table .
':' . $localizationParentRecord[
'uid'] .
' contained a reference to an original record that is not a default record (which is strange)!', 1);
4986 if ((
int)$row[
$GLOBALS[
'TCA'][$table][
'ctrl'][
'transOrigPointerField']] !== 0
4987 && (
int)$row[
$GLOBALS[
'TCA'][$table][
'ctrl'][
'languageField']] === 0) {
4988 $this->
newlog(
'Localization failed; Source record ' . $table .
':' . $row[
'uid'] .
' contained a reference to an original default record but is a default record itself (which is strange)!', 1);
4994 if (!empty($recordLocalizations)) {
4996 'Localization failed: there already are localizations (%s) for language %d of the "%s" record %d!',
4997 implode(
', ', array_column($recordLocalizations,
'uid')),
5014 if (($this->useTransOrigPointerField || $table ===
'pages') && (
int)$row[
$GLOBALS[
'TCA'][$table][
'ctrl'][
'languageField']] === 0) {
5016 } elseif (!$this->useTransOrigPointerField) {
5019 if (isset(
$GLOBALS[
'TCA'][$table][
'ctrl'][
'translationSource'])) {
5023 if (isset(
$GLOBALS[
'TCA'][$table][
'ctrl'][
'type'])) {
5027 foreach (
$GLOBALS[
'TCA'][$table][
'columns'] as $fN => $fCfg) {
5028 $translateToMsg =
'';
5030 if ($fCfg[
'l10n_mode'] ===
'prefixLangTitle') {
5031 if (($fCfg[
'config'][
'type'] ===
'text' || $fCfg[
'config'][
'type'] ===
'input') && (
string)$row[$fN] !==
'') {
5035 if (!empty($TSConfig[
'translateToMessage']) && !$tE[
'disablePrependAtCopy']) {
5037 $translateToMsg = @sprintf($translateToMsg, $langRec[
'title']);
5040 foreach (
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
't3lib/class.t3lib_tcemain.php'][
'processTranslateToClass'] ?? [] as $className) {
5041 $hookObj = GeneralUtility::makeInstance($className);
5042 if (method_exists($hookObj,
'processTranslateTo_copyAction')) {
5043 $hookObj->processTranslateTo_copyAction($row[$fN], $langRec, $this, $fN);
5046 if (!empty($translateToMsg)) {
5055 if ($table !==
'pages') {
5061 if ($autoVersionNewId !==
null) {
5062 $this->
triggerRemapAction($table, $newId, [$this,
'placeholderShadowing'], [$table, $autoVersionNewId],
true);
5069 if (!empty(
$GLOBALS[
'TCA'][$table][
'ctrl'][
'enablecolumns'][
'disabled'])) {
5070 $hiddenFieldName =
$GLOBALS[
'TCA'][$table][
'ctrl'][
'enablecolumns'][
'disabled'];
5071 $overrideValues[$hiddenFieldName] = $row[$hiddenFieldName] ??
$GLOBALS[
'TCA'][$table][
'columns'][$hiddenFieldName][
'config'][
'default'];
5075 $copyTCE->start([$table => [$temporaryId =>
$overrideValues]], [], $this->BE_USER);
5076 $copyTCE->process_datamap();
5078 $theNewSQLID = $copyTCE->substNEWwithIDs[$temporaryId];
5080 $this->copyMappingArray[$table][$uid] = $theNewSQLID;
5081 $newId = $theNewSQLID;
5109 if (!is_array($command)) {
5111 $parts = GeneralUtility::trimExplode(
',', $command);
5113 'field' => $parts[0],
5115 'language' => (int)$parentRecord[
$GLOBALS[
'TCA'][$table][
'ctrl'][
'languageField']]
5118 $command[
'action'] = $parts[1];
5120 $command[
'ids'] = [$parts[1]];
5125 if (empty($parentRecord[
$GLOBALS[
'TCA'][$table][
'ctrl'][
'languageField']])) {
5128 if (empty($parentRecordLocalization)) {
5129 if ($this->enableLogging) {
5130 $this->
log($table, $id, 0, 0, 0,
'Localization for parent record ' . $table .
':' . $id .
'" cannot be fetched', -1, [], $this->
eventPid($table, $id, $parentRecord[
'pid']));
5134 $parentRecord = $parentRecordLocalization[0];
5135 $id = $parentRecord[
'uid'];
5140 $field = $command[
'field'];
5141 $language = $command[
'language'];
5142 $action = $command[
'action'];
5143 $ids = $command[
'ids'];
5145 if (!$field || !($action ===
'localize' || $action ===
'synchronize') && empty($ids) || !isset(
$GLOBALS[
'TCA'][$table][
'columns'][$field][
'config'])) {
5149 $config =
$GLOBALS[
'TCA'][$table][
'columns'][$field][
'config'];
5150 $foreignTable = $config[
'foreign_table'];
5152 $transOrigPointer = (int)$parentRecord[
$GLOBALS[
'TCA'][$table][
'ctrl'][
'transOrigPointerField']];
5153 $childTransOrigPointerField =
$GLOBALS[
'TCA'][$foreignTable][
'ctrl'][
'transOrigPointerField'];
5155 if (!$parentRecord || !is_array($parentRecord) || $language <= 0 || !$transOrigPointer) {
5160 if ($inlineSubType ===
false) {
5167 $mmTable = $inlineSubType ===
'mm' && isset($config[
'MM']) && $config[
'MM'] ? $config[
'MM'] :
'';
5171 $dbAnalysisOriginal->start($transOrigRecord[$field], $foreignTable, $mmTable, $transOrigRecord[
'uid'], $table, $config);
5172 $elementsOriginal = [];
5173 foreach ($dbAnalysisOriginal->itemArray as $item) {
5174 $elementsOriginal[$item[
'id']] = $item;
5176 unset($dbAnalysisOriginal);
5180 $dbAnalysisCurrent->start($parentRecord[$field], $foreignTable, $mmTable, $id, $table, $config);
5182 if ($action ===
'synchronize') {
5183 foreach ($dbAnalysisCurrent->itemArray as $index => $item) {
5185 if (isset($childRecord[$childTransOrigPointerField]) && $childRecord[$childTransOrigPointerField] > 0) {
5186 $childTransOrigPointer = $childRecord[$childTransOrigPointerField];
5188 if (!isset($elementsOriginal[$childTransOrigPointer])) {
5189 unset($dbAnalysisCurrent->itemArray[$index]);
5190 $removeArray[$item[
'table']][$item[
'id']][
'delete'] = 1;
5196 if ($action ===
'localize' || $action ===
'synchronize') {
5197 foreach ($elementsOriginal as $originalId => $item) {
5198 $item[
'id'] = $this->
localize($item[
'table'], $item[
'id'], $language);
5200 $dbAnalysisCurrent->itemArray[] = $item;
5202 } elseif (!empty($ids)) {
5203 foreach ($ids as $childId) {
5207 $item = $elementsOriginal[$childId];
5208 $item[
'id'] = $this->
localize($item[
'table'], $item[
'id'], $language);
5210 $dbAnalysisCurrent->itemArray[] = $item;
5214 $value = implode(
',', $dbAnalysisCurrent->getValueArray());
5215 $this->registerDBList[$table][$id][$field] = $value;
5217 if (is_array($removeArray) && !empty($removeArray)) {
5219 $tce = GeneralUtility::makeInstance(__CLASS__);
5221 $tce->start([], $removeArray, $this->BE_USER);
5222 $tce->process_cmdmap();
5227 if ($inlineSubType ===
'list') {
5228 $updateFields = [$field => $value];
5229 } elseif ($inlineSubType ===
'field') {
5230 $dbAnalysisCurrent->writeForeignField($config, $id);
5231 $updateFields = [$field => $dbAnalysisCurrent->countItems(
false)];
5232 } elseif ($inlineSubType ===
'mm') {
5233 $dbAnalysisCurrent->writeMM($config[
'MM'], $id);
5234 $updateFields = [$field => $dbAnalysisCurrent->countItems(
false)];
5237 if (!empty($updateFields)) {
5238 $this->
updateDB($table, $id, $updateFields);
5257 if (is_array($recordToDelete)) {
5258 $recordWasDeleted =
false;
5259 foreach (
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
't3lib/class.t3lib_tcemain.php'][
'processCmdmapClass'] ?? [] as $className) {
5260 $hookObj = GeneralUtility::makeInstance($className);
5261 if (method_exists($hookObj,
'processCmdmap_deleteAction')) {
5262 $hookObj->processCmdmap_deleteAction($table, $id, $recordToDelete, $recordWasDeleted, $this);
5266 if (!$recordWasDeleted) {
5282 public function deleteEl($table, $uid, $noRecordCheck =
false, $forceHardDelete =
false,
bool $deleteRecordsOnPage =
true)
5284 if ($table ===
'pages') {
5285 $this->
deletePages($uid, $noRecordCheck, $forceHardDelete, $deleteRecordsOnPage);
5288 $this->
deleteRecord($table, $uid, $noRecordCheck, $forceHardDelete);
5302 if (is_array($versions)) {
5303 foreach ($versions as $verRec) {
5304 if (!$verRec[
'_CURRENT_VERSION']) {
5305 if ($table ===
'pages') {
5306 $this->
deletePages($verRec[
'uid'],
true, $forceHardDelete);
5308 $this->
deleteRecord($table, $verRec[
'uid'],
true, $forceHardDelete);
5315 if (!empty($versionMovePlaceholder)) {
5316 $this->
deleteEl($table, $versionMovePlaceholder[
'uid'],
true, $forceHardDelete);
5349 public function deleteRecord($table, $uid, $noRecordCheck =
false, $forceHardDelete =
false, $undeleteRecord =
false)
5352 if (!
$GLOBALS[
'TCA'][$table] || !$uid) {
5353 $this->
log($table, $uid, 3, 0, 1,
'Attempt to delete record without delete-permissions. [' . $this->BE_USER->errorMsg .
']');
5357 if (!$forceHardDelete && !$undeleteRecord && $this->
hasDeletedRecord($table, $uid)) {
5362 $deletedRecord = $forceHardDelete || $undeleteRecord;
5363 $fullLanguageAccessCheck =
true;
5364 if ($table ===
'pages') {
5367 if ($defaultLanguagePageId !== $uid) {
5368 $fullLanguageAccessCheck =
false;
5371 $hasEditAccess = $this->BE_USER->recordEditAccessInternals($table, $uid,
false, $deletedRecord, $fullLanguageAccessCheck);
5372 if (!$hasEditAccess) {
5373 $this->
log($table, $uid, 3, 0, 1,
'Attempt to delete record without delete-permissions');
5383 $deleteField =
$GLOBALS[
'TCA'][$table][
'ctrl'][
'delete'];
5384 $databaseErrorMessage =
'';
5385 if ($deleteField && !$forceHardDelete) {
5387 $deleteField => $undeleteRecord ? 0 : 1
5389 if (
$GLOBALS[
'TCA'][$table][
'ctrl'][
'tstamp']) {
5396 if (!$undeleteRecord) {
5397 $this->deletedRecords[$table][] = (int)$uid;
5400 GeneralUtility::makeInstance(ConnectionPool::class)
5401 ->getConnectionForTable($table)
5402 ->update($table, $updateFields, [
'uid' => (
int)$uid]);
5403 }
catch (DBALException $e) {
5404 $databaseErrorMessage = $e->getPrevious()->getMessage();
5408 foreach (
$GLOBALS[
'TCA'][$table][
'columns'] as $fieldName => $cfg) {
5409 $conf = $cfg[
'config'];
5410 switch ($conf[
'type']) {
5412 $flexObj = GeneralUtility::makeInstance(FlexFormTools::class);
5414 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
5415 ->getQueryBuilderForTable($table);
5416 $queryBuilder->getRestrictions()->removeAll();
5418 $files = $queryBuilder
5422 $queryBuilder->expr()->eq(
5424 $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)
5430 $flexObj->traverseFlexFormXMLData($table, $fieldName, $files, $this,
'deleteRecord_flexFormCallBack');
5436 if (!empty($fileFieldArr)) {
5437 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
5438 $queryBuilder->getRestrictions()->removeAll();
5439 $result = $queryBuilder
5440 ->select(...$fileFieldArr)
5442 ->where($queryBuilder->expr()->eq(
'uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)))
5444 if ($row = $result->fetch()) {
5445 $fArray = $fileFieldArr;
5447 foreach ($fArray as $theField) {
5452 $this->
log($table, $uid, 3, 0, 100,
'Delete: Zero rows in result when trying to read filenames from record which should be deleted');
5457 GeneralUtility::makeInstance(ConnectionPool::class)
5458 ->getConnectionForTable($table)
5459 ->delete($table, [
'uid' => (
int)$uid]);
5460 $this->deletedRecords[$table][] = (int)$uid;
5462 }
catch (DBALException $e) {
5463 $databaseErrorMessage = $e->getPrevious()->getMessage();
5466 if ($this->enableLogging) {
5468 $state = $undeleteRecord ? 1 : 3;
5469 if ($databaseErrorMessage ===
'') {
5470 if ($forceHardDelete) {
5471 $message =
'Record \'%s\' (%s) was deleted unrecoverable from page \'%s\' (%s)';
5473 $message = $state === 1 ?
'Record \'%s\' (%s) was restored on page \'%s\' (%s)' :
'Record \'%s\' (%s) was deleted from page \'%s\' (%s)';
5478 $this->
log($table, $uid, $state, 0, 0, $message, 0, [
5480 $table .
':' . $uid,
5481 $pagePropArr[
'header'],
5483 ], $propArr[
'event_pid']);
5485 $this->
log($table, $uid, $state, 0, 100, $databaseErrorMessage);
5490 if ($undeleteRecord) {
5504 $updateReferenceIndexCalls = [[$table, $uid]];
5507 if (is_array($this->updateRefIndexStack[$table]) && is_array($this->updateRefIndexStack[$table][$uid])) {
5508 while (
$args = array_pop($this->updateRefIndexStack[$table][$uid])) {
5509 if (!in_array(
$args, $updateReferenceIndexCalls,
true)) {
5512 $updateReferenceIndexCalls[] =
$args;
5515 unset($this->updateRefIndexStack[$table][$uid]);
5532 $refIndexObj = GeneralUtility::makeInstance(ReferenceIndex::class);
5533 $refIndexObj->enableRuntimeCache();
5534 $files = $refIndexObj->getRelations_procFiles($dataValue, $dsArr[
'TCEforms'][
'config'], $PA[
'uid']);
5536 if (is_array($files) && $dsArr[
'TCEforms'][
'config'][
'internal_type'] ===
'file') {
5538 foreach ($files as $dat) {
5539 if (@is_file($dat[
'ID_absFile'])) {
5543 $this->
log(
'', 0, 3, 0, 100,
'Delete: Referenced file \'' . $dat[
'ID_absFile'] .
'\' that was supposed to be deleted together with its record which didn\
't exist');
5558 public function deletePages($uid, $force =
false, $forceHardDelete =
false,
bool $deleteRecordsOnPage =
true)
5562 if ($this->enableLogging) {
5563 $this->
log(
'pages', $uid, 0, 0, 2,
'Deleting all pages starting from the root-page is disabled.', -1, [], 0);
5571 $res = GeneralUtility::intExplode(
',', $pageIdsInBranch . $uid,
true);
5576 if (is_array($res)) {
5577 foreach ($res as $deleteId) {
5582 $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $res,
'',
FlashMessage::ERROR,
true);
5584 $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
5585 $flashMessageService->getMessageQueueByIdentifier()->addMessage($flashMessage);
5599 public function deleteSpecificPage($uid, $forceHardDelete =
false,
bool $deleteRecordsOnPage =
true)
5606 $forceHardDelete = (bool)$forceHardDelete;
5610 $isPageTranslation =
false;
5611 $pageLanguageId = 0;
5612 if ($pageIdInDefaultLanguage !== $uid) {
5620 $isPageTranslation =
true;
5621 $pageLanguageId = $this->
pageInfo($uid,
$GLOBALS[
'TCA'][
'pages'][
'ctrl'][
'languageField']);
5624 if ($deleteRecordsOnPage) {
5626 foreach ($tableNames as $table) {
5632 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
5638 if ($isPageTranslation) {
5640 $queryBuilder->where(
5641 $queryBuilder->expr()->eq(
5643 $queryBuilder->createNamedParameter($pageIdInDefaultLanguage, \PDO::PARAM_INT)
5645 $queryBuilder->expr()->eq(
5646 $GLOBALS[
'TCA'][$table][
'ctrl'][
'languageField'],
5647 $queryBuilder->createNamedParameter($pageLanguageId, \PDO::PARAM_INT)
5652 $queryBuilder->where(
5653 $queryBuilder->expr()->eq(
5655 $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)
5659 $statement = $queryBuilder->execute();
5661 while ($row = $statement->fetch()) {
5666 $this->
deleteRecord($table, $row[
'uid'],
true, $forceHardDelete);
5675 $this->
deleteRecord(
'pages', $uid,
true, $forceHardDelete);
5692 if ($this->BE_USER->workspace > 0) {
5697 if (!empty($originalRecord) && !empty($movePlaceholder) && (
int)$originalRecord[
'pid'] !== (
int)$movePlaceholder[
'pid']) {
5704 'copy' =>
'-' . $movePlaceholder[
'uid']
5709 $dataHandler = GeneralUtility::makeInstance(__CLASS__);
5711 $dataHandler->neverHideAtCopy =
true;
5712 $dataHandler->start([], $command, $this->BE_USER);
5713 $dataHandler->process_cmdmap();
5714 unset($dataHandler);
5717 $this->
deleteRecord($table, $movePlaceholder[
'uid'],
true,
true);
5731 $isTranslatedPage =
null;
5737 if ($defaultLanguagePageId !== $uid) {
5738 if ($this->
doesRecordExist(
'pages', (
int)$defaultLanguagePageId,
'delete')) {
5739 $isTranslatedPage =
true;
5741 return 'Attempt to delete page without permissions';
5744 return 'Attempt to delete page without permissions';
5747 $pageIdsInBranch = $this->
doesBranchExist(
'', $uid, $this->pMap[
'delete'],
true);
5749 if ($this->deleteTree) {
5750 if ($pageIdsInBranch === -1) {
5751 return 'Attempt to delete pages in branch without permissions';
5754 $pagesInBranch = GeneralUtility::intExplode(
',', $pageIdsInBranch . $uid,
true);
5756 if ($pageIdsInBranch === -1) {
5757 return 'Attempt to delete page without permissions';
5759 if ($pageIdsInBranch !==
'') {
5760 return 'Attempt to delete page which has subpages';
5763 $pagesInBranch = [$uid];
5767 return 'Attempt to delete records from disallowed tables';
5770 foreach ($pagesInBranch as $pageInBranch) {
5771 if (!$this->BE_USER->recordEditAccessInternals(
'pages', $pageInBranch,
false,
false, $isTranslatedPage ?
false :
true)) {
5772 return 'Attempt to delete page which has prohibited localizations.';
5775 return $pagesInBranch;
5787 if ($table ===
'pages') {
5789 return is_array($res) ? false : $res;
5791 return $this->
doesRecordExist($table, $id,
'delete') ? false :
'No permission to delete record';
5805 if ($record[
'pid']) {
5808 if (!$page[
'deleted']) {
5811 $this->
log($table, $uid,
'isRecordUndeletable',
'', 1,
'Record cannot be undeleted since the page containing it is deleted! Undelete page "' . $page[
'title'] .
' (UID: ' . $page[
'uid'] .
')" first');
5831 $conf =
$GLOBALS[
'TCA'][$table][
'columns'];
5836 foreach ($row as $field => $value) {
5855 if ($conf[
'type'] ===
'inline') {
5856 $foreign_table = $conf[
'foreign_table'];
5857 if ($foreign_table) {
5859 if ($inlineType ===
'list' || $inlineType ===
'field') {
5862 $dbAnalysis->start($value, $conf[
'foreign_table'],
'', $uid, $table, $conf);
5863 $dbAnalysis->undeleteRecord =
true;
5865 $enableCascadingDelete =
true;
5867 if (isset($conf[
'behaviour'][
'enableCascadingDelete']) && $conf[
'behaviour'][
'enableCascadingDelete'] ==
false) {
5868 $enableCascadingDelete =
false;
5872 foreach ($dbAnalysis->itemArray as $v) {
5873 if (!$undeleteRecord) {
5874 if ($enableCascadingDelete) {
5884 $allowedTables = $conf[
'type'] ===
'group' ? $conf[
'allowed'] : $conf[
'foreign_table'];
5886 $dbAnalysis->start($value, $allowedTables, $conf[
'MM'], $uid, $table, $conf);
5887 foreach ($dbAnalysis->itemArray as $v) {
5888 $this->updateRefIndexStack[$table][$uid][] = [$v[
'table'], $v[
'id']];
5906 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
5907 $queryBuilder->getRestrictions()
5909 ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
5910 ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
5912 $queryBuilder->select(
'*')
5915 $queryBuilder->expr()->eq(
5916 $GLOBALS[
'TCA'][$table][
'ctrl'][
'transOrigPointerField'],
5917 $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)
5921 if (isset(
$GLOBALS[
'TCA'][$table][
'ctrl'][
'versioningWS']) &&
$GLOBALS[
'TCA'][$table][
'ctrl'][
'versioningWS']) {
5922 $queryBuilder->andWhere(
5923 $queryBuilder->expr()->eq(
't3ver_oid', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT))
5927 $result = $queryBuilder->execute();
5928 while ($record = $result->fetch()) {
5937 $this->
deleteAction($table, (
int)$record[
't3ver_oid'] > 0 ? (
int)$record[
't3ver_oid'] : (
int)$record[
'uid']);
5965 if (!
$GLOBALS[
'TCA'][$table] || !
$GLOBALS[
'TCA'][$table][
'ctrl'][
'versioningWS'] || $id <= 0) {
5966 $this->
newlog(
'Versioning is not supported for this table "' . $table .
'" / ' . $id, 1);
5974 if ($row ===
false) {
5976 'The record does not exist or you don\'t have correct permissions to make a new version (copy) of this record "' . $table .
':' . $id .
'"',
5983 if ($row[
'pid'] < 0) {
5984 $this->
newlog(
'Record "' . $table .
':' . $id .
'" you wanted to versionize was already a version in archive (pid=-1)!', 1);
5990 $this->
newlog(
'Record cannot be versioned because it is a placeholder for a moving operation', 1);
6000 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
6002 $highestVerNumber = $queryBuilder
6003 ->select(
't3ver_id')
6005 ->where($queryBuilder->expr()->orX(
6006 $queryBuilder->expr()->andX(
6007 $queryBuilder->expr()->eq(
'pid', $queryBuilder->createNamedParameter(-1, \PDO::PARAM_INT)),
6008 $queryBuilder->expr()->eq(
't3ver_oid', $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT))
6010 $queryBuilder->expr()->eq(
'uid', $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT))
6012 ->orderBy(
't3ver_id',
'DESC')
6017 $subVer = $row[
't3ver_id'] .
'.' . ($highestVerNumber + 1);
6020 't3ver_id' => $highestVerNumber + 1,
6022 't3ver_label' => $label ?: $subVer .
' / ' . date(
'd-m-Y H:m:s'),
6023 't3ver_wsid' => $this->BE_USER->workspace,
6029 if (
$GLOBALS[
'TCA'][$table][
'ctrl'][
'editlock']) {
6030 $overrideArray[
$GLOBALS[
'TCA'][$table][
'ctrl'][
'editlock']] = 0;
6033 if ($this->BE_USER->workspace !== 0) {
6038 if (empty($versionRecord[
'uid'])) {
6044 $workspaceOptions = [
6045 'delete' => $delete,
6048 return $this->
copyRecord_raw($table, $id, -1, $overrideArray, $workspaceOptions);
6053 return $versionRecord[
'uid'];
6069 $this->version_remapMMForVersionSwap_reg = [];
6070 $flexFormTools = GeneralUtility::makeInstance(FlexFormTools::class);
6071 foreach (
$GLOBALS[
'TCA'][$table][
'columns'] as $field => $fConf) {
6072 $conf = $fConf[
'config'];
6074 $allowedTables = $conf[
'type'] ===
'group' ? $conf[
'allowed'] : $conf[
'foreign_table'];
6075 $prependName = $conf[
'type'] ===
'group' ? $conf[
'prepend_tname'] :
'';
6079 $dbAnalysis->start(
'', $allowedTables, $conf[
'MM'], $id, $table, $conf);
6080 if (!empty($dbAnalysis->getValueArray($prependName))) {
6081 $this->version_remapMMForVersionSwap_reg[$id][$field] = [$dbAnalysis, $conf[
'MM'], $prependName];
6085 $dbAnalysis->start(
'', $allowedTables, $conf[
'MM'], $swapWith, $table, $conf);
6086 if (!empty($dbAnalysis->getValueArray($prependName))) {
6087 $this->version_remapMMForVersionSwap_reg[$swapWith][$field] = [$dbAnalysis, $conf[
'MM'], $prependName];
6090 } elseif ($conf[
'type'] ===
'flex') {
6092 $dataStructureIdentifier = $flexFormTools->getDataStructureIdentifier(
6098 $dataStructureArray = $flexFormTools->parseDataStructureByIdentifier($dataStructureIdentifier);
6099 $currentValueArray = GeneralUtility::xml2array($currentRec[$field]);
6100 if (is_array($currentValueArray)) {
6101 $this->
checkValue_flex_procInData($currentValueArray[
'data'], [], [], $dataStructureArray, [$table, $id, $field],
'version_remapMMForVersionSwap_flexFormCallBack');
6104 $dataStructureIdentifier = $flexFormTools->getDataStructureIdentifier(
6110 $dataStructureArray = $flexFormTools->parseDataStructureByIdentifier($dataStructureIdentifier);
6111 $currentValueArray = GeneralUtility::xml2array($swapRec[$field]);
6112 if (is_array($currentValueArray)) {
6113 $this->
checkValue_flex_procInData($currentValueArray[
'data'], [], [], $dataStructureArray, [$table, $swapWith, $field],
'version_remapMMForVersionSwap_flexFormCallBack');
6135 list($table, $uid, $field) = $pParams;
6137 $allowedTables = $dsConf[
'type'] ===
'group' ? $dsConf[
'allowed'] : $dsConf[
'foreign_table'];
6138 $prependName = $dsConf[
'type'] ===
'group' ? $dsConf[
'prepend_tname'] :
'';
6139 if ($dsConf[
'MM']) {
6142 $dbAnalysis->start(
'', $allowedTables, $dsConf[
'MM'], $uid, $table, $dsConf);
6143 $this->version_remapMMForVersionSwap_reg[$uid][$field .
'/' . $path] = [$dbAnalysis, $dsConf[
'MM'], $prependName];
6159 if (is_array($this->version_remapMMForVersionSwap_reg[$id])) {
6160 foreach ($this->version_remapMMForVersionSwap_reg[$id] as $field => $str) {
6161 $str[0]->remapMM($str[1], $id, -$id, $str[2]);
6164 if (is_array($this->version_remapMMForVersionSwap_reg[$swapWith])) {
6165 foreach ($this->version_remapMMForVersionSwap_reg[$swapWith] as $field => $str) {
6166 $str[0]->remapMM($str[1], $swapWith, $id, $str[2]);
6169 if (is_array($this->version_remapMMForVersionSwap_reg[$id])) {
6170 foreach ($this->version_remapMMForVersionSwap_reg[$id] as $field => $str) {
6171 $str[0]->remapMM($str[1], -$id, $swapWith, $str[2]);
6189 $copyTCE = GeneralUtility::makeInstance(DataHandler::class);
6193 $copyTCE->dontProcessTransformations =
true;
6207 if (!empty($this->registerDBList)) {
6208 $flexFormTools = GeneralUtility::makeInstance(FlexFormTools::class);
6209 foreach ($this->registerDBList as $table => $records) {
6210 foreach ($records as $uid =>
$fields) {
6212 $theUidToUpdate = $this->copyMappingArray_merged[$table][$uid];
6214 foreach (
$fields as $fieldName => $value) {
6215 $conf =
$GLOBALS[
'TCA'][$table][
'columns'][$fieldName][
'config'];
6216 switch ($conf[
'type']) {
6220 if (is_array($vArray)) {
6221 $newData[$fieldName] = implode(
',', $vArray);
6225 if ($value ===
'FlexForm_reference') {
6227 $origRecordRow = $this->
recordInfo($table, $theUidToUpdate,
'*');
6228 if (is_array($origRecordRow)) {
6231 $dataStructureIdentifier = $flexFormTools->getDataStructureIdentifier(
6232 [
'config' => $conf],
6237 $dataStructureArray = $flexFormTools->parseDataStructureByIdentifier($dataStructureIdentifier);
6238 $currentValueArray = GeneralUtility::xml2array($origRecordRow[$fieldName]);
6240 $currentValueArray[
'data'] = $this->
checkValue_flex_procInData($currentValueArray[
'data'], [], [], $dataStructureArray, [$table, $theUidToUpdate, $fieldName],
'remapListedDBRecords_flexFormCallBack');
6242 if (is_array($currentValueArray[
'data'])) {
6252 $this->logger->debug(
'Field type should not appear here: ' . $conf[
'type']);
6256 if (!empty($newData)) {
6257 $this->
updateDB($table, $theUidToUpdate_saveTo, $newData);
6278 list($table, $uid, $field) = $pParams;
6282 if (is_array($vArray)) {
6283 $dataValue = implode(
',', $vArray);
6287 return [
'value' => $dataValue];
6306 $allowedTables = $conf[
'type'] ===
'group' ? $conf[
'allowed'] : $conf[
'foreign_table'];
6308 $prependName = $conf[
'type'] ===
'group' ? $conf[
'prepend_tname'] :
'';
6310 $dontRemapTables = GeneralUtility::trimExplode(
',', $conf[
'dontRemapTablesOnCopy'],
true);
6313 $dbAnalysis->registerNonTableValues = $conf[
'type'] ===
'select' && $conf[
'allowNonIdValues'];
6314 $dbAnalysis->start($value, $allowedTables, $conf[
'MM'], $MM_localUid, $table, $conf);
6316 foreach ($dbAnalysis->itemArray as $k => $v) {
6317 $mapID = $this->copyMappingArray_merged[$v[
'table']][$v[
'id']];
6318 if ($mapID && !in_array($v[
'table'], $dontRemapTables,
true)) {
6319 $dbAnalysis->itemArray[$k][
'id'] = $mapID;
6323 if (!empty($conf[
'MM'])) {
6325 $dbAnalysis->purgeItemArray();
6326 if ($dbAnalysis->isPurged()) {
6333 if (!empty($this->copyMappingArray_merged[$table])) {
6334 $originalId = array_search($MM_localUid, $this->copyMappingArray_merged[$table]);
6336 if (!empty($liveId) && !empty($originalId) && (
int)$liveId === (
int)$originalId) {
6338 $liveRelations->setWorkspaceId(0);
6339 $liveRelations->start(
'', $allowedTables, $conf[
'MM'], $liveId, $table, $conf);
6341 $liveRelations->purgeItemArray(0);
6342 if ($liveRelations->isPurged()) {
6343 $liveRelations->writeMM($conf[
'MM'], $liveId, $prependName);
6350 $dbAnalysis->writeMM($conf[
'MM'], $MM_localUid, $prependName);
6352 return $dbAnalysis->getValueArray($prependName);
6368 $theUidToUpdate = $this->copyMappingArray_merged[$table][$uid];
6369 if ($conf[
'foreign_table']) {
6371 if ($inlineType ===
'mm') {
6373 } elseif ($inlineType !==
false) {
6376 $dbAnalysis->start($value, $conf[
'foreign_table'],
'', 0, $table, $conf);
6379 $originalItemArray = $dbAnalysis->itemArray;
6380 foreach ($dbAnalysis->itemArray as &$item) {
6382 if (!empty($versionedId)) {
6383 $item[
'id'] = $versionedId;
6388 if ($inlineType ===
'field') {
6389 $dbAnalysis->writeForeignField($conf, $uid, $theUidToUpdate);
6391 $thePidToUpdate =
null;
6393 if ($table ===
'pages') {
6394 $thePidToUpdate = $theUidToUpdate;
6395 } elseif (isset($this->registerDBPids[$table][$uid])) {
6396 $thePidToUpdate = $this->registerDBPids[$table][$uid];
6397 $thePidToUpdate = $this->copyMappingArray_merged[
'pages'][$thePidToUpdate];
6401 if ($thePidToUpdate) {
6406 if ($liveId !==
null) {
6407 $thePidToUpdate = $liveId;
6409 $updateValues = [
'pid' => $thePidToUpdate];
6410 foreach ($originalItemArray as $v) {
6412 GeneralUtility::makeInstance(ConnectionPool::class)
6413 ->getConnectionForTable($v[
'table'])
6414 ->update($v[
'table'], $updateValues, [
'uid' => (
int)$v[
'id']]);
6429 if (is_array($this->remapStack)) {
6430 $remapFlexForms = [];
6433 foreach ($this->remapStack as $remapAction) {
6435 if (!is_array($remapAction[
'pos'])) {
6439 $field = $remapAction[
'field'];
6440 $id = $remapAction[
'args'][$remapAction[
'pos'][
'id']];
6442 $table = $remapAction[
'args'][$remapAction[
'pos'][
'table']];
6443 $valueArray = $remapAction[
'args'][$remapAction[
'pos'][
'valueArray']];
6444 $tcaFieldConf = $remapAction[
'args'][$remapAction[
'pos'][
'tcaFieldConf']];
6445 $additionalData = $remapAction[
'additionalData'];
6447 if (strpos($id,
'NEW') !==
false) {
6449 $id = $this->substNEWwithIDs[$id];
6451 if (isset($this->autoVersionIdMap[$table][$id])) {
6452 $id = $this->autoVersionIdMap[$table][$id];
6454 $remapAction[
'args'][$remapAction[
'pos'][
'id']] = $id;
6457 if (is_array($valueArray)) {
6458 foreach ($valueArray as $key => $value) {
6459 if (strpos($value,
'NEW') !==
false) {
6460 if (strpos($value,
'_') ===
false) {
6461 $affectedTable = $tcaFieldConf[
'foreign_table'];
6462 $prependTable =
false;
6464 $parts = explode(
'_', $value);
6465 $value = array_pop($parts);
6466 $affectedTable = implode(
'_', $parts);
6467 $prependTable =
true;
6469 $value = $this->substNEWwithIDs[$value];
6471 if (isset($this->autoVersionIdMap[$affectedTable][$value])) {
6472 $value = $this->autoVersionIdMap[$affectedTable][$value];
6474 if ($prependTable) {
6475 $value = $affectedTable .
'_' . $value;
6478 $this->newRelatedIDs[$affectedTable][] = $value;
6479 $valueArray[$key] = $value;
6482 $remapAction[
'args'][$remapAction[
'pos'][
'valueArray']] = $valueArray;
6485 if (!empty($remapAction[
'func'])) {
6486 $newValue = call_user_func_array([$this, $remapAction[
'func']], $remapAction[
'args']);
6489 if (is_array($newValue)) {
6496 if (!empty($field)) {
6497 $fieldArray = [$field => $newValue];
6498 if (
$GLOBALS[
'TCA'][$table][
'ctrl'][
'tstamp']) {
6501 $this->
updateDB($table, $id, $fieldArray);
6502 } elseif (!empty($additionalData[
'flexFormId']) && !empty($additionalData[
'flexFormPath'])) {
6504 $flexFormId = $additionalData[
'flexFormId'];
6505 $flexFormPath = $additionalData[
'flexFormPath'];
6507 if (!isset($remapFlexForms[$flexFormId])) {
6508 $remapFlexForms[$flexFormId] = [];
6511 $remapFlexForms[$flexFormId][$flexFormPath] = $newValue;
6515 if (isset($this->remapStackRecords[$table][$rawId][
'processDatamap_afterDatabaseOperations'])) {
6516 $hookArgs = $this->remapStackRecords[$table][$rawId][
'processDatamap_afterDatabaseOperations'];
6517 if (!isset($hookPayload[$table][$rawId])) {
6518 $hookPayload[$table][$rawId] = [
6519 'status' => $hookArgs[
'status'],
6520 'fieldArray' => $hookArgs[
'fieldArray'],
6521 'hookObjects' => $hookArgs[
'hookObjectsArr'],
6524 $hookPayload[$table][$rawId][
'fieldArray'][$field] = $newValue;
6528 if ($remapFlexForms) {
6529 foreach ($remapFlexForms as $flexFormId => $modifications) {
6534 foreach ($hookPayload as $tableName => $rawIdPayload) {
6535 foreach ($rawIdPayload as $rawId => $payload) {
6536 foreach ($payload[
'hookObjects'] as $hookObject) {
6537 if (!method_exists($hookObject,
'processDatamap_afterDatabaseOperations')) {
6540 $hookObject->processDatamap_afterDatabaseOperations(
6544 $payload[
'fieldArray'],
6552 if ($this->remapStackActions) {
6553 foreach ($this->remapStackActions as $action) {
6554 if (isset($action[
'callback'], $action[
'arguments'])) {
6555 call_user_func_array($action[
'callback'], $action[
'arguments']);
6560 foreach ($this->remapStackRefIndex as $table => $idArray) {
6561 foreach ($idArray as $id) {
6563 unset($this->remapStackRefIndex[$table][$id]);
6567 $this->remapStack = [];
6568 $this->remapStackRecords = [];
6569 $this->remapStackActions = [];
6570 $this->remapStackRefIndex = [];
6581 list($table, $uid, $field) = explode(
':', $flexFormId, 3);
6584 $uid = $this->substNEWwithIDs[$uid];
6589 if (!$table || !$uid || !$field || !is_array($record)) {
6596 $valueStructure = GeneralUtility::xml2array($record[$field]);
6599 foreach ($modifications as $path => $value) {
6601 $valueStructure[
'data'],
6607 if (is_array($valueStructure[
'data'])) {
6613 $this->
updateDB($table, $uid, $values);
6631 protected function triggerRemapAction($table, $id, array $callback, array $arguments, $forceRemapStackActions =
false)
6634 if (!$forceRemapStackActions && !isset($this->remapStackRecords[$table][$id]) && !isset($this->remapStackChildIds[$id])) {
6635 call_user_func_array($callback, $arguments);
6649 public function addRemapAction($table, $id, array $callback, array $arguments)
6651 $this->remapStackActions[] = [
6656 'callback' => $callback,
6657 'arguments' => $arguments
6669 $this->remapStackRefIndex[$table][$id] = $id;
6686 foreach ($incomingFieldArray as $field => $value) {
6687 $fieldConf =
$GLOBALS[
'TCA'][$table][
'columns'][$field][
'config'];
6688 if (
$registerDBList[$table][$id][$field] && ($foreignTable = $fieldConf[
'foreign_table'])) {
6689 $newValueArray = [];
6690 $origValueArray = is_array($value) ? $value : explode(
',', $value);
6692 foreach ($origValueArray as $childId) {
6693 $newValueArray[] = $this->autoVersionIdMap[$foreignTable][$childId] ? $this->autoVersionIdMap[$foreignTable][$childId] : $childId;
6696 $incomingFieldArray[$field] = implode(
',', $newValueArray);
6720 $res = $this->admin || (!$this->
tableAdminOnly($table) && isset($this->BE_USER->groupData[
'tables_modify']) && GeneralUtility::inList($this->BE_USER->groupData[
'tables_modify'], $table));
6724 $hookObject->checkModifyAccessList($res, $table, $this);
6738 if (!isset($this->isRecordInWebMount_Cache[$table .
':' . $id])) {
6740 $this->isRecordInWebMount_Cache[$table .
':' . $id] = $this->
isInWebMount($recP[
'event_pid']);
6742 return $this->isRecordInWebMount_Cache[$table .
':' . $id];
6753 if (!isset($this->isInWebMount_Cache[$pid])) {
6754 $this->isInWebMount_Cache[$pid] = $this->BE_USER->isInWebMount($pid);
6756 return $this->isInWebMount_Cache[$pid];
6771 if (is_array($hookObjectsArr)) {
6772 foreach ($hookObjectsArr as $hookObj) {
6773 if (method_exists($hookObj,
'checkRecordUpdateAccess')) {
6774 $res = $hookObj->checkRecordUpdateAccess($table, $id, $data, $res, $this);
6783 if (
$GLOBALS[
'TCA'][$table] && (
int)$id > 0) {
6784 $cacheId =
'checkRecordUpdateAccess' .
'_' . $table .
'_' . $id;
6787 $cachedValue = $this->runtimeCache->get($cacheId);
6788 if (!empty($cachedValue)) {
6789 return $cachedValue;
6796 $this->runtimeCache->set($cacheId, $res);
6817 if (isset($this->recInsertAccessCache[$insertTable][$pid])) {
6818 return $this->recInsertAccessCache[$insertTable][$pid];
6822 if ($insertTable ===
'pages') {
6823 $perms = $this->pMap[
'new'];
6824 } elseif (($insertTable ===
'sys_file_reference') && array_key_exists(
'pages', $this->datamap)) {
6826 $perms = $this->pMap[
'edit'];
6828 $perms = $this->pMap[
'editcontent'];
6837 $this->recInsertAccessCache[$insertTable][$pid] = $res;
6838 } elseif ($this->enableLogging) {
6840 $this->
log($insertTable, $pid, $action, 0, 1,
'Attempt to insert record on page \'%s\' (%s) where this table, %s, is not allowed', 11, [$propArr[
'header'], $pid, $insertTable], $propArr[
'event_pid']);
6842 } elseif ($this->enableLogging) {
6844 $this->
log($insertTable, $pid, $action, 0, 1,
'Attempt to insert a record on page \'%s\' (%s) from table \'%s\' without permissions. Or non-existing page.', 12, [$propArr[
'header'], $pid, $insertTable], $propArr[
'event_pid']);
6858 $page_uid = (int)$page_uid;
6859 $rootLevelSetting = (int)
$GLOBALS[
'TCA'][$checkTable][
'ctrl'][
'rootLevel'];
6861 if ($checkTable !==
'pages' && $rootLevelSetting !== -1 && ($rootLevelSetting xor !$page_uid)) {
6872 $doktype = $this->
pageInfo($page_uid,
'doktype');
6873 $allowedTableList =
$GLOBALS[
'PAGES_TYPES'][$doktype][
'allowedTables'] ??
$GLOBALS[
'PAGES_TYPES'][
'default'][
'allowedTables'];
6874 $allowedArray = GeneralUtility::trimExplode(
',', $allowedTableList,
true);
6876 if (strpos($allowedTableList,
'*') !==
false || in_array($checkTable, $allowedArray,
true)) {
6910 $cacheId = md5(
'doesRecordExist_pageLookUp' .
'_' . $id .
'_' . $perms .
'_' . implode(
6913 ) .
'_' . (
string)$this->admin);
6916 $cachedResult = $this->runtimeCache->get($cacheId);
6917 if (!empty($cachedResult)) {
6918 return $cachedResult;
6921 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
'pages');
6924 ->select(...$columns)
6926 ->where($queryBuilder->expr()->eq(
6928 $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)
6930 if ($perms && !$this->admin) {
6931 $queryBuilder->andWhere($this->BE_USER->getPagePermsClause($perms));
6933 if (!$this->admin &&
$GLOBALS[
'TCA'][
'pages'][
'ctrl'][
'editlock'] &&
6936 $queryBuilder->andWhere($queryBuilder->expr()->eq(
6937 $GLOBALS[
'TCA'][
'pages'][
'ctrl'][
'editlock'],
6938 $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
6942 $row = $queryBuilder->execute()->fetch();
6943 $this->runtimeCache->set($cacheId, $row);
6963 $perms = (int)$perms;
6965 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
'pages');
6967 $result = $queryBuilder
6968 ->select(
'uid',
'perms_userid',
'perms_groupid',
'perms_user',
'perms_group',
'perms_everybody')
6970 ->where($queryBuilder->expr()->eq(
'pid', $queryBuilder->createNamedParameter($pid, \PDO::PARAM_INT)))
6971 ->orderBy(
'sorting')
6973 while ($row = $result->fetch()) {
6975 if ($this->admin || $this->BE_USER->doesUserHaveAccess($row, $perms)) {
6976 $inList .= $row[
'uid'] .
',';
6980 if ($inList === -1) {
7002 return (
bool)
$GLOBALS[
'TCA'][$table][
'ctrl'][
'readOnly'];
7014 return !empty(
$GLOBALS[
'TCA'][$table][
'ctrl'][
'adminOnly']);
7028 $destinationId = (int)$destinationId;
7030 if ($destinationId === $id) {
7033 while ($destinationId !== 0 && $loopCheck > 0) {
7035 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
'pages');
7037 $result = $queryBuilder
7038 ->select(
'pid',
'uid',
't3ver_oid',
't3ver_wsid')
7040 ->where($queryBuilder->expr()->eq(
'uid', $queryBuilder->createNamedParameter($destinationId, \PDO::PARAM_INT)))
7042 if ($row = $result->fetch()) {
7044 if ($row[
'pid'] == $id) {
7047 $destinationId = (int)$row[
'pid'];
7064 if (isset($this->BE_USER->groupData[
'non_exclude_fields'])) {
7065 $nonExcludeFieldsArray = array_flip(GeneralUtility::trimExplode(
',', $this->BE_USER->groupData[
'non_exclude_fields']));
7066 foreach (
$GLOBALS[
'TCA'] as $table => $tableConfiguration) {
7067 if (isset($tableConfiguration[
'columns'])) {
7068 foreach ($tableConfiguration[
'columns'] as $field => $config) {
7069 if ($config[
'exclude'] && !isset($nonExcludeFieldsArray[$table .
':' . $field])) {
7070 $list[] = $table .
'-' . $field;
7089 $page_uid = (int)$page_uid;
7094 $allowedTableList =
$GLOBALS[
'PAGES_TYPES'][$doktype][
'allowedTables'] ??
$GLOBALS[
'PAGES_TYPES'][
'default'][
'allowedTables'];
7096 if (strpos($allowedTableList,
'*') !==
false) {
7099 $allowedArray = GeneralUtility::trimExplode(
',', $allowedTableList,
true);
7102 foreach ($allTableNames as $table) {
7104 if (in_array($table, $allowedArray,
true)) {
7107 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
7108 $queryBuilder->getRestrictions()->removeAll();
7109 $count = $queryBuilder
7112 ->where($queryBuilder->expr()->eq(
7114 $queryBuilder->createNamedParameter($page_uid, \PDO::PARAM_INT)
7119 $tableList[] = $table;
7122 return implode(
',', $tableList);
7140 if (!isset($this->pageCache[$id])) {
7141 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
'pages');
7142 $queryBuilder->getRestrictions()->removeAll();
7143 $row = $queryBuilder
7146 ->where($queryBuilder->expr()->eq(
'uid', $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)))
7150 $this->pageCache[$id] = $row;
7153 return $this->pageCache[$id][$field];
7165 public function recordInfo($table, $id, $fieldList)
7168 if ((
int)$id === 0 || !isset(
$GLOBALS[
'TCA'][$table])) {
7171 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
7172 $queryBuilder->getRestrictions()->removeAll();
7173 $result = $queryBuilder
7174 ->select(...GeneralUtility::trimExplode(
',', $fieldList))
7176 ->where($queryBuilder->expr()->eq(
'uid', $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)))
7179 return $result ?:
null;
7194 if ($this->bypassAccessCheckForRecords) {
7195 $columns = GeneralUtility::trimExplode(
',', $fieldList,
true);
7197 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
7198 $queryBuilder->getRestrictions()->removeAll();
7200 $record = $queryBuilder->select(...$columns)
7202 ->where($queryBuilder->expr()->eq(
'uid', $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)))
7206 return $record ?:
false;
7210 if ($table !==
'pages') {
7218 if ($table ===
'sys_file_reference' && array_key_exists(
'pages', $this->datamap)) {
7221 $perms =
'editcontent';
7226 $perms = (int)$this->pMap[$perms];
7228 $perms = (int)$perms;
7231 throw new \RuntimeException(
'Internal ERROR: no permissions to check for non-admin user', 1270853920);
7236 $columns = GeneralUtility::trimExplode(
',', $fieldList,
true);
7237 if ($table !==
'pages') {
7240 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
7243 ->select(...$columns)
7245 ->where($queryBuilder->expr()->eq(
'uid', $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)))
7255 if (is_array($pageRec) || !
$output[
'pid'] && ($this->admin || $isRootLevelRestrictionIgnored)) {
7279 $row = $table ===
'pages' && !$id ? [
'title' =>
'[root-level]',
'uid' => 0,
'pid' => 0] : $this->
recordInfo($table, $id,
'*');
7299 'pid' => $row[
'pid'],
7300 'event_pid' => $this->
eventPid($table, isset($row[
'_ORIG_pid']) ? $row[
't3ver_oid'] : $row[
'uid'], $row[
'pid']),
7301 't3ver_state' =>
$GLOBALS[
'TCA'][$table][
'ctrl'][
'versioningWS'] ? $row[
't3ver_state'] :
'',
7302 '_ORIG_pid' => $row[
'_ORIG_pid']
7314 public function eventPid($table, $uid, $pid)
7316 return $table ===
'pages' ? $uid : $pid;
7332 public function updateDB($table, $id, $fieldArray)
7334 if (is_array($fieldArray) && is_array(
$GLOBALS[
'TCA'][$table]) && (
int)$id) {
7336 unset($fieldArray[
'uid']);
7337 if (!empty($fieldArray)) {
7340 $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($table);
7343 $platform = $connection->getDatabasePlatform();
7344 if ($platform instanceof SQLServerPlatform) {
7346 $tableDetails = $connection->getSchemaManager()->listTableDetails($table);
7347 foreach ($fieldArray as $columnName => $columnValue) {
7348 $types[$columnName] = $tableDetails->getColumn($columnName)->getType()->getBindingType();
7353 $updateErrorMessage =
'';
7355 $connection->
update($table, $fieldArray, [
'uid' => (
int)$id], $types);
7356 }
catch (DBALException $e) {
7357 $updateErrorMessage = $e->getPrevious()->getMessage();
7360 if ($updateErrorMessage ===
'') {
7364 $historyEntryId = 0;
7365 if (isset($this->historyRecords[$table .
':' . $id])) {
7368 if ($this->enableLogging) {
7369 if ($this->checkStoredRecords) {
7372 $newRow = $fieldArray;
7373 $newRow[
'uid'] = $id;
7377 $this->
log($table, $id, 2, $propArr[
'pid'], 0,
'Record \'%s\' (%s) was updated.' . ($propArr[
'_ORIG_pid'] == -1 ?
' (Offline version).' :
' (Online).'), 10, [$propArr[
'header'], $table .
':' . $id,
'history' => $historyEntryId], $propArr[
'event_pid']);
7382 if ($table ===
'pages') {
7383 unset($this->pageCache[$id]);
7386 $this->
log($table, $id, 2, 0, 2,
'SQL error: \'%s\' (%s)', 12, [$updateErrorMessage, $table .
':' . $id]);
7404 public function insertDB($table, $id, $fieldArray, $newVersion =
false, $suggestedUid = 0, $dontSetNewIdIndex =
false)
7406 if (is_array($fieldArray) && is_array(
$GLOBALS[
'TCA'][$table]) && isset($fieldArray[
'pid'])) {
7408 unset($fieldArray[
'uid']);
7409 if (!empty($fieldArray)) {
7414 $suggestedUid = (int)$suggestedUid;
7415 if ($this->BE_USER->isAdmin() && $suggestedUid && $this->suggestedInsertUids[$table .
':' . $suggestedUid]) {
7417 if ($this->suggestedInsertUids[$table .
':' . $suggestedUid] ===
'DELETE') {
7419 GeneralUtility::makeInstance(ConnectionPool::class)
7420 ->getConnectionForTable($table)
7421 ->delete($table, [
'uid' => (
int)$suggestedUid]);
7423 $fieldArray[
'uid'] = $suggestedUid;
7427 if (!empty(
$GLOBALS[
'TCA'][$table][
'ctrl'][
'transOrigDiffSourceField'])
7428 && array_key_exists(
$GLOBALS[
'TCA'][$table][
'ctrl'][
'transOrigDiffSourceField'], $fieldArray)
7432 $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($table);
7433 $insertErrorMessage =
'';
7441 }
catch (DBALException $e) {
7442 $insertErrorMessage = $e->getPrevious()->getMessage();
7445 if ($insertErrorMessage ===
'') {
7451 if (!$dontSetNewIdIndex) {
7452 $this->substNEWwithIDs[$NEW_id] = $id;
7453 $this->substNEWwithIDs_table[$NEW_id] = $table;
7456 if ($this->enableLogging) {
7458 if ($this->checkStoredRecords) {
7461 $newRow = $fieldArray;
7462 $newRow[
'uid'] = $id;
7472 if ($this->enableLogging) {
7474 $this->
log($table, $id, 1, 0, 0,
'New version created of table \'%s\', uid \'%s\'. UID of new version is \'%s\'', 10, [$table, $fieldArray[
't3ver_oid'], $id], $propArr[
'event_pid'], $NEW_id);
7477 if ($this->enableLogging) {
7480 $this->
log($table, $id, 1, 0, 0,
'Record \'%s\' (%s) was inserted on page \'%s\' (%s)', 10, [$propArr[
'header'], $table .
':' . $id, $page_propArr[
'header'], $newRow[
'pid']], $newRow[
'pid'], $NEW_id);
7487 if ($this->enableLogging) {
7488 $this->
log($table, $id, 1, 0, 2,
'SQL error: \'%s\' (%s)', 12, [$insertErrorMessage, $table .
':' . $id]);
7508 if (is_array(
$GLOBALS[
'TCA'][$table]) && $id) {
7509 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
7510 $queryBuilder->getRestrictions()->removeAll();
7512 $row = $queryBuilder
7515 ->where($queryBuilder->expr()->eq(
'uid', $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)))
7522 foreach ($fieldArray as $key => $value) {
7523 if (!$this->checkStoredRecords_loose || $value || $row[$key]) {
7524 if (is_float($row[$key])) {
7526 if ((
double)$value !== (
double)$row[$key]) {
7530 $dbType =
$GLOBALS[
'TCA'][$table][
'columns'][$key][
'config'][
'dbType'] ??
false;
7531 if ($dbType ===
'datetime' || $dbType ===
'time') {
7534 if ((
string)$value !== (
string)$row[$key]) {
7538 if (is_numeric($value) && is_numeric($row[$key])) {
7539 if ((
double)$value === (
double)$row[$key]) {
7551 'These fields of record %d in table "%s" have not been saved correctly: %s! The values might have changed due to type casting of the database.',
7556 $this->
log($table, $id, $action, 0, 1, $message);
7576 if (isset($this->historyRecords[$table .
':' . $id])) {
7580 $this->historyRecords[$table .
':' . $id]
7590 return GeneralUtility::makeInstance(
7591 RecordHistoryStore::class,
7593 $this->BE_USER->user[
'uid'],
7594 $this->BE_USER->user[
'ses_backuserid'] ??
null,
7596 $this->BE_USER->workspace
7610 $refIndexObj = GeneralUtility::makeInstance(ReferenceIndex::class);
7612 $refIndexObj->setWorkspaceId($this->BE_USER->workspace);
7614 $refIndexObj->enableRuntimeCache();
7615 $refIndexObj->updateRefIndexTable($table, $id);
7655 $sortColumn =
$GLOBALS[
'TCA'][$table][
'ctrl'][
'sortby'] ??
'';
7660 $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
7661 $queryBuilder = $connectionPool->getQueryBuilderForTable($table);
7665 ->select($sortColumn,
'pid',
'uid')
7671 $row = $queryBuilder
7672 ->where($queryBuilder->expr()->eq(
'pid', $queryBuilder->createNamedParameter($pid, \PDO::PARAM_INT)))
7673 ->orderBy($sortColumn,
'ASC')
7674 ->addOrderBy(
'uid',
'ASC')
7681 if ($row[
'uid'] == $uid) {
7682 return $row[$sortColumn];
7685 if ($row[$sortColumn] < 1) {
7691 return floor($row[$sortColumn] / 2);
7699 $row = $queryBuilder
7700 ->where($queryBuilder->expr()->eq(
7702 $queryBuilder->createNamedParameter(abs($pid), \PDO::PARAM_INT)
7713 $row = $lookForLiveVersion;
7717 $row = $movePlaceholder;
7720 if ((
int)$row[
'uid'] === (
int)$uid) {
7721 $sortNumber = $row[$sortColumn];
7723 $queryBuilder = $connectionPool->getQueryBuilderForTable($table);
7726 $subResults = $queryBuilder
7727 ->select($sortColumn,
'pid',
'uid')
7730 $queryBuilder->expr()->eq(
7732 $queryBuilder->createNamedParameter($row[
'pid'], \PDO::PARAM_INT)
7734 $queryBuilder->expr()->gte(
7736 $queryBuilder->createNamedParameter($row[$sortColumn], \PDO::PARAM_INT)
7739 ->orderBy($sortColumn,
'ASC')
7740 ->addOrderBy(
'uid',
'DESC')
7746 if (count($subResults) === 2) {
7748 $subrow = array_pop($subResults);
7750 $sortNumber = $row[$sortColumn] + floor(($subrow[$sortColumn] - $row[$sortColumn]) / 2);
7752 if ($sortNumber <= $row[$sortColumn] || $sortNumber >= $subrow[$sortColumn]) {
7761 return [
'pid' => $row[
'pid'],
'sortNumber' => $sortNumber];
7763 if ($this->enableLogging) {
7766 $this->
log($table, $uid, 4, 0, 1,
'Attempt to move record \'%s\' (%s) to after a non-existing record (uid=%s)', 1, [$propArr[
'header'], $table .
':' . $uid, abs($pid)], $propArr[
'pid']);
7785 public function resorting($table, $pid, $sortColumn, $return_SortNumber_After_This_Uid)
7787 trigger_error(
'DataHandler->resorting() will be removed in TYPO3 v10.0, use the increaseSortingOfFollowingRecords() function instead.', E_USER_DEPRECATED);
7789 $sortBy =
$GLOBALS[
'TCA'][$table][
'ctrl'][
'sortby'] ??
'';
7790 if ($sortBy && $sortBy === $sortColumn) {
7793 $i = $intervals * 2;
7794 $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($table);
7798 $result = $queryBuilder
7801 ->where($queryBuilder->expr()->eq(
'pid', $queryBuilder->createNamedParameter($pid, \PDO::PARAM_INT)))
7802 ->orderBy($sortColumn,
'ASC')
7803 ->addOrderBy(
'uid',
'ASC')
7805 if ($connection->getDatabasePlatform() instanceof SqlitePlatform) {
7813 $result = $result->fetchAll();
7814 foreach ($result as $row) {
7815 $uid = (int)$row[
'uid'];
7817 $connection->
update($table, [$sortColumn => $i], [
'uid' => (
int)$uid]);
7819 if ($uid == $return_SortNumber_After_This_Uid) {
7824 die(
'Fatal ERROR!! No Uid at resorting.');
7829 while ($row = $result->fetch()) {
7831 $uid = (int)$row[
'uid'];
7833 $connection->
update($table, [$sortColumn => $i], [
'uid' => (
int)$uid]);
7835 if ($uid == $return_SortNumber_After_This_Uid) {
7840 die(
'Fatal ERROR!! No Uid at resorting.');
7862 $sortBy =
$GLOBALS[
'TCA'][$table][
'ctrl'][
'sortby'] ??
'';
7864 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
7868 ->where($queryBuilder->expr()->eq(
'pid', $queryBuilder->createNamedParameter($pid, \PDO::PARAM_INT)))
7869 ->set($sortBy, $queryBuilder->quoteIdentifier($sortBy) .
' + ' . $this->sortIntervals .
' + ' . $this->sortIntervals,
false);
7870 if ($sortingValue !==
null) {
7871 $queryBuilder->andWhere($queryBuilder->expr()->gt($sortBy, $sortingValue));
7874 $deleteColumn =
$GLOBALS[
'TCA'][$table][
'ctrl'][
'delete'] ??
'';
7875 if ($deleteColumn) {
7876 $queryBuilder->andWhere($queryBuilder->expr()->eq($deleteColumn, 0));
7879 $queryBuilder->execute();
7902 $previousLocalizedRecordUid = $uid;
7903 $sortColumn =
$GLOBALS[
'TCA'][$table][
'ctrl'][
'sortby'] ??
'';
7905 $select = [$sortColumn,
'pid',
'uid'];
7907 if ($table ===
'tt_content') {
7908 $select[] =
'colPos';
7912 if (is_array($row)) {
7913 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
7917 ->select(...$select)
7920 $queryBuilder->expr()->eq(
7922 $queryBuilder->createNamedParameter($pid, \PDO::PARAM_INT)
7924 $queryBuilder->expr()->eq(
7925 $GLOBALS[
'TCA'][$table][
'ctrl'][
'languageField'],
7926 $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
7928 $queryBuilder->expr()->lt(
7930 $queryBuilder->createNamedParameter($row[$sortColumn], \PDO::PARAM_INT)
7933 ->orderBy($sortColumn,
'DESC')
7934 ->addOrderBy(
'uid',
'DESC')
7936 if ($table ===
'tt_content') {
7939 $queryBuilder->expr()->eq(
7941 $queryBuilder->createNamedParameter($row[
'colPos'], \PDO::PARAM_INT)
7946 if ($previousRow = $queryBuilder->execute()->fetch()) {
7948 if (is_array($previousLocalizedRecord[0])) {
7949 $previousLocalizedRecordUid = $previousLocalizedRecord[0][
'uid'];
7954 return $previousLocalizedRecordUid;
7967 if ((
string)$TSConfig_p[
'userid'] !==
'') {
7968 $fieldArray[
'perms_userid'] = (int)$TSConfig_p[
'userid'];
7970 if ((
string)$TSConfig_p[
'groupid'] !==
'') {
7971 $fieldArray[
'perms_groupid'] = (int)$TSConfig_p[
'groupid'];
7973 if ((
string)$TSConfig_p[
'user'] !==
'') {
7976 if ((
string)$TSConfig_p[
'group'] !==
'') {
7979 if ((
string)$TSConfig_p[
'everybody'] !==
'') {
7995 if (is_array(
$GLOBALS[
'TCA'][$table][
'columns'])) {
7996 foreach (
$GLOBALS[
'TCA'][$table][
'columns'] as $field => $content) {
7997 if (isset($this->defaultValues[$table][$field])) {
7998 $fieldArray[$field] = $this->defaultValues[$table][$field];
7999 } elseif (isset($content[
'config'][
'default'])) {
8000 $fieldArray[$field] = $content[
'config'][
'default'];
8005 if ($table ===
'pages') {
8007 $fieldArray[
'perms_groupid'] = (int)$this->BE_USER->firstMainGroup;
8008 $fieldArray[
'perms_user'] = $this->assemblePermissions($this->defaultPermissions[
'user']);
8010 $fieldArray[
'perms_everybody'] = $this->
assemblePermissions($this->defaultPermissions[
'everybody']);
8024 if (
$GLOBALS[
'TCA'][$table][
'ctrl'][
'languageField']) {
8025 if (!isset($incomingFieldArray[
$GLOBALS[
'TCA'][$table][
'ctrl'][
'languageField']])) {
8027 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
8028 ->getQueryBuilderForTable(
'sys_language');
8029 $queryBuilder->getRestrictions()
8031 ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
8034 ->from(
'sys_language')
8035 ->where($queryBuilder->expr()->eq(
'pid', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)));
8036 $rows = array_merge([[
'uid' => 0]], $queryBuilder->execute()->fetchAll(), [[
'uid' => -1]]);
8037 foreach ($rows as $r) {
8038 if ($this->BE_USER->checkLanguageAccess($r[
'uid'])) {
8039 $incomingFieldArray[
$GLOBALS[
'TCA'][$table][
'ctrl'][
'languageField']] = $r[
'uid'];
8056 if (is_array($this->overrideValues[$table])) {
8057 $data = array_merge($data, $this->overrideValues[$table]);
8073 $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($table);
8076 $currentRecord = $queryBuilder->select(
'*')
8078 ->where($queryBuilder->expr()->eq(
'uid', $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)))
8082 if (is_array($currentRecord)) {
8083 $tableDetails = $connection->getSchemaManager()->listTableDetails($table);
8084 $columnRecordTypes = [];
8085 foreach ($currentRecord as $columnName => $_) {
8086 $columnRecordTypes[$columnName] =
'';
8087 $type = $tableDetails->getColumn($columnName)->getType();
8088 if ($type instanceof IntegerType) {
8089 $columnRecordTypes[$columnName] =
'int';
8093 foreach ($fieldArray as $col => $val) {
8094 $fieldConfiguration =
$GLOBALS[
'TCA'][$table][
'columns'][$col][
'config'];
8095 $isNullField = (!empty($fieldConfiguration[
'eval']) && GeneralUtility::inList($fieldConfiguration[
'eval'],
'null'));
8100 unset($fieldArray[$col]);
8102 if (!isset($this->mmHistoryRecords[$table .
':' . $id][
'oldRecord'][$col])) {
8103 $this->historyRecords[$table .
':' . $id][
'oldRecord'][$col] = $currentRecord[$col];
8104 } elseif ($this->mmHistoryRecords[$table .
':' . $id][
'oldRecord'][$col] != $this->mmHistoryRecords[$table .
':' . $id][
'newRecord'][$col]) {
8105 $this->historyRecords[$table .
':' . $id][
'oldRecord'][$col] = $this->mmHistoryRecords[$table .
':' . $id][
'oldRecord'][$col];
8107 if (!isset($this->mmHistoryRecords[$table .
':' . $id][
'newRecord'][$col])) {
8108 $this->historyRecords[$table .
':' . $id][
'newRecord'][$col] = $fieldArray[$col];
8109 } elseif ($this->mmHistoryRecords[$table .
':' . $id][
'newRecord'][$col] != $this->mmHistoryRecords[$table .
':' . $id][
'oldRecord'][$col]) {
8110 $this->historyRecords[$table .
':' . $id][
'newRecord'][$col] = $this->mmHistoryRecords[$table .
':' . $id][
'newRecord'][$col];
8138 $result = (string)$submittedValue === (
string)$storedValue || $storedType ===
'int' && (int)$storedValue === (
int)$submittedValue;
8141 } elseif ($storedValue !==
null) {
8143 $submittedValue !==
null
8149 $result = ($submittedValue ===
null);
8164 $keyArr = GeneralUtility::trimExplode(
',', $string,
true);
8166 foreach ($keyArr as $key) {
8167 if ($key && isset($this->pMap[$key])) {
8168 $value |= $this->pMap[$key];
8182 $token = md5(microtime());
8183 $parts = explode($token, preg_replace(
'/(&#([0-9]+);)/', $token .
'\\2' . $token, $input));
8184 foreach ($parts as $k => $v) {
8189 $parts[$k] = chr($v);
8193 return implode(
'', $parts);
8216 return ' AND ' . $table .
'.' .
$GLOBALS[
'TCA'][$table][
'ctrl'][
'delete'] .
'=0';
8229 $restrictions->add(GeneralUtility::makeInstance(DeletedRestriction::class));
8243 if (isset(self::$recordPidsForDeletedRecords[$table][$uid])) {
8244 return self::$recordPidsForDeletedRecords[$table][$uid];
8247 return [$parentUid];
8259 trigger_error(
'Method getTCEMAIN_TSconfig() will be removed in TYPO3 v10.0.', E_USER_DEPRECATED);
8272 $tA = is_array($TSconfig[
'table.'][$table .
'.']) ? $TSconfig[
'table.'][$table .
'.'] : [];
8273 $dA = is_array($TSconfig[
'default.']) ? $TSconfig[
'default.'] : [];
8285 public function getPID($table, $uid)
8287 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
8288 $queryBuilder->getRestrictions()
8290 $queryBuilder->select(
'pid')
8292 ->where($queryBuilder->expr()->eq(
'uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)));
8293 if ($row = $queryBuilder->execute()->fetch()) {
8305 foreach ($this->dbAnalysisStore as $action) {
8308 $action[0]->writeMM($action[1], $id, $action[3]);
8318 foreach ($this->removeFilesStore as $file) {
8319 if (@is_file($file)) {
8339 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
'pages');
8340 $restrictions = $queryBuilder->getRestrictions()->removeAll();
8345 ->where($queryBuilder->expr()->eq(
'pid', $queryBuilder->createNamedParameter($pid, \PDO::PARAM_INT)))
8346 ->orderBy(
'sorting',
'DESC');
8347 if (!$this->admin) {
8348 $queryBuilder->andWhere($this->BE_USER->getPagePermsClause($this->pMap[
'show']));
8350 if ((
int)$this->BE_USER->workspace === 0) {
8351 $queryBuilder->andWhere(
8352 $queryBuilder->expr()->eq(
't3ver_wsid', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT))
8355 $queryBuilder->andWhere($queryBuilder->expr()->in(
8357 $queryBuilder->createNamedParameter([0, $this->BE_USER->workspace], Connection::PARAM_INT_ARRAY)
8360 $result = $queryBuilder->execute();
8363 while ($row = $result->fetch()) {
8364 $pages[$row[
'uid']] = $row;
8368 if (!empty($pages) && (
int)$this->BE_USER->workspace !== 0) {
8369 $pages = array_reverse(
8380 foreach ($pages as $page) {
8381 if ($page[
'uid'] != $rootID) {
8382 $CPtable[$page[
'uid']] = $pid;
8385 $CPtable = $this->
int_pageTreeInfo($CPtable, $page[
'uid'], $counter - 1, $rootID);
8417 foreach (
$GLOBALS[
'TCA'][$table][
'columns'] as $field => $conf) {
8418 if ($conf[
'config'][
'type'] ===
'input' && (
string)$curData[$field] !==
'') {
8419 $evalCodesArray = GeneralUtility::trimExplode(
',', $conf[
'config'][
'eval'],
true);
8420 if (in_array(
'uniqueInPid', $evalCodesArray,
true)) {
8421 $newV = $this->
getUnique($table, $field, $curData[$field], $uid, $curData[
'pid']);
8422 if ((
string)$newV !== (
string)$curData[$field]) {
8423 $newData[$field] = $newV;
8429 if (!empty($newData)) {
8430 $this->
updateDB($table, $uid, $newData);
8444 $workspaceId = $this->BE_USER->workspace;
8446 foreach (
$GLOBALS[
'TCA'][$table][
'columns'] as $field => $conf) {
8447 if ($conf[
'config'][
'type'] ===
'slug' && (
string)$curData[$field] !==
'') {
8448 $evalCodesArray = GeneralUtility::trimExplode(
',', $conf[
'config'][
'eval'],
true);
8449 if (in_array(
'uniqueInSite', $evalCodesArray,
true)) {
8450 $helper = GeneralUtility::makeInstance(SlugHelper::class, $table, $field, $conf[
'config'], $workspaceId);
8452 $newValue = $helper->buildSlugForUniqueInSite($curData[$field], $state);
8453 if ((
string)$newValue !== (
string)$curData[$field]) {
8454 $newData[$field] = $newValue;
8460 if (!empty($newData)) {
8461 $this->
updateDB($table, $uid, $newData);
8477 foreach ($subPages as $thePageUid => $thePagePid) {
8479 if ($recordWasModified) {
8498 if (
$GLOBALS[
'TCA'][$table] &&
$GLOBALS[
'TCA'][$table][
'ctrl'][
'copyAfterDuplFields']) {
8499 $prevData = $this->
recordInfo($table, $prevUid,
'*');
8500 $theFields = GeneralUtility::trimExplode(
',',
$GLOBALS[
'TCA'][$table][
'ctrl'][
'copyAfterDuplFields'],
true);
8501 foreach ($theFields as $field) {
8502 if (
$GLOBALS[
'TCA'][$table][
'columns'][$field] && ($update || !isset($newData[$field]))) {
8503 $newData[$field] = $prevData[$field];
8506 if ($update && !empty($newData)) {
8507 $this->
updateDB($table, $uid, $newData);
8523 if (isset(
$GLOBALS[
'TCA'][$table][
'columns'])) {
8524 foreach (
$GLOBALS[
'TCA'][$table][
'columns'] as $field => $configArr) {
8525 if ($configArr[
'config'][
'type'] ===
'group' && ($configArr[
'config'][
'internal_type'] ===
'file' || $configArr[
'config'][
'internal_type'] ===
'file_reference')) {
8526 $listArr[] = $field;
8547 if ((
string)$value !==
'') {
8551 if (!empty($configuration[
'MM']) || !empty($configuration[
'foreign_field'])) {
8555 if (array_key_exists(
'default', $configuration)) {
8556 return $configuration[
'default'];
8570 return $conf[
'type'] ===
'group' && $conf[
'internal_type'] ===
'db' || $conf[
'type'] ===
'select' && $conf[
'foreign_table'];
8582 if ($conf[
'type'] !==
'inline' || !$conf[
'foreign_table']) {
8585 if ($conf[
'foreign_field']) {
8608 public function getCopyHeader($table, $pid, $field, $value, $count, $prevTitle =
'')
8611 $checkTitle = $value;
8613 $checkTitle = $value . rtrim(
' ' . sprintf($this->
prependLabel($table), $count));
8616 if ($prevTitle != $checkTitle || $count < 100) {
8617 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
8619 $rowCount = $queryBuilder
8623 $queryBuilder->expr()->eq(
'pid', $queryBuilder->createNamedParameter($pid, \PDO::PARAM_INT)),
8624 $queryBuilder->expr()->eq($field, $queryBuilder->createNamedParameter($checkTitle, \PDO::PARAM_STR))
8629 return $this->
getCopyHeader($table, $pid, $field, $value, $count + 1, $checkTitle);
8659 $query = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
8660 $query->getRestrictions()
8665 ->where($query->expr()->eq(
'uid', $query->createNamedParameter(abs($pid), \PDO::PARAM_INT)))
8670 $row = $lookForLiveVersion;
8672 $pid = (int)$row[
'pid'];
8686 $regex =
'/\s' . sprintf(preg_quote($this->
prependLabel($table)),
'[0-9]*') .
'$/';
8687 return @preg_replace($regex,
'', $value);
8700 $uploadFolder =
$GLOBALS[
'TCA'][$table][
'columns'][$field][
'config'][
'uploadfolder'];
8701 if ($uploadFolder && trim($filelist) &&
$GLOBALS[
'TCA'][$table][
'columns'][$field][
'config'][
'internal_type'] ===
'file') {
8703 $fileArray = GeneralUtility::trimExplode(
',', $filelist,
true);
8704 foreach ($fileArray as $theFile) {
8705 $theFileFullPath = $uploadPath .
'/' . $theFile;
8706 if (@is_file($theFileFullPath)) {
8709 $this->
log($table, 0, 3, 0, 100,
'Delete: Referenced file that was supposed to be deleted together with it\'s record didn\'t exist');
8728 if (!empty($pageIds)) {
8730 foreach ($tableNames as $table) {
8731 $query = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
8732 $query->getRestrictions()
8734 ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
8735 $count = $query->count(
'uid')
8737 ->where($query->expr()->in(
8739 $query->createNamedParameter($pageIds, Connection::PARAM_INT_ARRAY)
8761 if (isset($this->copyMappingArray[$table][$uid])) {
8764 if (isset($this->copyMappingArray[$table]) && in_array($uid, array_values($this->copyMappingArray[$table]))) {
8788 if (!is_array(static::$recordsToClearCacheFor[$table])) {
8789 static::$recordsToClearCacheFor[$table] = [];
8791 static::$recordsToClearCacheFor[$table][] = (int)$uid;
8792 if ($pid !==
null) {
8793 if (!is_array(static::$recordPidsForDeletedRecords[$table])) {
8794 static::$recordPidsForDeletedRecords[$table] = [];
8796 static::$recordPidsForDeletedRecords[$table][$uid][] = (int)$pid;
8806 $clearCacheCommands = [];
8808 foreach (static::$recordsToClearCacheFor as $table => $uids) {
8809 foreach (array_unique($uids) as $uid) {
8810 if (!isset(
$GLOBALS[
'TCA'][$table]) || $uid <= 0) {
8815 foreach ($pageUids as $originalParent) {
8816 list($tagsToClearFromPrepare, $clearCacheCommandsFromPrepare)
8818 $tagsToClear = array_merge($tagsToClear, $tagsToClearFromPrepare);
8819 $clearCacheCommands = array_merge($clearCacheCommands, $clearCacheCommandsFromPrepare);
8826 $cacheManager->flushCachesInGroupByTags(
'pages', array_keys($tagsToClear));
8829 $clearCacheCommands = array_unique($clearCacheCommands);
8831 foreach ($clearCacheCommands as $command) {
8836 static::$recordsToClearCacheFor = [];
8839 static::$recordPidsForDeletedRecords = [];
8854 $clearCacheCommands = [];
8858 if (empty($TSConfig[
'clearCache_disable'])) {
8859 $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
8861 $pageIdsThatNeedCacheFlush = [];
8862 if ($table ===
'pages') {
8867 $queryBuilder = $connectionPool->getQueryBuilderForTable(
'pages');
8868 $queryBuilder->getRestrictions()
8870 ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
8871 $siblings = $queryBuilder
8872 ->select(
'A.pid AS pid',
'B.uid AS uid')
8873 ->from(
'pages',
'A')
8874 ->from(
'pages',
'B')
8876 $queryBuilder->expr()->eq(
'A.uid', $queryBuilder->createNamedParameter($pageUid, \PDO::PARAM_INT)),
8877 $queryBuilder->expr()->eq(
'B.pid', $queryBuilder->quoteIdentifier(
'A.pid')),
8878 $queryBuilder->expr()->gte(
'A.pid', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT))
8883 while ($row_tmp = $siblings->fetch()) {
8884 $pageIdsThatNeedCacheFlush[] = (int)$row_tmp[
'uid'];
8885 $parentPageId = (int)$row_tmp[
'pid'];
8887 if ($TSConfig[
'clearCache_pageSiblingChildren']) {
8888 $siblingChildrenQuery = $connectionPool->getQueryBuilderForTable(
'pages');
8889 $siblingChildrenQuery->getRestrictions()
8891 ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
8892 $siblingChildren = $siblingChildrenQuery
8895 ->where($siblingChildrenQuery->expr()->eq(
8897 $siblingChildrenQuery->createNamedParameter($row_tmp[
'uid'], \PDO::PARAM_INT)
8900 while ($row_tmp2 = $siblingChildren->fetch()) {
8901 $pageIdsThatNeedCacheFlush[] = (int)$row_tmp2[
'uid'];
8906 if ($parentPageId > 0) {
8907 $pageIdsThatNeedCacheFlush[] = $parentPageId;
8910 if ($TSConfig[
'clearCache_pageGrandParent']) {
8911 $parentQuery = $connectionPool->getQueryBuilderForTable(
'pages');
8912 $parentQuery->getRestrictions()
8914 ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
8915 $row_tmp = $parentQuery
8918 ->where($parentQuery->expr()->eq(
8920 $parentQuery->createNamedParameter($parentPageId, \PDO::PARAM_INT)
8924 if (!empty($row_tmp)) {
8925 $pageIdsThatNeedCacheFlush[] = (int)$row_tmp[
'pid'];
8930 $pageIdsThatNeedCacheFlush[] = $pageUid = (int)$this->
getPID($table, $uid);
8932 if ($TSConfig[
'clearCache_pageGrandParent']) {
8933 $parentQuery = $connectionPool->getQueryBuilderForTable(
'pages');
8934 $parentQuery->getRestrictions()
8936 ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
8937 $parentPageRecord = $parentQuery
8940 ->where($parentQuery->expr()->eq(
8942 $parentQuery->createNamedParameter($pageUid, \PDO::PARAM_INT)
8946 if (!empty($parentPageRecord)) {
8947 $pageIdsThatNeedCacheFlush[] = (int)$parentPageRecord[
'pid'];
8952 foreach (
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
't3lib/class.t3lib_tcemain.php'][
'clearPageCacheEval'] ?? [] as $funcName) {
8953 $_params = [
'pageIdArray' => &$pageIdsThatNeedCacheFlush,
'table' => $table,
'uid' => $uid,
'functionID' =>
'clear_cache()'];
8955 GeneralUtility::callUserFunction($funcName, $_params, $this);
8958 foreach ($pageIdsThatNeedCacheFlush as $pageId) {
8963 $tagsToClear[
'pageId_' . $pageId] =
true;
8967 $tagsToClear[$table] =
true;
8968 $tagsToClear[$table .
'_' . $uid] =
true;
8971 if (!empty($TSConfig[
'clearCacheCmd'])) {
8972 $commands = GeneralUtility::trimExplode(
',', $TSConfig[
'clearCacheCmd'],
true);
8973 $clearCacheCommands = array_unique($commands);
8976 $_params = [
'table' => $table,
'uid' => $uid,
'uid_page' => $pageUid,
'TSConfig' => $TSConfig,
'tags' => $tagsToClear];
8977 foreach (
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
't3lib/class.t3lib_tcemain.php'][
'clearCachePostProc'] ?? [] as $_funcRef) {
8978 GeneralUtility::callUserFunction($_funcRef, $_params, $this);
9025 if (is_object($this->BE_USER)) {
9026 $this->BE_USER->writelog(3, 1, 0, 0,
'User %s has cleared the cache (cacheCmd=%s)', [$this->BE_USER->user[
'username'], $cacheCmd]);
9028 $userTsConfig = $this->BE_USER->getTSConfig();
9029 switch (strtolower($cacheCmd)) {
9031 if ($this->admin || ($userTsConfig[
'options.'][
'clearCache.'][
'pages'] ??
false)) {
9039 if (($userTsConfig[
'options.'][
'clearCache.'][
'all'] ??
false)
9040 || ($this->admin && (
bool)($userTsConfig[
'options.'][
'clearCache.'][
'all'] ??
true))
9043 GeneralUtility::makeInstance(ConnectionPool::class)
9044 ->getConnectionForTable(
'cache_treelist')
9045 ->truncate(
'cache_treelist');
9048 GeneralUtility::makeInstance(OpcodeCacheService::class)->clearAllActive();
9054 'Calling clear_cacheCmd() with arguments "temp_cached" or "system", using'
9055 .
' the TSconfig option "options.clearCache.system" will be removed in TYPO3 v10.0, use "all"'
9056 .
' instead or call the group cache clearing of "system" group directly via a custom extension.',
9059 if ($this->admin || $userTsConfig[
'options.'][
'clearCache.'][
'system'] ??
false) {
9068 $list_cache = [$cacheCmd];
9070 foreach (
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
't3lib/class.t3lib_tcemain.php'][
'clearPageCacheEval'] ?? [] as $funcName) {
9071 $_params = [
'pageIdArray' => &$list_cache,
'cacheCmd' => $cacheCmd,
'functionID' =>
'clear_cacheCmd()'];
9073 GeneralUtility::callUserFunction($funcName, $_params, $this);
9076 if (is_array($list_cache)) {
9077 foreach ($list_cache as $pageId) {
9078 $tagsToFlush[] =
'pageId_' . (int)$pageId;
9083 if (GeneralUtility::isFirstPartOfStr(strtolower($cacheCmd),
'cachetag:')) {
9084 $cacheTag = substr($cacheCmd, 9);
9085 $tagsToFlush[] = $cacheTag;
9088 if (!empty($tagsToFlush)) {
9093 $_params = [
'cacheCmd' => strtolower($cacheCmd),
'tags' => $tagsToFlush];
9094 foreach (
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
't3lib/class.t3lib_tcemain.php'][
'clearCachePostProc'] ?? [] as $_funcRef) {
9095 GeneralUtility::callUserFunction($_funcRef, $_params, $this);
9119 public function log($table, $recuid, $action, $recpid, $error, $details, $details_nr = -1, $data = [], $event_pid = -1, $NEWid =
'')
9121 if (!$this->enableLogging) {
9126 if (!$this->storeLogMessages) {
9130 $detailMessage = $details;
9131 if (is_array($data)) {
9132 $detailMessage = vsprintf($details, $data);
9134 $this->errorLog[] =
'[' . $type .
'.' . $action .
'.' . $details_nr .
']: ' . $detailMessage;
9136 return $this->BE_USER->writelog($type, $action, $error, $details_nr, $details, $data, $table, $recuid, $recpid, $event_pid, $NEWid);
9149 return $this->
log(
'', 0, 0, 0, $error, $message, -1);
9164 public function newlog2($message, $table, $uid, $pid =
null, $error = 0)
9166 trigger_error(
'DataHandler->newlog2() will be removed in TYPO3 v10.0, use the generic log() function instead.', E_USER_DEPRECATED);
9167 if (!$this->enableLogging) {
9170 if ($pid ===
null) {
9172 $pid = $propArr[
'pid'];
9174 return $this->
log($table, $uid, 0, 0, $error, $message, -1, [], $this->
eventPid($table, $uid, $pid));
9182 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
'sys_log');
9183 $queryBuilder->getRestrictions()->removeAll();
9184 $result = $queryBuilder
9188 $queryBuilder->expr()->eq(
'type', $queryBuilder->createNamedParameter(1, \PDO::PARAM_INT)),
9189 $queryBuilder->expr()->lt(
'action', $queryBuilder->createNamedParameter(256, \PDO::PARAM_INT)),
9190 $queryBuilder->expr()->eq(
9192 $queryBuilder->createNamedParameter($this->BE_USER->user[
'uid'], \PDO::PARAM_INT)
9194 $queryBuilder->expr()->eq(
9196 $queryBuilder->createNamedParameter(
$GLOBALS[
'EXEC_TIME'], \PDO::PARAM_INT)
9198 $queryBuilder->expr()->neq(
'error', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT))
9202 while ($row = $result->fetch()) {
9203 $log_data = unserialize($row[
'log_data']);
9204 $msg = $row[
'error'] .
': ' . sprintf($row[
'details'], $log_data[0], $log_data[1], $log_data[2], $log_data[3], $log_data[4]);
9206 $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $msg,
'',
FlashMessage::ERROR,
true);
9208 $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
9209 $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
9210 $defaultFlashMessageQueue->enqueue($flashMessage);
9228 $localizationParentFieldName =
$GLOBALS[
'TCA'][
'pages'][
'ctrl'][
'transOrigPointerField'];
9229 $row = $this->
recordInfo(
'pages', $pageId, $localizationParentFieldName);
9230 $localizationParent = (int)$row[$localizationParentFieldName];
9231 if ($localizationParent > 0) {
9232 return $localizationParent;
9248 $result = $fieldArray;
9249 foreach ($fieldArray as $field => $value) {
9251 &&
$GLOBALS[
'TCA'][$table][
'columns'][$field][
'config'][
'type'] ===
'inline'
9252 &&
$GLOBALS[
'TCA'][$table][
'columns'][$field][
'config'][
'foreign_field']) {
9253 $result[$field] = count(GeneralUtility::trimExplode(
',', $value,
true));
9270 !empty($this->deletedRecords[$tableName])
9271 && in_array($uid, $this->deletedRecords[$tableName])
9285 if (isset($this->autoVersionIdMap[$table][$id])) {
9286 $result = $this->autoVersionIdMap[$table][$id];
9301 if ($autoVersionId !==
null) {
9302 $id = $autoVersionId;
9314 foreach ($idValues as $idValue) {
9315 if (strpos($idValue,
'NEW') === 0) {
9316 $this->remapStackChildIds[$idValue] =
true;
9333 $connection = GeneralUtility::makeInstance(ConnectionPool::class)
9334 ->getConnectionForTable($tableName);
9335 $sortingStatement = !empty($sortingField)
9339 $resolver = GeneralUtility::makeInstance(
9340 PlainDataResolver::class,
9346 $resolver->setWorkspaceId($this->BE_USER->workspace);
9347 $resolver->setKeepDeletePlaceholder(
false);
9348 $resolver->setKeepMovePlaceholder(
false);
9349 $resolver->setKeepLiveIds(
true);
9350 $recordIds = $resolver->get();
9353 foreach ($recordIds as $recordId) {
9369 if (!isset($this->outerMostInstance)) {
9370 $stack = array_reverse(debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT | DEBUG_BACKTRACE_IGNORE_ARGS));
9371 foreach ($stack as $stackItem) {
9372 if (isset($stackItem[
'object']) && $stackItem[
'object'] instanceof
self) {
9373 $this->outerMostInstance = $stackItem[
'object'];
9413 $nestedElementCalls = (array)$this->runtimeCache->get($this->cachePrefixNestedElementCalls);
9414 return isset($nestedElementCalls[$identifier][$table][$id]);
9427 $nestedElementCalls = (array)$this->runtimeCache->get($this->cachePrefixNestedElementCalls);
9428 $nestedElementCalls[$identifier][$table][$id] =
true;
9429 $this->runtimeCache->set($this->cachePrefixNestedElementCalls, $nestedElementCalls);
9437 $this->runtimeCache->remove($this->cachePrefixNestedElementCalls);
9453 $elementsToBeDeleted = (array)$this->runtimeCache->get(
'core-datahandler-elementsToBeDeleted');
9454 return isset($elementsToBeDeleted[$table][$id]);
9464 $elementsToBeDeleted = (array)$this->runtimeCache->get(
'core-datahandler-elementsToBeDeleted');
9465 $this->runtimeCache->set(
'core-datahandler-elementsToBeDeleted', array_merge($elementsToBeDeleted, $this->
getCommandMapElements(
'delete')));
9475 $this->runtimeCache->remove(
'core-datahandler-elementsToBeDeleted');
9488 foreach ($elements as $key => $value) {
9489 if (empty($value)) {
9490 unset($elements[$key]);
9505 foreach ($this->cmdmap as $tableName => $idArray) {
9506 foreach ($idArray as $id => $commandArray) {
9507 foreach ($commandArray as $command => $value) {
9508 if ($value && $command == $needle) {
9509 $elements[$tableName][$id] =
true;
9523 if (!empty($this->control[
'active'])) {
9525 $this->control[
'active'],
9539 protected function setNullValues(array $active, array &$haystack)
9541 foreach ($active as $key => $value) {
9543 if (is_array($value)) {
9548 } elseif ($value == 0) {
9551 $haystack[$key] =
null;
9567 if ($suggestedUid !== 0 && $connection->getDatabasePlatform() instanceof PostgreSqlPlatform) {
9573 return $suggestedUid;
9575 if ($connection->getDatabasePlatform() instanceof SQLServerPlatform) {
9578 $id = $connection->lastInsertId($tableName);
9599 if (!((
int)$id > 0)) {
9601 $result = $connection->executeQuery(
'SELECT IDENT_CURRENT(\'' . $table .
'\') AS
id')->fetch();
9602 if (isset($result['id']) && $result['id'] > 0) {
9603 $id = $result['id'];
9617 protected function postProcessPostgresqlInsert(Connection $connection, string $tableName)
9619 $queryBuilder = $connection->createQueryBuilder();
9620 $queryBuilder->getRestrictions()->removeAll();
9621 $row = $queryBuilder->select('PGT.schemaname
', 'S.relname
', 'C.attname
', 'T.relname AS tablename
')
9622 ->from('pg_class
', 'S
')
9623 ->from('pg_depend
', 'D
')
9624 ->from('pg_class
', 'T
')
9625 ->from('pg_attribute
', 'C
')
9626 ->from('pg_tables
', 'PGT
')
9628 $queryBuilder->expr()->eq('S.relkind
', $queryBuilder->quote('S
')),
9629 $queryBuilder->expr()->eq('S.oid
', $queryBuilder->quoteIdentifier('D.objid
')),
9630 $queryBuilder->expr()->eq('D.refobjid
', $queryBuilder->quoteIdentifier('T.oid
')),
9631 $queryBuilder->expr()->eq('D.refobjid
', $queryBuilder->quoteIdentifier('C.attrelid
')),
9632 $queryBuilder->expr()->eq('D.refobjsubid
', $queryBuilder->quoteIdentifier('C.attnum
')),
9633 $queryBuilder->expr()->eq('T.relname
', $queryBuilder->quoteIdentifier('PGT.tablename
')),
9634 $queryBuilder->expr()->eq('PGT.tablename
', $queryBuilder->quote($tableName))
9640 if ($row !== false) {
9643 'SELECT SETVAL(%s, COALESCE(MAX(%s), 0)+1, FALSE) FROM %s
',
9644 $connection->quote($row['schemaname
'] . '.
' . $row['relname
']),
9645 $connection->quoteIdentifier($row['attname
']),
9646 $connection->quoteIdentifier($row['schemaname
'] . '.
' . $row['tablename
'])
9658 protected function getFieldEvalCacheIdentifier($additionalIdentifier)
9660 return 'core-datahandler-eval-
' . md5($additionalIdentifier);
9666 protected function createRelationHandlerInstance()
9668 $isWorkspacesLoaded = ExtensionManagementUtility::isLoaded('workspaces
');
9669 $relationHandler = GeneralUtility::makeInstance(RelationHandler::class);
9670 $relationHandler->setWorkspaceId($this->BE_USER->workspace);
9671 $relationHandler->setUseLiveReferenceIds($isWorkspacesLoaded);
9672 $relationHandler->setUseLiveParentIds($isWorkspacesLoaded);
9673 return $relationHandler;
9681 protected function getCacheManager()
9683 return GeneralUtility::makeInstance(CacheManager::class);
9691 protected function getResourceFactory()
9693 return ResourceFactory::getInstance();
9699 protected function getLanguageService()
9701 return $GLOBALS['LANG
'];
9704 public function getHistoryRecords(): array
9706 return $this->historyRecords;