17 use Doctrine\DBAL\DBALException;
18 use Psr\Log\LoggerAwareInterface;
19 use Psr\Log\LoggerAwareTrait;
68 'sys_history' =>
true,
69 'tx_extensionmanager_domain_model_extension' => true
84 'perms_userid' =>
true,
85 'perms_groupid' =>
true,
87 'perms_group' =>
true,
88 'perms_everybody' =>
true,
166 $this->runtimeCache = GeneralUtility::makeInstance(CacheManager::class)->getCache(
'cache_runtime');
215 $uid = $uid ? (int)$uid : 0;
226 $cacheId = static::$cachePrefixTableRelationFields . $tableName;
227 if (!$this->useRuntimeCache || !$this->runtimeCache->has($cacheId)) {
229 $this->runtimeCache->set($cacheId, $tableRelationFields);
231 $tableRelationFields = $this->runtimeCache->get($cacheId);
234 $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
235 $connection = $connectionPool->getConnectionForTable(
'sys_refindex');
239 $queryBuilder = $connection->createQueryBuilder();
240 $queryBuilder->getRestrictions()->removeAll();
241 $queryResult = $queryBuilder->select(
'hash')->from(
'sys_refindex')->where(
242 $queryBuilder->expr()->eq(
'tablename', $queryBuilder->createNamedParameter($tableName, \PDO::PARAM_STR)),
243 $queryBuilder->expr()->eq(
'recuid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)),
244 $queryBuilder->expr()->eq(
246 $queryBuilder->createNamedParameter($this->getWorkspaceId(), \PDO::PARAM_INT)
249 $currentRelationHashes = [];
250 while ($relation = $queryResult->fetch()) {
251 $currentRelationHashes[$relation[
'hash']] =
true;
255 if ($tableRelationFields !==
'') {
257 if ($existingRecord) {
259 $this->relations = [];
266 if (!is_array($relation)) {
269 $relation[
'hash'] = md5(implode(
'
270 // First, check if already indexed and if so, unset that row (so in the end we know which rows to remove!)
271 if (isset($currentRelationHashes[$relation['hash
']])) {
272 unset($currentRelationHashes[$relation['hash
']]);
273 $result['keptNodes
']++;
274 $relation['_ACTION
'] = 'KEPT
';
278 $connection->insert('sys_refindex
', $relation);
280 $result['addedNodes
']++;
281 $relation['_ACTION
'] = 'ADDED
';
284 $result['relations
'] = $relations;
288 // If any old are left, remove them:
289 if (!empty($currentRelationHashes)) {
290 $hashList = array_keys($currentRelationHashes);
291 if (!empty($hashList)) {
292 $result['deletedNodes
'] = count($hashList);
293 $result['deletedNodes_hashList
'] = implode(',
', $hashList);
295 $maxBindParameters = PlatformInformation::getMaxBindParameters($connection->getDatabasePlatform());
296 foreach (array_chunk($hashList, $maxBindParameters - 10, true) as $chunk) {
300 $queryBuilder = $connection->createQueryBuilder();
302 ->delete('sys_refindex
')
304 $queryBuilder->expr()->in(
306 $queryBuilder->createNamedParameter($chunk, Connection::PARAM_STR_ARRAY)
326 public function generateRefIndexData($tableName, $uid)
328 if (!isset($GLOBALS['TCA
'][$tableName])) {
332 $this->relations = [];
335 $uid = $uid ? (int)$uid : 0;
337 // Get raw record from DB
338 $record = $this->getRecordRawCached($tableName, $uid);
341 if (!is_array($record)) {
345 return $this->generateDataUsingRecord($tableName, $record);
355 public function getNumberOfReferencedRecords(string $tableName, int $uid): int
357 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_refindex
');
358 return (int)$queryBuilder
359 ->count('*
')->from('sys_refindex
')
361 $queryBuilder->expr()->eq(
363 $queryBuilder->createNamedParameter($tableName, \PDO::PARAM_STR)
365 $queryBuilder->expr()->eq(
367 $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)
369 $queryBuilder->expr()->eq(
371 $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
373 )->execute()->fetchColumn(0);
383 protected function generateDataUsingRecord(string $tableName, array $record): array
385 $this->relations = [];
386 $deleteField = $GLOBALS['TCA
'][$tableName]['ctrl
']['delete'];
388 // Is the record deleted?
389 $deleted = $deleteField && $record[$deleteField] ? 1 : 0;
391 // Get all relations from record:
392 $recordRelations = $this->getRelations($tableName, $record);
393 // Traverse those relations, compile records to insert in table:
394 foreach ($recordRelations as $fieldName => $fieldRelations) {
396 switch ((string)$fieldRelations['type
']) {
398 $this->createEntryDataForDatabaseRelationsUsingRecord($tableName, $record, $fieldName, '', $deleted, $fieldRelations['itemArray
']);
400 case 'file_reference
':
401 // not used (see getRelations()), but fallback to file
403 $this->createEntryDataForFileRelationsUsingRecord($tableName, $record, $fieldName, '', $deleted, $fieldRelations['newValueFiles
']);
406 // DB references in FlexForms
407 if (is_array($fieldRelations['flexFormRels
']['db
'])) {
408 foreach ($fieldRelations['flexFormRels
']['db
'] as $flexPointer => $subList) {
409 $this->createEntryDataForDatabaseRelationsUsingRecord($tableName, $record, $fieldName, $flexPointer, $deleted, $subList);
412 // File references in FlexForms
413 // @todo #65463 Test correct handling of file references in FlexForms
414 if (is_array($fieldRelations['flexFormRels
']['file
'])) {
415 foreach ($fieldRelations['flexFormRels
']['file
'] as $flexPointer => $subList) {
416 $this->createEntryDataForFileRelationsUsingRecord($tableName, $record, $fieldName, $flexPointer, $deleted, $subList);
419 // Soft references in FlexForms
420 // @todo #65464 Test correct handling of soft references in FlexForms
421 if (is_array($fieldRelations['flexFormRels
']['softrefs
'])) {
422 foreach ($fieldRelations['flexFormRels
']['softrefs
'] as $flexPointer => $subList) {
423 $this->createEntryDataForSoftReferencesUsingRecord($tableName, $record, $fieldName, $flexPointer, $deleted, $subList['keys
']);
428 // Soft references in the field
429 if (is_array($fieldRelations['softrefs
'])) {
430 $this->createEntryDataForSoftReferencesUsingRecord($tableName, $record, $fieldName, '', $deleted, $fieldRelations['softrefs
']['keys
']);
434 return array_filter($this->relations);
454 public function createEntryData($table, $uid, $field, $flexPointer, $deleted, $ref_table, $ref_uid, $ref_string = '', $sort = -1, $softref_key = '', $softref_id = '')
456 $uid = $uid ? (int)$uid : 0;
460 return $this->createEntryDataUsingRecord(
462 $this->getRecordRawCached($table, $uid),
464 (string)$flexPointer,
465 $deleted ? (int)$deleted : 0,
467 $ref_uid ? (int)$ref_uid : 0,
469 $sort ? (int)$sort : 0,
470 (string)$softref_key,
491 protected function createEntryDataUsingRecord(string $tableName, array $record, string $fieldName, string $flexPointer, int $deleted, string $referencedTable, int $referencedUid, string $referenceString = '', int $sort = -1, string $softReferenceKey = '', string $softReferenceId = '')
494 if (BackendUtility::isTableWorkspaceEnabled($tableName)) {
495 $workspaceId = $this->getWorkspaceId();
496 if (isset($record['t3ver_wsid
']) && (int)$record['t3ver_wsid
'] !== $workspaceId) {
497 // The given record is workspace-enabled but doesn't live in the selected workspace => don
't add index as it's not actually there
502 'tablename' => $tableName,
503 'recuid' => $record[
'uid'],
504 'field' => $fieldName,
505 'flexpointer' => $flexPointer,
506 'softref_key' => $softReferenceKey,
507 'softref_id' => $softReferenceId,
509 'deleted' => (int)$deleted,
511 'ref_table' => $referencedTable,
512 'ref_uid' => $referencedUid,
513 'ref_string' => mb_substr($referenceString, 0, 1024)
529 $uid = $uid ? (int)$uid : 0;
537 (
string)$flexPointer,
538 $deleted ? (
int)$deleted : 0,
555 foreach ($items as $sort => $i) {
556 $this->relations[] = $this->
createEntryDataUsingRecord($tableName, $record, $fieldName, $flexPointer, $deleted, $i[
'table'], (
int)$i[
'id'],
'', $sort);
572 $uid = $uid ? (int)$uid : 0;
580 (
string)$flexPointer,
581 $deleted ? (
int)$deleted : 0,
598 foreach ($items as $sort => $i) {
599 $filePath = $i[
'ID_absFile'];
629 $uid = $uid ? (int)$uid : 0;
630 if (!$uid || !is_array($keys)) {
637 (
string)$flexPointer,
638 $deleted ? (
int)$deleted : 0,
655 foreach ($keys as $spKey => $elements) {
656 if (is_array($elements)) {
657 foreach ($elements as $subKey => $el) {
658 if (is_array($el[
'subst'])) {
659 switch ((
string)$el[
'subst'][
'type']) {
661 list($referencedTable, $referencedUid) = explode(
':', $el[
'subst'][
'recordRef']);
662 $this->relations[] = $this->
createEntryDataUsingRecord($tableName, $record, $fieldName, $flexPointer, $deleted, $referencedTable, (
int)$referencedUid,
'', -1, $spKey, $subKey);
664 case 'file_reference':
667 $this->relations[] = $this->
createEntryDataUsingRecord($tableName, $record, $fieldName, $flexPointer, $deleted,
'_FILE', 0, $el[
'subst'][
'relFileName'], -1, $spKey, $subKey);
670 $this->relations[] = $this->
createEntryDataUsingRecord($tableName, $record, $fieldName, $flexPointer, $deleted,
'_STRING', 0, $el[
'subst'][
'tokenValue'], -1, $spKey, $subKey);
701 foreach ($row as $field => $value) {
703 $conf =
$GLOBALS[
'TCA'][$table][
'columns'][$field][
'config'];
706 if (!empty($resultsFromFiles)) {
711 $fileResultsFromFiles = [];
712 $dbResultsFromFiles = [];
713 foreach ($resultsFromFiles as $resultFromFiles) {
714 if (isset($resultFromFiles[
'table']) && $resultFromFiles[
'table'] ===
'sys_file') {
715 $dbResultsFromFiles[] = $resultFromFiles;
718 $fileResultsFromFiles[] = $resultFromFiles;
721 if (!empty($fileResultsFromFiles)) {
724 'newValueFiles' => $fileResultsFromFiles
727 if (!empty($dbResultsFromFiles)) {
730 'itemArray' => $dbResultsFromFiles
735 if ($conf[
'type'] ===
'input' && $conf[
'renderType'] ===
'inputLink' && empty($conf[
'softref'])) {
736 $conf[
'softref'] =
'typolink';
740 if (!empty($resultsFromDatabase)) {
744 'itemArray' => $resultsFromDatabase
748 if ($conf[
'type'] ===
'flex') {
752 $currentValueArray = GeneralUtility::xml2array($value);
754 if (is_array($currentValueArray)) {
755 $this->temp_flexRelations = [
761 $flexFormTools = GeneralUtility::makeInstance(FlexFormTools::class);
762 $flexFormTools->traverseFlexFormXMLData($table, $field, $row, $this,
'getRelations_flexFormCallBack');
771 if ((
string)$value !==
'') {
772 $softRefValue = $value;
773 if (!empty($conf[
'softref'])) {
775 foreach ($softRefs as $spKey => $spParams) {
777 if (is_object($softRefObj)) {
778 $resultArray = $softRefObj->findRef($table, $field, $uid, $softRefValue, $spKey, $spParams);
779 if (is_array($resultArray)) {
780 $outRow[$field][
'softrefs'][
'keys'][$spKey] = $resultArray[
'elements'];
781 if ((
string)$resultArray[
'content'] !==
'') {
782 $softRefValue = $resultArray[
'content'];
788 if (!empty($outRow[$field][
'softrefs']) && (
string)$value !== (
string)$softRefValue && strpos($softRefValue,
'{softref:') !==
false) {
789 $outRow[$field][
'softrefs'][
'tokenizedContent'] = $softRefValue;
809 $structurePath = substr($structurePath, 5) .
'/';
810 $dsConf = $dsArr[
'TCEforms'][
'config'];
812 list($table, $uid, $field) = [
819 if (!empty($resultsFromFiles)) {
824 $fileResultsFromFiles = [];
825 $dbResultsFromFiles = [];
826 foreach ($resultsFromFiles as $resultFromFiles) {
827 if (isset($resultFromFiles[
'table']) && $resultFromFiles[
'table'] ===
'sys_file') {
828 $dbResultsFromFiles[] = $resultFromFiles;
830 $fileResultsFromFiles[] = $resultFromFiles;
833 if (!empty($fileResultsFromFiles)) {
834 $this->temp_flexRelations[
'file'][$structurePath] = $fileResultsFromFiles;
836 if (!empty($dbResultsFromFiles)) {
837 $this->temp_flexRelations[
'db'][$structurePath] = $dbResultsFromFiles;
841 if ($dsConf[
'type'] ===
'input' && $dsConf[
'renderType'] ===
'inputLink' && empty($dsConf[
'softref'])) {
842 $dsConf[
'softref'] =
'typolink';
846 if (!empty($resultsFromDatabase)) {
848 $this->temp_flexRelations[
'db'][$structurePath] = $resultsFromDatabase;
851 if (is_array($dataValue) || (
string)$dataValue !==
'') {
852 $softRefValue = $dataValue;
854 if ($softRefs !==
false) {
855 foreach ($softRefs as $spKey => $spParams) {
857 if (is_object($softRefObj)) {
858 $resultArray = $softRefObj->findRef($table, $field, $uid, $softRefValue, $spKey, $spParams, $structurePath);
859 if (is_array($resultArray) && is_array($resultArray[
'elements'])) {
860 $this->temp_flexRelations[
'softrefs'][$structurePath][
'keys'][$spKey] = $resultArray[
'elements'];
861 if ((
string)$resultArray[
'content'] !==
'') {
862 $softRefValue = $resultArray[
'content'];
868 if (!empty($this->temp_flexRelations[
'softrefs']) && (
string)$dataValue !== (
string)$softRefValue) {
869 $this->temp_flexRelations[
'softrefs'][$structurePath][
'tokenizedContent'] = $softRefValue;
885 if ($conf[
'type'] !==
'group' || ($conf[
'internal_type'] !==
'file' && $conf[
'internal_type'] !==
'file_reference')) {
892 $dbAnalysis = GeneralUtility::makeInstance(RelationHandler::class);
893 $dbAnalysis->start(
'',
'files', $conf[
'MM'], $uid);
894 foreach ($dbAnalysis->itemArray as $someval) {
895 if ($someval[
'id']) {
896 $theFileValues[] = $someval[
'id'];
900 $theFileValues = explode(
',', $value);
903 $uploadFolder = $conf[
'internal_type'] ===
'file' ? $conf[
'uploadfolder'] :
'';
906 foreach ($theFileValues as $file) {
908 $realFile = $destinationFolder .
'/' . trim($file);
911 'ID' => md5($realFile),
912 'ID_absFile' => $realFile
915 if ($conf[
'internal_type'] ===
'file_reference') {
918 if ($file instanceof File || $file instanceof Folder) {
922 'table' =>
'sys_file',
923 'id' => $file->getUid()
926 }
catch (\Exception $e) {
929 $newValueFiles[] = $newValueFile;
932 return $newValueFiles;
950 if ($conf[
'type'] ===
'inline' && !empty($conf[
'foreign_table']) && empty($conf[
'MM'])) {
951 $dbAnalysis = GeneralUtility::makeInstance(RelationHandler::class);
952 $dbAnalysis->setUseLiveReferenceIds(
false);
953 $dbAnalysis->start($value, $conf[
'foreign_table'],
'', $uid, $table, $conf);
954 return $dbAnalysis->itemArray;
958 $allowedTables = $conf[
'type'] ===
'group' ? $conf[
'allowed'] : $conf[
'foreign_table'];
959 if ($conf[
'MM_opposite_field']) {
962 $dbAnalysis = GeneralUtility::makeInstance(RelationHandler::class);
963 $dbAnalysis->start($value, $allowedTables, $conf[
'MM'], $uid, $table, $conf);
964 return $dbAnalysis->itemArray;
994 public function setReferenceValue($hash, $newValue, $returnDataArray =
false, $bypassWorkspaceAdminCheck =
false)
997 if ($backendUser->workspace === 0 && $backendUser->isAdmin() || $bypassWorkspaceAdminCheck) {
998 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
'sys_refindex');
999 $queryBuilder->getRestrictions()->removeAll();
1002 $referenceRecord = $queryBuilder
1004 ->from(
'sys_refindex')
1006 $queryBuilder->expr()->eq(
'hash', $queryBuilder->createNamedParameter($hash, \PDO::PARAM_STR))
1013 if (!is_array($referenceRecord)) {
1014 return 'ERROR: No reference record with hash="' . $hash .
'" was found!';
1017 if (empty(
$GLOBALS[
'TCA'][$referenceRecord[
'tablename']])) {
1018 return 'ERROR: Table "' . $referenceRecord[
'tablename'] .
'" was not in TCA!';
1022 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
1023 ->getQueryBuilderForTable($referenceRecord[
'tablename']);
1024 $queryBuilder->getRestrictions()->removeAll();
1025 $record = $queryBuilder
1027 ->from($referenceRecord[
'tablename'])
1029 $queryBuilder->expr()->eq(
1031 $queryBuilder->createNamedParameter($referenceRecord[
'recuid'], \PDO::PARAM_INT)
1038 if (is_array($record)) {
1040 $recordRelations = $this->
getRelations($referenceRecord[
'tablename'], $record, $referenceRecord[
'field']);
1041 if ($fieldRelation = $recordRelations[$referenceRecord[
'field']]) {
1045 switch ((
string)$fieldRelation[
'type']) {
1052 case 'file_reference':
1062 if (is_array($fieldRelation[
'flexFormRels'][
'db'][$referenceRecord[
'flexpointer']])) {
1063 $error = $this->
setReferenceValue_dbRels($referenceRecord, $fieldRelation[
'flexFormRels'][
'db'][$referenceRecord[
'flexpointer']], $newValue, $dataArray, $referenceRecord[
'flexpointer']);
1069 if (is_array($fieldRelation[
'flexFormRels'][
'file'][$referenceRecord[
'flexpointer']])) {
1070 $error = $this->
setReferenceValue_fileRels($referenceRecord, $fieldRelation[
'flexFormRels'][
'file'][$referenceRecord[
'flexpointer']], $newValue, $dataArray, $referenceRecord[
'flexpointer']);
1076 if ($referenceRecord[
'softref_key'] && is_array($fieldRelation[
'flexFormRels'][
'softrefs'][$referenceRecord[
'flexpointer']][
'keys'][$referenceRecord[
'softref_key']])) {
1077 $error = $this->
setReferenceValue_softreferences($referenceRecord, $fieldRelation[
'flexFormRels'][
'softrefs'][$referenceRecord[
'flexpointer']], $newValue, $dataArray, $referenceRecord[
'flexpointer']);
1085 if ($referenceRecord[
'softref_key'] && is_array($fieldRelation[
'softrefs'][
'keys'][$referenceRecord[
'softref_key']])) {
1092 if ($returnDataArray) {
1096 $dataHandler = GeneralUtility::makeInstance(DataHandler::class);
1097 $dataHandler->dontProcessTransformations =
true;
1098 $dataHandler->bypassWorkspaceRestrictions =
true;
1099 $dataHandler->bypassFileHandling =
true;
1101 $dataHandler->bypassAccessCheckForRecords =
true;
1103 $dataHandler->start($dataArray, []);
1104 $dataHandler->process_datamap();
1106 if (!empty($dataHandler->errorLog)) {
1107 return LF .
'DataHandler:' . implode(LF .
'DataHandler:', $dataHandler->errorLog);
1112 return 'ERROR: BE_USER object is not admin OR not in workspace 0 (Live)';
1130 if ((
int)$itemArray[$refRec[
'sorting']][
'id'] === (
int)$refRec[
'ref_uid'] && (
string)$itemArray[$refRec[
'sorting']][
'table'] === (
string)$refRec[
'ref_table']) {
1133 if ($newValue ===
null) {
1134 unset($itemArray[$refRec[
'sorting']]);
1136 list($itemArray[$refRec[
'sorting']][
'table'], $itemArray[$refRec[
'sorting']][
'id']) = explode(
':', $newValue);
1140 foreach ($itemArray as $pair) {
1141 $saveValue[] = $pair[
'table'] .
'_' . $pair[
'id'];
1145 $flexFormTools = GeneralUtility::makeInstance(FlexFormTools::class);
1146 $dataArray[$refRec[
'tablename']][$refRec[
'recuid']][$refRec[
'field']][
'data'] = [];
1147 $flexFormTools->setArrayValueByPath(substr($flexPointer, 0, -1), $dataArray[$refRec[
'tablename']][$refRec[
'recuid']][$refRec[
'field']][
'data'], implode(
',', $saveValue));
1149 $dataArray[$refRec[
'tablename']][$refRec[
'recuid']][$refRec[
'field']] = implode(
',', $saveValue);
1152 return 'ERROR: table:id pair "' . $refRec[
'ref_table'] .
':' . $refRec[
'ref_uid'] .
'" did not match that of the record ("' . $itemArray[$refRec[
'sorting']][
'table'] .
':' . $itemArray[$refRec[
'sorting']][
'id'] .
'") in sorting index "' . $refRec[
'sorting'] .
'"';
1171 if ($ID_absFile === (
string)$refRec[
'ref_string'] && $refRec[
'ref_table'] ===
'_FILE') {
1174 if ($newValue ===
null) {
1175 unset($itemArray[$refRec[
'sorting']]);
1177 $itemArray[$refRec[
'sorting']][
'filename'] = $newValue;
1181 foreach ($itemArray as $fileInfo) {
1182 $saveValue[] = $fileInfo[
'filename'];
1186 $flexFormTools = GeneralUtility::makeInstance(FlexFormTools::class);
1187 $dataArray[$refRec[
'tablename']][$refRec[
'recuid']][$refRec[
'field']][
'data'] = [];
1188 $flexFormTools->setArrayValueByPath(substr($flexPointer, 0, -1), $dataArray[$refRec[
'tablename']][$refRec[
'recuid']][$refRec[
'field']][
'data'], implode(
',', $saveValue));
1190 $dataArray[$refRec[
'tablename']][$refRec[
'recuid']][$refRec[
'field']] = implode(
',', $saveValue);
1193 return 'ERROR: either "' . $refRec[
'ref_table'] .
'" was not "_FILE" or file Environment::getPublicPath()+"' . $refRec[
'ref_string'] .
'" did not match that of the record ("' . $itemArray[$refRec[
'sorting']][
'ID_absFile'] .
'") in sorting index "' . $refRec[
'sorting'] .
'"';
1211 if (!is_array($softref[
'keys'][$refRec[
'softref_key']][$refRec[
'softref_id']])) {
1212 return 'ERROR: Soft reference parser key "' . $refRec[
'softref_key'] .
'" or the index "' . $refRec[
'softref_id'] .
'" was not found.';
1216 $softref[
'keys'][$refRec[
'softref_key']][$refRec[
'softref_id']][
'subst'][
'tokenValue'] =
'' . $newValue;
1218 foreach ($softref[
'keys'] as $sfIndexes) {
1219 foreach ($sfIndexes as $data) {
1220 $softref[
'tokenizedContent'] = str_replace(
'{softref:' . $data[
'subst'][
'tokenID'] .
'}', $data[
'subst'][
'tokenValue'], $softref[
'tokenizedContent']);
1224 if (!strstr($softref[
'tokenizedContent'],
'{softref:')) {
1226 $flexFormTools = GeneralUtility::makeInstance(FlexFormTools::class);
1227 $dataArray[$refRec[
'tablename']][$refRec[
'recuid']][$refRec[
'field']][
'data'] = [];
1228 $flexFormTools->setArrayValueByPath(substr($flexPointer, 0, -1), $dataArray[$refRec[
'tablename']][$refRec[
'recuid']][$refRec[
'field']][
'data'], $softref[
'tokenizedContent']);
1230 $dataArray[$refRec[
'tablename']][$refRec[
'recuid']][$refRec[
'field']] = $softref[
'tokenizedContent'];
1233 return 'ERROR: After substituting all found soft references there were still soft reference tokens in the text. (theoretically this does not have to be an error if the string "{softref:" happens to be in the field for another reason.)';
1254 ($configuration[
'type'] ===
'group' && $configuration[
'internal_type'] ===
'db')
1256 ($configuration[
'type'] ===
'select' || $configuration[
'type'] ===
'inline')
1257 && !empty($configuration[
'foreign_table'])
1273 ($configuration[
'type'] ===
'group' && ($configuration[
'internal_type'] ===
'file' || $configuration[
'internal_type'] ===
'file_reference'))
1275 ($configuration[
'type'] ===
'input' && $configuration[
'renderType'] ===
'inputLink')
1277 $configuration[
'type'] ===
'flex'
1279 isset($configuration[
'softref'])
1291 if (!isset(
$GLOBALS[
'TCA'][$tableName][
'columns'])) {
1297 foreach (
$GLOBALS[
'TCA'][$tableName][
'columns'] as $field => $fieldDefinition) {
1298 if (is_array($fieldDefinition[
'config'])) {
1300 if (isset($fieldDefinition[
'config'][
'type']) && $fieldDefinition[
'config'][
'type'] ===
'flex') {
1333 public function updateIndex($testOnly, $cli_echo =
false)
1339 $headerContent = $testOnly ?
'Reference Index being TESTED (nothing written, remove the "--check" argument)' :
'Reference Index being Updated';
1341 echo
'*******************************************' . LF . $headerContent . LF .
'*******************************************' . LF;
1344 $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
1345 $refIndexConnectionName = empty(
$GLOBALS[
'TYPO3_CONF_VARS'][
'DB'][
'TableMapping'][
'sys_refindex'])
1347 :
$GLOBALS[
'TYPO3_CONF_VARS'][
'DB'][
'TableMapping'][
'sys_refindex'];
1349 foreach (
$GLOBALS[
'TCA'] as $tableName => $cfg) {
1353 $tableConnectionName = empty(
$GLOBALS[
'TYPO3_CONF_VARS'][
'DB'][
'TableMapping'][$tableName])
1355 :
$GLOBALS[
'TYPO3_CONF_VARS'][
'DB'][
'TableMapping'][$tableName];
1362 $queryBuilder = $connectionPool->getQueryBuilderForTable($tableName);
1363 $queryBuilder->getRestrictions()->removeAll();
1365 $queryResult = $queryBuilder
1369 }
catch (DBALException $e) {
1373 '" exists in TCA but does not exist in the database. You should run the Database Analyzer in the Install Tool to fix this.';
1374 $this->logger->error($msg, [
'exception' => $e]);
1378 $tableNames[] = $tableName;
1380 while ($record = $queryResult->fetch()) {
1381 $refIndexObj = GeneralUtility::makeInstance(self::class);
1382 if (isset($record[
't3ver_wsid'])) {
1383 $refIndexObj->setWorkspaceId($record[
't3ver_wsid']);
1385 $result = $refIndexObj->updateRefIndexTable($tableName, $record[
'uid'], $testOnly);
1387 if ($result[
'addedNodes'] || $result[
'deletedNodes']) {
1388 $error =
'Record ' . $tableName .
':' . $record[
'uid'] .
' had ' . $result[
'addedNodes'] .
' added indexes and ' . $result[
'deletedNodes'] .
' deleted indexes';
1397 if ($refIndexConnectionName !== $tableConnectionName) {
1398 $this->logger->error(
'Not checking table "' . $tableName .
'" for lost indexes, "sys_refindex" table uses a different connection');
1404 $subQueryBuilder = $connectionPool->getQueryBuilderForTable($tableName);
1405 $subQueryBuilder->getRestrictions()->removeAll();
1408 ->from($tableName,
'sub_' . $tableName)
1410 $subQueryBuilder->expr()->eq(
1411 'sub_' . $tableName .
'.uid',
1412 $queryBuilder->quoteIdentifier(
'sys_refindex.recuid')
1417 $queryBuilder = $connectionPool->getQueryBuilderForTable(
'sys_refindex');
1418 $queryBuilder->getRestrictions()->removeAll();
1419 $lostIndexes = $queryBuilder
1421 ->from(
'sys_refindex')
1423 $queryBuilder->expr()->eq(
1425 $queryBuilder->createNamedParameter($tableName, \PDO::PARAM_STR)
1427 'NOT EXISTS (' . $subQueryBuilder->getSQL() .
')'
1432 if ($lostIndexes > 0) {
1433 $error =
'Table ' . $tableName .
' has ' . $lostIndexes .
' lost indexes which are now deleted';
1439 $queryBuilder = $connectionPool->getQueryBuilderForTable(
'sys_refindex');
1440 $queryBuilder->delete(
'sys_refindex')
1442 $queryBuilder->expr()->eq(
1444 $queryBuilder->createNamedParameter($tableName, \PDO::PARAM_STR)
1446 'NOT EXISTS (' . $subQueryBuilder->getSQL() .
')'
1454 $queryBuilder = $connectionPool->getQueryBuilderForTable(
'sys_refindex');
1455 $queryBuilder->getRestrictions()->removeAll();
1456 $lostTables = $queryBuilder
1458 ->from(
'sys_refindex')
1460 $queryBuilder->expr()->notIn(
1462 $queryBuilder->createNamedParameter($tableNames, Connection::PARAM_STR_ARRAY)
1467 if ($lostTables > 0) {
1468 $error =
'Index table hosted ' . $lostTables .
' indexes for non-existing tables, now removed';
1474 $queryBuilder = $connectionPool->getQueryBuilderForTable(
'sys_refindex');
1475 $queryBuilder->delete(
'sys_refindex')
1477 $queryBuilder->expr()->notIn(
1479 $queryBuilder->createNamedParameter($tableNames, Connection::PARAM_STR_ARRAY)
1485 $recordsCheckedString = $recCount .
' records from ' . $tableCount .
' tables were checked/updated.' . LF;
1486 $flashMessage = GeneralUtility::makeInstance(
1487 FlashMessage::class,
1488 $errorCount ? implode(
'##LF##',
$errors) :
'Index Integrity was perfect!',
1489 $recordsCheckedString,
1493 $flashMessageRenderer = GeneralUtility::makeInstance(FlashMessageRendererResolver::class)->resolve();
1494 $bodyContent = $flashMessageRenderer->render([$flashMessage]);
1496 echo $recordsCheckedString . ($errorCount ?
'Updates: ' . $errorCount :
'Index Integrity was perfect!') . LF;
1499 $registry = GeneralUtility::makeInstance(Registry::class);
1500 $registry->set(
'core',
'sys_refindex_lastUpdate',
$GLOBALS[
'EXEC_TIME']);
1502 return [$headerContent, $bodyContent, $errorCount];
1527 $recordCacheId = $tableName .
':' . $uid;
1528 if (!$this->useRuntimeCache || !isset($this->recordCache[$recordCacheId])) {
1531 $cacheId = static::$cachePrefixTableRelationFields . $tableName;
1532 if (!$this->useRuntimeCache || !$this->runtimeCache->has($cacheId)) {
1534 if ($this->useRuntimeCache) {
1535 $this->runtimeCache->set($cacheId, $tableRelationFields);
1538 $tableRelationFields = $this->runtimeCache->get($cacheId);
1542 if ($tableRelationFields ===
'') {
1546 if ($tableRelationFields ===
'*') {
1548 $selectFields =
'*';
1551 $selectFields =
'uid,' . $tableRelationFields;
1552 $deleteField =
$GLOBALS[
'TCA'][$tableName][
'ctrl'][
'delete'];
1554 $selectFields .=
',' . $deleteField;
1557 $selectFields .=
',t3ver_wsid';
1561 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
1562 ->getQueryBuilderForTable($tableName);
1563 $queryBuilder->getRestrictions()->removeAll();
1564 $row = $queryBuilder
1565 ->select(...GeneralUtility::trimExplode(
',', $selectFields,
true))
1568 $queryBuilder->expr()->eq(
1570 $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)
1576 $this->recordCache[$recordCacheId] = $row;
1578 return $this->recordCache[$recordCacheId];
1589 if (isset(static::$excludedTables[$tableName])) {
1590 return static::$excludedTables[$tableName];
1595 $excludeTable =
false;
1597 $signalSlotDispatcher->dispatch(__CLASS__,
'shouldExcludeTableFromReferenceIndex', [$tableName, &$excludeTable]);
1599 static::$excludedTables[$tableName] = $excludeTable;
1601 return static::$excludedTables[$tableName];
1614 if (isset(static::$excludedColumns[$column])) {
1618 if (is_array(
$GLOBALS[
'TCA'][$tableName][
'columns'][$column]) && (!$onlyColumn || $onlyColumn === $column)) {
1632 $this->useRuntimeCache =
true;
1640 $this->useRuntimeCache =
false;