‪TYPO3CMS  10.4
ReferenceIndex.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
18 use Doctrine\DBAL\DBALException;
19 use Psr\EventDispatcher\EventDispatcherInterface;
20 use Psr\Log\LoggerAwareInterface;
21 use Psr\Log\LoggerAwareTrait;
22 use Psr\Log\LogLevel;
33 
47 class ‪ReferenceIndex implements LoggerAwareInterface
48 {
49  use LoggerAwareTrait;
50 
64  protected static ‪$excludedTables = [
65  'sys_log' => true,
66  'tx_extensionmanager_domain_model_extension' => true
67  ];
68 
79  protected static ‪$excludedColumns = [
80  'uid' => true,
81  'perms_userid' => true,
82  'perms_groupid' => true,
83  'perms_user' => true,
84  'perms_group' => true,
85  'perms_everybody' => true,
86  'pid' => true
87  ];
88 
95  protected static ‪$cachePrefixTableRelationFields = 'core-refidx-tblRelFields-';
96 
105  public ‪$temp_flexRelations = [];
106 
114  public ‪$relations = [];
115 
122  protected ‪$recordCache = [];
123 
130  public ‪$hashVersion = 1;
131 
137  protected ‪$workspaceId = 0;
138 
144  protected ‪$runtimeCache;
145 
150  protected ‪$useRuntimeCache = false;
151 
155  protected ‪$eventDispatcher;
156 
160  public function ‪__construct(EventDispatcherInterface ‪$eventDispatcher = null)
161  {
162  $this->eventDispatcher = ‪$eventDispatcher ?? GeneralUtility::getContainer()->get(EventDispatcherInterface::class);
163  $this->runtimeCache = GeneralUtility::makeInstance(CacheManager::class)->getCache('runtime');
164  }
165 
172  public function ‪setWorkspaceId(‪$workspaceId)
173  {
174  $this->workspaceId = (int)‪$workspaceId;
175  }
176 
184  public function ‪getWorkspaceId()
185  {
186  return ‪$this->workspaceId;
187  }
188 
201  public function ‪updateRefIndexTable($tableName, $uid, $testOnly = false)
202  {
203  $result = [
204  'keptNodes' => 0,
205  'deletedNodes' => 0,
206  'addedNodes' => 0
207  ];
208 
209  $uid = $uid ? (int)$uid : 0;
210  if (!$uid) {
211  return $result;
212  }
213 
214  // If this table cannot contain relations, skip it
215  if ($this->‪shouldExcludeTableFromReferenceIndex($tableName)) {
216  return $result;
217  }
218 
219  // Fetch tableRelationFields and save them in cache if not there yet
220  $cacheId = static::$cachePrefixTableRelationFields . $tableName;
221  $tableRelationFields = $this->useRuntimeCache ? $this->runtimeCache->get($cacheId) : false;
222  if ($tableRelationFields === false) {
223  $tableRelationFields = $this->‪fetchTableRelationFields($tableName);
224  if ($this->useRuntimeCache) {
225  $this->runtimeCache->set($cacheId, $tableRelationFields);
226  }
227  }
228 
229  $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
230  $connection = $connectionPool->getConnectionForTable('sys_refindex');
231 
232  // Get current index from Database with hash as index using $uidIndexField
233  // no restrictions are needed, since sys_refindex is not a TCA table
234  $queryBuilder = $connection->createQueryBuilder();
235  $queryBuilder->getRestrictions()->removeAll();
236  $queryResult = $queryBuilder->select('hash')->from('sys_refindex')->where(
237  $queryBuilder->expr()->eq('tablename', $queryBuilder->createNamedParameter($tableName, \PDO::PARAM_STR)),
238  $queryBuilder->expr()->eq('recuid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)),
239  $queryBuilder->expr()->eq(
240  'workspace',
241  $queryBuilder->createNamedParameter($this->getWorkspaceId(), \PDO::PARAM_INT)
242  )
243  )->execute();
244  $currentRelationHashes = [];
245  while ($relation = $queryResult->fetch()) {
246  $currentRelationHashes[$relation['hash']] = true;
247  }
248 
249  // If the table has fields which could contain relations and the record does exist (including deleted-flagged)
250  if ($tableRelationFields !== '') {
251  $existingRecord = $this->‪getRecordRawCached($tableName, $uid);
252  if ($existingRecord) {
253  // Table has relation fields and record exists - get relations
254  $this->relations = [];
255  ‪$relations = $this->‪generateDataUsingRecord($tableName, $existingRecord);
256  if (!is_array(‪$relations)) {
257  return $result;
258  }
259  // Traverse the generated index:
260  foreach (‪$relations as &$relation) {
261  if (!is_array($relation)) {
262  continue;
263  }
264  // Exclude any relations TO a specific table
265  if (($relation['ref_table'] ?? '') && $this->‪shouldExcludeTableFromReferenceIndex($relation['ref_table'])) {
266  continue;
267  }
268  $relation['hash'] = md5(implode('
269  // First, check if already indexed and if so, unset that row (so in the end we know which rows to remove!)
270  if (isset($currentRelationHashes[$relation['hash']])) {
271  unset($currentRelationHashes[$relation['hash']]);
272  $result['keptNodes']++;
273  $relation['_ACTION'] = 'KEPT';
274  } else {
275  // If new, add it:
276  if (!$testOnly) {
277  $connection->insert('sys_refindex', $relation);
278  }
279  $result['addedNodes']++;
280  $relation['_ACTION'] = 'ADDED';
281  }
282  }
283  $result['relations'] = $relations;
284  }
285  }
286 
287  // If any old are left, remove them:
288  if (!empty($currentRelationHashes)) {
289  $hashList = array_keys($currentRelationHashes);
290  if (!empty($hashList)) {
291  $result['deletedNodes'] = count($hashList);
292  $result['deletedNodes_hashList'] = implode(',', $hashList);
293  if (!$testOnly) {
294  $maxBindParameters = PlatformInformation::getMaxBindParameters($connection->getDatabasePlatform());
295  foreach (array_chunk($hashList, $maxBindParameters - 10, true) as $chunk) {
296  if (empty($chunk)) {
297  continue;
298  }
299  $queryBuilder = $connection->createQueryBuilder();
300  $queryBuilder
301  ->delete('sys_refindex')
302  ->where(
303  $queryBuilder->expr()->in(
304  'hash',
305  $queryBuilder->createNamedParameter($chunk, Connection::PARAM_STR_ARRAY)
306  )
307  )
308  ->execute();
309  }
310  }
311  }
312  }
313 
314  return $result;
315  }
316 
325  public function generateRefIndexData($tableName, $uid)
326  {
327  if (!isset($GLOBALS['TCA'][$tableName])) {
328  return null;
329  }
330 
331  $this->relations = [];
332 
333  $record = null;
334  $uid = $uid ? (int)$uid : 0;
335  if ($uid) {
336  // Get raw record from DB
337  $record = $this->getRecordRawCached($tableName, $uid);
338  }
339 
340  if (!is_array($record)) {
341  return null;
342  }
343 
344  return $this->generateDataUsingRecord($tableName, $record);
345  }
346 
354  public function getNumberOfReferencedRecords(string $tableName, int $uid): int
355  {
356  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_refindex');
357  return (int)$queryBuilder
358  ->count('*')->from('sys_refindex')
359  ->where(
360  $queryBuilder->expr()->eq(
361  'ref_table',
362  $queryBuilder->createNamedParameter($tableName, \PDO::PARAM_STR)
363  ),
364  $queryBuilder->expr()->eq(
365  'ref_uid',
366  $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)
367  ),
368  $queryBuilder->expr()->eq(
369  'deleted',
370  $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
371  )
372  )->execute()->fetchColumn(0);
373  }
374 
382  protected function generateDataUsingRecord(string $tableName, array $record): array
383  {
384  $this->relations = [];
385 
386  if (BackendUtility::isTableWorkspaceEnabled($tableName)) {
387  // Never write relations for t3ver_state = 1 and t3ver_state = 3 placeholder records
388  $versionState = VersionState::cast($record['t3ver_state']);
389  if ($versionState->equals(VersionState::NEW_PLACEHOLDER) || $versionState->equals(VersionState::MOVE_PLACEHOLDER)) {
390  return [];
391  }
392  }
393 
394  // Is the record deleted?
395  $deleteField = $GLOBALS['TCA'][$tableName]['ctrl']['delete'];
396  $deleted = $deleteField && $record[$deleteField] ? 1 : 0;
397 
398  // Get all relations from record:
399  $recordRelations = $this->getRelations($tableName, $record);
400  // Traverse those relations, compile records to insert in table:
401  foreach ($recordRelations as $fieldName => $fieldRelations) {
402  // Based on type
403  switch ((string)$fieldRelations['type']) {
404  case 'db':
405  $this->createEntryDataForDatabaseRelationsUsingRecord($tableName, $record, $fieldName, '', $deleted, $fieldRelations['itemArray']);
406  break;
407  case 'flex':
408  // DB references in FlexForms
409  if (is_array($fieldRelations['flexFormRels']['db'])) {
410  foreach ($fieldRelations['flexFormRels']['db'] as $flexPointer => $subList) {
411  $this->createEntryDataForDatabaseRelationsUsingRecord($tableName, $record, $fieldName, $flexPointer, $deleted, $subList);
412  }
413  }
414  // Soft references in FlexForms
415  // @todo #65464 Test correct handling of soft references in FlexForms
416  if (is_array($fieldRelations['flexFormRels']['softrefs'])) {
417  foreach ($fieldRelations['flexFormRels']['softrefs'] as $flexPointer => $subList) {
418  $this->createEntryDataForSoftReferencesUsingRecord($tableName, $record, $fieldName, $flexPointer, $deleted, $subList['keys']);
419  }
420  }
421  break;
422  }
423  // Soft references in the field
424  if (is_array($fieldRelations['softrefs'])) {
425  $this->createEntryDataForSoftReferencesUsingRecord($tableName, $record, $fieldName, '', $deleted, $fieldRelations['softrefs']['keys']);
426  }
427  }
428 
429  return array_filter($this->relations);
430  }
431 
449  public function createEntryData($table, $uid, $field, $flexPointer, $deleted, $ref_table, $ref_uid, $ref_string = '', $sort = -1, $softref_key = '', $softref_id = '')
450  {
451  $uid = $uid ? (int)$uid : 0;
452  if (!$uid) {
453  return null;
454  }
455  return $this->createEntryDataUsingRecord(
456  (string)$table,
457  $this->getRecordRawCached($table, $uid) ?: [],
458  (string)$field,
459  (string)$flexPointer,
460  $deleted ? (int)$deleted : 0,
461  (string)$ref_table,
462  $ref_uid ? (int)$ref_uid : 0,
463  (string)$ref_string,
464  $sort ? (int)$sort : 0,
465  (string)$softref_key,
466  (string)$softref_id
467  );
468  }
469 
486  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 = '')
487  {
488  $workspaceId = 0;
489  if (BackendUtility::isTableWorkspaceEnabled($tableName)) {
490  $workspaceId = $this->getWorkspaceId();
491  if (isset($record['t3ver_wsid']) && (int)$record['t3ver_wsid'] !== $workspaceId) {
492  // The given record is workspace-enabled but doesn't live in the selected workspace => don't add index as it's not actually there
493  return false;
494  }
495  }
496  return [
497  'tablename' => $tableName,
498  'recuid' => $record['uid'],
499  'field' => $fieldName,
500  'flexpointer' => $flexPointer,
501  'softref_key' => $softReferenceKey,
502  'softref_id' => $softReferenceId,
503  'sorting' => $sort,
504  'deleted' => (int)$deleted,
505  'workspace' => ‪$workspaceId,
506  'ref_table' => $referencedTable,
507  'ref_uid' => $referencedUid,
508  'ref_string' => mb_substr($referenceString, 0, 1024)
509  ];
510  }
511 
522  public function ‪createEntryData_dbRels($table, $uid, $fieldName, $flexPointer, $deleted, $items)
523  {
524  $uid = $uid ? (int)$uid : 0;
525  if (!$uid) {
526  return;
527  }
529  (string)$table,
530  $this->‪getRecordRawCached($table, $uid) ?: [],
531  (string)$fieldName,
532  (string)$flexPointer,
533  $deleted ? (int)$deleted : 0,
534  (array)$items
535  );
536  }
537 
548  protected function ‪createEntryDataForDatabaseRelationsUsingRecord(string $tableName, array $record, string $fieldName, string $flexPointer, int $deleted, array $items)
549  {
550  foreach ($items as $sort => $i) {
551  $this->relations[] = $this->‪createEntryDataUsingRecord($tableName, $record, $fieldName, $flexPointer, $deleted, $i['table'], (int)$i['id'], '', $sort);
552  }
553  }
554 
565  public function ‪createEntryData_softreferences($table, $uid, $fieldName, $flexPointer, $deleted, $keys)
566  {
567  $uid = $uid ? (int)$uid : 0;
568  if (!$uid || !is_array($keys)) {
569  return;
570  }
572  (string)$table,
573  $this->‪getRecordRawCached($table, $uid) ?: [],
574  (string)$fieldName,
575  (string)$flexPointer,
576  $deleted ? (int)$deleted : 0,
577  (array)$keys
578  );
579  }
580 
591  protected function ‪createEntryDataForSoftReferencesUsingRecord(string $tableName, array $record, string $fieldName, string $flexPointer, int $deleted, array $keys)
592  {
593  foreach ($keys as $spKey => $elements) {
594  if (is_array($elements)) {
595  foreach ($elements as $subKey => $el) {
596  if (is_array($el['subst'])) {
597  switch ((string)$el['subst']['type']) {
598  case 'db':
599  [$referencedTable, $referencedUid] = explode(':', $el['subst']['recordRef']);
600  $this->relations[] = $this->‪createEntryDataUsingRecord($tableName, $record, $fieldName, $flexPointer, $deleted, $referencedTable, (int)$referencedUid, '', -1, $spKey, $subKey);
601  break;
602  case 'string':
603  $this->relations[] = $this->‪createEntryDataUsingRecord($tableName, $record, $fieldName, $flexPointer, $deleted, '_STRING', 0, $el['subst']['tokenValue'], -1, $spKey, $subKey);
604  break;
605  }
606  }
607  }
608  }
609  }
610  }
611 
612  /*******************************
613  *
614  * Get relations from table row
615  *
616  *******************************/
617 
629  public function ‪getRelations($table, $row, $onlyField = '')
630  {
631  // Initialize:
632  $uid = $row['uid'];
633  $outRow = [];
634  foreach ($row as $field => $value) {
635  if ($this->‪shouldExcludeTableColumnFromReferenceIndex($table, $field, $onlyField) === false) {
636  $conf = ‪$GLOBALS['TCA'][$table]['columns'][$field]['config'];
637  // Add a softref definition for link fields if the TCA does not specify one already
638  if ($conf['type'] === 'input' && $conf['renderType'] === 'inputLink' && empty($conf['softref'])) {
639  $conf['softref'] = 'typolink';
640  }
641  // Add DB:
642  $resultsFromDatabase = $this->‪getRelations_procDB($value, $conf, $uid, $table);
643  if (!empty($resultsFromDatabase)) {
644  // Create an entry for the field with all DB relations:
645  $outRow[$field] = [
646  'type' => 'db',
647  'itemArray' => $resultsFromDatabase
648  ];
649  }
650  // For "flex" fieldtypes we need to traverse the structure looking for db references of course!
651  if ($conf['type'] === 'flex') {
652  // Get current value array:
653  // NOTICE: failure to resolve Data Structures can lead to integrity problems with the reference index. Please look up
654  // the note in the JavaDoc documentation for the function FlexFormTools->getDataStructureIdentifier()
655  $currentValueArray = ‪GeneralUtility::xml2array($value);
656  // Traversing the XML structure, processing:
657  if (is_array($currentValueArray)) {
658  $this->temp_flexRelations = [
659  'db' => [],
660  'softrefs' => []
661  ];
662  // Create and call iterator object:
663  $flexFormTools = GeneralUtility::makeInstance(FlexFormTools::class);
664  $flexFormTools->traverseFlexFormXMLData($table, $field, $row, $this, 'getRelations_flexFormCallBack');
665  // Create an entry for the field:
666  $outRow[$field] = [
667  'type' => 'flex',
668  'flexFormRels' => ‪$this->temp_flexRelations
669  ];
670  }
671  }
672  // Soft References:
673  if ((string)$value !== '') {
674  $softRefValue = $value;
675  if (!empty($conf['softref'])) {
676  $softRefs = ‪BackendUtility::explodeSoftRefParserList($conf['softref']);
677  foreach ($softRefs as $spKey => $spParams) {
678  $softRefObj = ‪BackendUtility::softRefParserObj($spKey);
679  if (is_object($softRefObj)) {
680  $resultArray = $softRefObj->findRef($table, $field, $uid, $softRefValue, $spKey, $spParams);
681  if (is_array($resultArray)) {
682  $outRow[$field]['softrefs']['keys'][$spKey] = $resultArray['elements'];
683  if ((string)$resultArray['content'] !== '') {
684  $softRefValue = $resultArray['content'];
685  }
686  }
687  }
688  }
689  }
690  if (!empty($outRow[$field]['softrefs']) && (string)$value !== (string)$softRefValue && strpos($softRefValue, '{softref:') !== false) {
691  $outRow[$field]['softrefs']['tokenizedContent'] = $softRefValue;
692  }
693  }
694  }
695  }
696  return $outRow;
697  }
698 
709  public function ‪getRelations_flexFormCallBack($dsArr, $dataValue, $PA, $structurePath)
710  {
711  // Removing "data/" in the beginning of path (which points to location in data array)
712  $structurePath = substr($structurePath, 5) . '/';
713  $dsConf = $dsArr['TCEforms']['config'];
714  // Implode parameter values:
715  [$table, $uid, $field] = [
716  $PA['table'],
717  $PA['uid'],
718  $PA['field']
719  ];
720  // Add a softref definition for link fields if the TCA does not specify one already
721  if ($dsConf['type'] === 'input' && $dsConf['renderType'] === 'inputLink' && empty($dsConf['softref'])) {
722  $dsConf['softref'] = 'typolink';
723  }
724  // Add DB:
725  $resultsFromDatabase = $this->‪getRelations_procDB($dataValue, $dsConf, $uid, $table);
726  if (!empty($resultsFromDatabase)) {
727  // Create an entry for the field with all DB relations:
728  $this->temp_flexRelations['db'][$structurePath] = $resultsFromDatabase;
729  }
730  // Soft References:
731  if (is_array($dataValue) || (string)$dataValue !== '') {
732  $softRefValue = $dataValue;
733  $softRefs = ‪BackendUtility::explodeSoftRefParserList($dsConf['softref']);
734  if ($softRefs !== false) {
735  foreach ($softRefs as $spKey => $spParams) {
736  $softRefObj = ‪BackendUtility::softRefParserObj($spKey);
737  if (is_object($softRefObj)) {
738  $resultArray = $softRefObj->findRef($table, $field, $uid, $softRefValue, $spKey, $spParams, $structurePath);
739  if (is_array($resultArray) && is_array($resultArray['elements'])) {
740  $this->temp_flexRelations['softrefs'][$structurePath]['keys'][$spKey] = $resultArray['elements'];
741  if ((string)$resultArray['content'] !== '') {
742  $softRefValue = $resultArray['content'];
743  }
744  }
745  }
746  }
747  }
748  if (!empty($this->temp_flexRelations['softrefs']) && (string)$dataValue !== (string)$softRefValue) {
749  $this->temp_flexRelations['softrefs'][$structurePath]['tokenizedContent'] = $softRefValue;
750  }
751  }
752  }
753 
763  public function ‪getRelations_procDB($value, $conf, $uid, $table = '')
764  {
765  // Get IRRE relations
766  if (empty($conf)) {
767  return false;
768  }
769  if ($conf['type'] === 'inline' && !empty($conf['foreign_table']) && empty($conf['MM'])) {
770  $dbAnalysis = GeneralUtility::makeInstance(RelationHandler::class);
771  $dbAnalysis->setUseLiveReferenceIds(false);
772  $dbAnalysis->setWorkspaceId($this->‪getWorkspaceId());
773  $dbAnalysis->start($value, $conf['foreign_table'], '', $uid, $table, $conf);
774  return $dbAnalysis->itemArray;
775  // DB record lists:
776  }
777  if ($this->‪isDbReferenceField($conf)) {
778  $allowedTables = $conf['type'] === 'group' ? $conf['allowed'] : $conf['foreign_table'];
779  if ($conf['MM_opposite_field']) {
780  return [];
781  }
782  $dbAnalysis = GeneralUtility::makeInstance(RelationHandler::class);
783  $dbAnalysis->start($value, $allowedTables, $conf['MM'], $uid, $table, $conf);
784  return $dbAnalysis->itemArray;
785  }
786  return false;
787  }
788 
789  /*******************************
790  *
791  * Setting values
792  *
793  *******************************/
794 
814  public function ‪setReferenceValue($hash, $newValue, $returnDataArray = false, $bypassWorkspaceAdminCheck = false)
815  {
816  $backendUser = $this->‪getBackendUser();
817  if ($backendUser->workspace === 0 && $backendUser->isAdmin() || $bypassWorkspaceAdminCheck) {
818  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_refindex');
819  $queryBuilder->getRestrictions()->removeAll();
820 
821  // Get current index from Database
822  $referenceRecord = $queryBuilder
823  ->select('*')
824  ->from('sys_refindex')
825  ->where(
826  $queryBuilder->expr()->eq('hash', $queryBuilder->createNamedParameter($hash, \PDO::PARAM_STR))
827  )
828  ->setMaxResults(1)
829  ->execute()
830  ->fetch();
831 
832  // Check if reference existed.
833  if (!is_array($referenceRecord)) {
834  return 'ERROR: No reference record with hash="' . $hash . '" was found!';
835  }
836 
837  if (empty(‪$GLOBALS['TCA'][$referenceRecord['tablename']])) {
838  return 'ERROR: Table "' . $referenceRecord['tablename'] . '" was not in TCA!';
839  }
840 
841  // Get that record from database
842  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
843  ->getQueryBuilderForTable($referenceRecord['tablename']);
844  $queryBuilder->getRestrictions()->removeAll();
845  $record = $queryBuilder
846  ->select('*')
847  ->from($referenceRecord['tablename'])
848  ->where(
849  $queryBuilder->expr()->eq(
850  'uid',
851  $queryBuilder->createNamedParameter($referenceRecord['recuid'], \PDO::PARAM_INT)
852  )
853  )
854  ->setMaxResults(1)
855  ->execute()
856  ->fetch();
857 
858  if (is_array($record)) {
859  // Get relation for single field from record
860  $recordRelations = $this->‪getRelations($referenceRecord['tablename'], $record, $referenceRecord['field']);
861  if ($fieldRelation = $recordRelations[$referenceRecord['field']]) {
862  // Initialize data array that is to be sent to DataHandler afterwards:
863  $dataArray = [];
864  // Based on type
865  switch ((string)$fieldRelation['type']) {
866  case 'db':
867  $error = $this->‪setReferenceValue_dbRels($referenceRecord, $fieldRelation['itemArray'], $newValue, $dataArray);
868  if ($error) {
869  return $error;
870  }
871  break;
872  case 'flex':
873  // DB references in FlexForms
874  if (is_array($fieldRelation['flexFormRels']['db'][$referenceRecord['flexpointer']])) {
875  $error = $this->‪setReferenceValue_dbRels($referenceRecord, $fieldRelation['flexFormRels']['db'][$referenceRecord['flexpointer']], $newValue, $dataArray, $referenceRecord['flexpointer']);
876  if ($error) {
877  return $error;
878  }
879  }
880  // Soft references in FlexForms
881  if ($referenceRecord['softref_key'] && is_array($fieldRelation['flexFormRels']['softrefs'][$referenceRecord['flexpointer']]['keys'][$referenceRecord['softref_key']])) {
882  $error = $this->‪setReferenceValue_softreferences($referenceRecord, $fieldRelation['flexFormRels']['softrefs'][$referenceRecord['flexpointer']], $newValue, $dataArray, $referenceRecord['flexpointer']);
883  if ($error) {
884  return $error;
885  }
886  }
887  break;
888  }
889  // Soft references in the field:
890  if ($referenceRecord['softref_key'] && is_array($fieldRelation['softrefs']['keys'][$referenceRecord['softref_key']])) {
891  $error = $this->‪setReferenceValue_softreferences($referenceRecord, $fieldRelation['softrefs'], $newValue, $dataArray);
892  if ($error) {
893  return $error;
894  }
895  }
896  // Data Array, now ready to be sent to DataHandler
897  if ($returnDataArray) {
898  return $dataArray;
899  }
900  // Execute CMD array:
901  $dataHandler = GeneralUtility::makeInstance(DataHandler::class);
902  $dataHandler->dontProcessTransformations = true;
903  $dataHandler->bypassWorkspaceRestrictions = true;
904  // Otherwise this cannot update things in deleted records...
905  $dataHandler->bypassAccessCheckForRecords = true;
906  // Check has been done previously that there is a backend user which is Admin and also in live workspace
907  $dataHandler->start($dataArray, []);
908  $dataHandler->process_datamap();
909  // Return errors if any:
910  if (!empty($dataHandler->errorLog)) {
911  return LF . 'DataHandler:' . implode(LF . 'DataHandler:', $dataHandler->errorLog);
912  }
913  }
914  }
915  } else {
916  return 'ERROR: BE_USER object is not admin OR not in workspace 0 (Live)';
917  }
918 
919  return false;
920  }
921 
932  public function ‪setReferenceValue_dbRels($refRec, $itemArray, $newValue, &$dataArray, $flexPointer = '')
933  {
934  if ((int)$itemArray[$refRec['sorting']]['id'] === (int)$refRec['ref_uid'] && (string)$itemArray[$refRec['sorting']]['table'] === (string)$refRec['ref_table']) {
935  // Setting or removing value:
936  // Remove value:
937  if ($newValue === null) {
938  unset($itemArray[$refRec['sorting']]);
939  } else {
940  [$itemArray[$refRec['sorting']]['table'], $itemArray[$refRec['sorting']]['id']] = explode(':', $newValue);
941  }
942  // Traverse and compile new list of records:
943  $saveValue = [];
944  foreach ($itemArray as $pair) {
945  $saveValue[] = $pair['table'] . '_' . $pair['id'];
946  }
947  // Set in data array:
948  if ($flexPointer) {
949  $flexFormTools = GeneralUtility::makeInstance(FlexFormTools::class);
950  $dataArray[$refRec['tablename']][$refRec['recuid']][$refRec['field']]['data'] = [];
951  $flexFormTools->setArrayValueByPath(substr($flexPointer, 0, -1), $dataArray[$refRec['tablename']][$refRec['recuid']][$refRec['field']]['data'], implode(',', $saveValue));
952  } else {
953  $dataArray[$refRec['tablename']][$refRec['recuid']][$refRec['field']] = implode(',', $saveValue);
954  }
955  } else {
956  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'] . '"';
957  }
958 
959  return false;
960  }
961 
972  public function ‪setReferenceValue_softreferences($refRec, $softref, $newValue, &$dataArray, $flexPointer = '')
973  {
974  if (!is_array($softref['keys'][$refRec['softref_key']][$refRec['softref_id']])) {
975  return 'ERROR: Soft reference parser key "' . $refRec['softref_key'] . '" or the index "' . $refRec['softref_id'] . '" was not found.';
976  }
977 
978  // Set new value:
979  $softref['keys'][$refRec['softref_key']][$refRec['softref_id']]['subst']['tokenValue'] = '' . $newValue;
980  // Traverse softreferences and replace in tokenized content to rebuild it with new value inside:
981  foreach ($softref['keys'] as $sfIndexes) {
982  foreach ($sfIndexes as $data) {
983  $softref['tokenizedContent'] = str_replace('{softref:' . $data['subst']['tokenID'] . '}', $data['subst']['tokenValue'], $softref['tokenizedContent']);
984  }
985  }
986  // Set in data array:
987  if (strpos($softref['tokenizedContent'], '{softref:') === false) {
988  if ($flexPointer) {
989  $flexFormTools = GeneralUtility::makeInstance(FlexFormTools::class);
990  $dataArray[$refRec['tablename']][$refRec['recuid']][$refRec['field']]['data'] = [];
991  $flexFormTools->setArrayValueByPath(substr($flexPointer, 0, -1), $dataArray[$refRec['tablename']][$refRec['recuid']][$refRec['field']]['data'], $softref['tokenizedContent']);
992  } else {
993  $dataArray[$refRec['tablename']][$refRec['recuid']][$refRec['field']] = $softref['tokenizedContent'];
994  }
995  } else {
996  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.)';
997  }
998 
999  return false;
1000  }
1001 
1002  /*******************************
1003  *
1004  * Helper functions
1005  *
1006  *******************************/
1007 
1014  protected function ‪isDbReferenceField(array $configuration)
1015  {
1016  return
1017  ($configuration['type'] === 'group' && $configuration['internal_type'] === 'db')
1018  || (
1019  ($configuration['type'] === 'select' || $configuration['type'] === 'inline')
1020  && !empty($configuration['foreign_table'])
1021  )
1022  ;
1023  }
1024 
1031  public function ‪isReferenceField(array $configuration)
1032  {
1033  return
1034  $this->‪isDbReferenceField($configuration)
1035  ||
1036  ($configuration['type'] === 'input' && $configuration['renderType'] === 'inputLink') // getRelations_procDB
1037  ||
1038  $configuration['type'] === 'flex'
1039  ||
1040  isset($configuration['softref'])
1041  ;
1042  }
1043 
1050  protected function ‪fetchTableRelationFields($tableName)
1051  {
1052  if (!isset(‪$GLOBALS['TCA'][$tableName]['columns'])) {
1053  return '';
1054  }
1055 
1056  ‪$fields = [];
1057 
1058  foreach (‪$GLOBALS['TCA'][$tableName]['columns'] as $field => $fieldDefinition) {
1059  if (is_array($fieldDefinition['config'])) {
1060  // Check for flex field
1061  if (isset($fieldDefinition['config']['type']) && $fieldDefinition['config']['type'] === 'flex') {
1062  // Fetch all fields if the is a field of type flex in the table definition because the complete row is passed to
1063  // FlexFormTools->getDataStructureIdentifier() in the end and might be needed in ds_pointerField or a hook
1064  return '*';
1065  }
1066  // Only fetch this field if it can contain a reference
1067  if ($this->‪isReferenceField($fieldDefinition['config'])) {
1068  ‪$fields[] = $field;
1069  }
1070  }
1071  }
1073  return implode(',', ‪$fields);
1074  }
1075 
1083  public function ‪updateIndex($testOnly, $cli_echo = null)
1084  {
1085  $progressListener = null;
1086  if ($cli_echo instanceof ‪ProgressListenerInterface) {
1087  $progressListener = $cli_echo;
1088  $cli_echo = null;
1089  }
1090  if ($cli_echo !== null) {
1091  trigger_error('The second argument of ReferenceIndex->updateIndex() will not work in TYPO3 v11 anymore. Use the ProgressListener to show detailed results', E_USER_DEPRECATED);
1092  } else {
1093  // default value for now
1094  $cli_echo = false;
1095  }
1096  ‪$errors = [];
1097  $tableNames = [];
1098  $recCount = 0;
1099  $headerContent = $testOnly ? 'Reference Index being TESTED (nothing written, remove the "--check" argument)' : 'Reference Index being Updated';
1100  if ($cli_echo) {
1101  echo '*******************************************' . LF . $headerContent . LF . '*******************************************' . LF;
1102  }
1103  // Traverse all tables:
1104  $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
1105  $refIndexConnectionName = empty(‪$GLOBALS['TYPO3_CONF_VARS']['DB']['TableMapping']['sys_refindex'])
1107  : ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['TableMapping']['sys_refindex'];
1108 
1109  foreach (‪$GLOBALS['TCA'] as $tableName => $cfg) {
1110  if ($this->‪shouldExcludeTableFromReferenceIndex($tableName)) {
1111  continue;
1112  }
1113  $tableConnectionName = empty(‪$GLOBALS['TYPO3_CONF_VARS']['DB']['TableMapping'][$tableName])
1115  : ‪$GLOBALS['TYPO3_CONF_VARS']['DB']['TableMapping'][$tableName];
1116 
1117  ‪$fields = ['uid'];
1119  ‪$fields[] = 't3ver_wsid';
1120  }
1121  // Traverse all records in tables, including deleted records
1122  $queryBuilder = $connectionPool->getQueryBuilderForTable($tableName);
1123  $queryBuilder->getRestrictions()->removeAll();
1124  try {
1125  $queryResult = $queryBuilder
1126  ->select(...‪$fields)
1127  ->from($tableName)
1128  ->orderBy('uid')
1129  ->execute();
1130  } catch (DBALException $e) {
1131  // Table exists in TCA but does not exist in the database
1132  $msg = 'Table "' .
1133  $tableName .
1134  '" exists in TCA but does not exist in the database. You should run the Database Analyzer in the Install Tool to fix this.';
1135  $this->logger->error($msg, ['exception' => $e]);
1136  continue;
1137  }
1138 
1139  if ($progressListener) {
1140  $progressListener->start($queryResult->rowCount(), $tableName);
1141  }
1142  $tableNames[] = $tableName;
1143  while ($record = $queryResult->fetch()) {
1144  if ($progressListener) {
1145  $progressListener->advance();
1146  }
1147  $refIndexObj = GeneralUtility::makeInstance(self::class);
1148  if (isset($record['t3ver_wsid'])) {
1149  $refIndexObj->setWorkspaceId($record['t3ver_wsid']);
1150  }
1151  $result = $refIndexObj->updateRefIndexTable($tableName, $record['uid'], $testOnly);
1152  $recCount++;
1153  if ($result['addedNodes'] || $result['deletedNodes']) {
1154  $error = 'Record ' . $tableName . ':' . $record['uid'] . ' had ' . $result['addedNodes'] . ' added indexes and ' . $result['deletedNodes'] . ' deleted indexes';
1155  ‪$errors[] = $error;
1156  if ($progressListener) {
1157  $progressListener->log($error, LogLevel::WARNING);
1158  }
1159  if ($cli_echo) {
1160  echo $error . LF;
1161  }
1162  }
1163  }
1164  if ($progressListener) {
1165  $progressListener->finish();
1166  }
1167 
1168  // Subselect based queries only work on the same connection
1169  if ($refIndexConnectionName !== $tableConnectionName) {
1170  $this->logger->error('Not checking table "' . $tableName . '" for lost indexes, "sys_refindex" table uses a different connection');
1171  continue;
1172  }
1173 
1174  // Searching for lost indexes for this table
1175  // Build sub-query to find lost records
1176  $subQueryBuilder = $connectionPool->getQueryBuilderForTable($tableName);
1177  $subQueryBuilder->getRestrictions()->removeAll();
1178  $subQueryBuilder
1179  ->select('uid')
1180  ->from($tableName, 'sub_' . $tableName)
1181  ->where(
1182  $subQueryBuilder->expr()->eq(
1183  'sub_' . $tableName . '.uid',
1184  $queryBuilder->quoteIdentifier('sys_refindex.recuid')
1185  )
1186  );
1187 
1188  // Main query to find lost records
1189  $queryBuilder = $connectionPool->getQueryBuilderForTable('sys_refindex');
1190  $queryBuilder->getRestrictions()->removeAll();
1191  $lostIndexes = $queryBuilder
1192  ->count('hash')
1193  ->from('sys_refindex')
1194  ->where(
1195  $queryBuilder->expr()->eq(
1196  'tablename',
1197  $queryBuilder->createNamedParameter($tableName, \PDO::PARAM_STR)
1198  ),
1199  'NOT EXISTS (' . $subQueryBuilder->getSQL() . ')'
1200  )
1201  ->execute()
1202  ->fetchColumn(0);
1203 
1204  if ($lostIndexes > 0) {
1205  $error = 'Table ' . $tableName . ' has ' . $lostIndexes . ' lost indexes which are now deleted';
1206  ‪$errors[] = $error;
1207  if ($progressListener) {
1208  $progressListener->log($error, LogLevel::WARNING);
1209  }
1210  if ($cli_echo) {
1211  echo $error . LF;
1212  }
1213  if (!$testOnly) {
1214  $queryBuilder = $connectionPool->getQueryBuilderForTable('sys_refindex');
1215  $queryBuilder->delete('sys_refindex')
1216  ->where(
1217  $queryBuilder->expr()->eq(
1218  'tablename',
1219  $queryBuilder->createNamedParameter($tableName, \PDO::PARAM_STR)
1220  ),
1221  'NOT EXISTS (' . $subQueryBuilder->getSQL() . ')'
1222  )
1223  ->execute();
1224  }
1225  }
1226  }
1227 
1228  // Searching lost indexes for non-existing tables
1229  $lostTables = $this->‪getAmountOfUnusedTablesInReferenceIndex($tableNames);
1230  if ($lostTables > 0) {
1231  $error = 'Index table hosted ' . $lostTables . ' indexes for non-existing tables, now removed';
1232  ‪$errors[] = $error;
1233  if ($progressListener) {
1234  $progressListener->log($error, LogLevel::WARNING);
1235  }
1236  if ($cli_echo) {
1237  echo $error . LF;
1238  }
1239  if (!$testOnly) {
1241  }
1242  }
1243  $errorCount = count(‪$errors);
1244  $recordsCheckedString = $recCount . ' records from ' . count($tableNames) . ' tables were checked/updated.' . LF;
1245  if ($progressListener) {
1246  if ($errorCount) {
1247  $progressListener->log($recordsCheckedString . 'Updates: ' . $errorCount, LogLevel::WARNING);
1248  } else {
1249  $progressListener->log($recordsCheckedString . 'Index Integrity was perfect!', LogLevel::INFO);
1250  }
1251  }
1252  if ($cli_echo) {
1253  echo $recordsCheckedString . ($errorCount ? 'Updates: ' . $errorCount : 'Index Integrity was perfect!') . LF;
1254  }
1255  if (!$testOnly) {
1256  $registry = GeneralUtility::makeInstance(Registry::class);
1257  $registry->set('core', 'sys_refindex_lastUpdate', ‪$GLOBALS['EXEC_TIME']);
1258  }
1259  return [$headerContent, trim($recordsCheckedString), $errorCount, ‪$errors];
1260  }
1261 
1262  protected function ‪getAmountOfUnusedTablesInReferenceIndex(array $tableNames): int
1263  {
1264  $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
1265  $queryBuilder = $connectionPool->getQueryBuilderForTable('sys_refindex');
1266  $queryBuilder->getRestrictions()->removeAll();
1267  $lostTables = $queryBuilder
1268  ->count('hash')
1269  ->from('sys_refindex')
1270  ->where(
1271  $queryBuilder->expr()->notIn(
1272  'tablename',
1273  $queryBuilder->createNamedParameter($tableNames, Connection::PARAM_STR_ARRAY)
1274  )
1275  )->execute()
1276  ->fetchColumn(0);
1277  return (int)$lostTables;
1278  }
1279 
1280  protected function ‪removeReferenceIndexDataFromUnusedDatabaseTables(array $tableNames): void
1281  {
1282  $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
1283  $queryBuilder = $connectionPool->getQueryBuilderForTable('sys_refindex');
1284  $queryBuilder->delete('sys_refindex')
1285  ->where(
1286  $queryBuilder->expr()->notIn(
1287  'tablename',
1288  $queryBuilder->createNamedParameter($tableNames, Connection::PARAM_STR_ARRAY)
1289  )
1290  )->execute();
1291  }
1292 
1313  protected function ‪getRecordRawCached(string $tableName, int $uid)
1314  {
1315  $recordCacheId = $tableName . ':' . $uid;
1316  if (!$this->useRuntimeCache || !isset($this->recordCache[$recordCacheId])) {
1317 
1318  // Fetch fields of the table which might contain relations
1319  $cacheId = static::$cachePrefixTableRelationFields . $tableName;
1320  $tableRelationFields = $this->useRuntimeCache ? $this->runtimeCache->get($cacheId) : false;
1321  if ($tableRelationFields === false) {
1322  $tableRelationFields = $this->‪fetchTableRelationFields($tableName);
1323  if ($this->useRuntimeCache) {
1324  $this->runtimeCache->set($cacheId, $tableRelationFields);
1325  }
1326  }
1327 
1328  // Return if there are no fields which could contain relations
1329  if ($tableRelationFields === '') {
1330  return ‪$this->relations;
1331  }
1332 
1333  if ($tableRelationFields === '*') {
1334  // If one field of a record is of type flex, all fields have to be fetched to be passed to FlexFormTools->getDataStructureIdentifier()
1335  $selectFields = '*';
1336  } else {
1337  // otherwise only fields that might contain relations are fetched
1338  $selectFields = 'uid,' . $tableRelationFields;
1339  $deleteField = ‪$GLOBALS['TCA'][$tableName]['ctrl']['delete'];
1340  if ($deleteField) {
1341  $selectFields .= ',' . $deleteField;
1342  }
1344  $selectFields .= ',t3ver_wsid,t3ver_state';
1345  }
1346  }
1347 
1348  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
1349  ->getQueryBuilderForTable($tableName);
1350  $queryBuilder->getRestrictions()->removeAll();
1351  $row = $queryBuilder
1352  ->select(...‪GeneralUtility::trimExplode(',', $selectFields, true))
1353  ->from($tableName)
1354  ->where(
1355  $queryBuilder->expr()->eq(
1356  'uid',
1357  $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)
1358  )
1359  )
1360  ->execute()
1361  ->fetch();
1362 
1363  $this->recordCache[$recordCacheId] = $row;
1364  }
1365  return $this->recordCache[$recordCacheId];
1366  }
1367 
1374  protected function ‪shouldExcludeTableFromReferenceIndex($tableName)
1375  {
1376  if (isset(static::$excludedTables[$tableName])) {
1377  return static::$excludedTables[$tableName];
1378  }
1379 
1380  // Only exclude tables from ReferenceIndex which do not contain any relations and never
1381  // did since existing references won't be deleted!
1382  $event = new IsTableExcludedFromReferenceIndexEvent($tableName);
1383  $event = $this->eventDispatcher->dispatch($event);
1384  static::$excludedTables[$tableName] = $event->isTableExcluded();
1385 
1386  return static::$excludedTables[$tableName];
1387  }
1388 
1397  protected function ‪shouldExcludeTableColumnFromReferenceIndex($tableName, $column, $onlyColumn)
1398  {
1399  if (isset(static::$excludedColumns[$column])) {
1400  return true;
1401  }
1402 
1403  if (is_array(‪$GLOBALS['TCA'][$tableName]['columns'][$column]) && (!$onlyColumn || $onlyColumn === $column)) {
1404  return false;
1405  }
1406 
1407  return true;
1408  }
1409 
1415  public function ‪enableRuntimeCache()
1416  {
1417  $this->useRuntimeCache = true;
1418  }
1419 
1423  public function ‪disableRuntimeCache()
1424  {
1425  $this->useRuntimeCache = false;
1426  }
1427 
1433  protected function ‪getBackendUser()
1434  {
1435  return ‪$GLOBALS['BE_USER'];
1436  }
1437 }
‪TYPO3\CMS\Core\DataHandling\DataHandler
Definition: DataHandler.php:84
‪TYPO3\CMS\Core\DataHandling\Event\IsTableExcludedFromReferenceIndexEvent
Definition: IsTableExcludedFromReferenceIndexEvent.php:28
‪TYPO3\CMS\Core\Utility\GeneralUtility\xml2array
‪static mixed xml2array($string, $NSprefix='', $reportDocTag=false)
Definition: GeneralUtility.php:1531
‪TYPO3\CMS\Core\Database\ReferenceIndex\disableRuntimeCache
‪disableRuntimeCache()
Definition: ReferenceIndex.php:1412
‪TYPO3\CMS\Core\Database\ReferenceIndex\$cachePrefixTableRelationFields
‪static string $cachePrefixTableRelationFields
Definition: ReferenceIndex.php:92
‪TYPO3\CMS\Core\Database\ReferenceIndex\$temp_flexRelations
‪array $temp_flexRelations
Definition: ReferenceIndex.php:101
‪TYPO3\CMS\Core\Database\ReferenceIndex\getAmountOfUnusedTablesInReferenceIndex
‪getAmountOfUnusedTablesInReferenceIndex(array $tableNames)
Definition: ReferenceIndex.php:1251
‪TYPO3\CMS\Core\Database\ReferenceIndex\$relations
‪array $relations
Definition: ReferenceIndex.php:109
‪TYPO3\CMS\Core\Database\ReferenceIndex\getRecordRawCached
‪array false getRecordRawCached(string $tableName, int $uid)
Definition: ReferenceIndex.php:1302
‪TYPO3\CMS\Core\Database\ReferenceIndex\getRelations_procDB
‪array bool getRelations_procDB($value, $conf, $uid, $table='')
Definition: ReferenceIndex.php:752
‪TYPO3\CMS\Core\Database\ReferenceIndex\enableRuntimeCache
‪enableRuntimeCache()
Definition: ReferenceIndex.php:1404
‪TYPO3\CMS\Backend\Utility\BackendUtility\softRefParserObj
‪static mixed softRefParserObj($spKey)
Definition: BackendUtility.php:3225
‪TYPO3\CMS\Core\Database\ReferenceIndex\shouldExcludeTableColumnFromReferenceIndex
‪bool shouldExcludeTableColumnFromReferenceIndex($tableName, $column, $onlyColumn)
Definition: ReferenceIndex.php:1386
‪TYPO3\CMS\Core\Database\ReferenceIndex\shouldExcludeTableFromReferenceIndex
‪bool shouldExcludeTableFromReferenceIndex($tableName)
Definition: ReferenceIndex.php:1363
‪TYPO3\CMS\Core\Database\ReferenceIndex\createEntryData_softreferences
‪createEntryData_softreferences($table, $uid, $fieldName, $flexPointer, $deleted, $keys)
Definition: ReferenceIndex.php:554
‪TYPO3\CMS\Core\Database\ReferenceIndex\$eventDispatcher
‪EventDispatcherInterface $eventDispatcher
Definition: ReferenceIndex.php:144
‪TYPO3\CMS\Core\Database\ReferenceIndex
Definition: ReferenceIndex.php:48
‪TYPO3\CMS\Core\Database\ReferenceIndex\createEntryDataForSoftReferencesUsingRecord
‪createEntryDataForSoftReferencesUsingRecord(string $tableName, array $record, string $fieldName, string $flexPointer, int $deleted, array $keys)
Definition: ReferenceIndex.php:580
‪TYPO3\CMS\Core\Database\ReferenceIndex\$excludedColumns
‪static array $excludedColumns
Definition: ReferenceIndex.php:77
‪TYPO3\CMS\Core\Registry
Definition: Registry.php:33
‪TYPO3\CMS\Core\Database\ReferenceIndex\fetchTableRelationFields
‪string fetchTableRelationFields($tableName)
Definition: ReferenceIndex.php:1039
‪TYPO3\CMS\Core\Database\ReferenceIndex\$excludedTables
‪static array $excludedTables
Definition: ReferenceIndex.php:63
‪TYPO3\CMS\Core\Database\ReferenceIndex\$recordCache
‪array $recordCache
Definition: ReferenceIndex.php:116
‪TYPO3\CMS\Core\Database\ReferenceIndex\__construct
‪__construct(EventDispatcherInterface $eventDispatcher=null)
Definition: ReferenceIndex.php:149
‪TYPO3\CMS\Core\Database\ReferenceIndex\getRelations
‪array getRelations($table, $row, $onlyField='')
Definition: ReferenceIndex.php:618
‪TYPO3\CMS\Core\Database\ReferenceIndex\removeReferenceIndexDataFromUnusedDatabaseTables
‪removeReferenceIndexDataFromUnusedDatabaseTables(array $tableNames)
Definition: ReferenceIndex.php:1269
‪TYPO3\CMS\Core\Database\ReferenceIndex\$useRuntimeCache
‪bool $useRuntimeCache
Definition: ReferenceIndex.php:140
‪$fields
‪$fields
Definition: pages.php:5
‪TYPO3\CMS\Core\Database\ReferenceIndex\createEntryData_dbRels
‪createEntryData_dbRels($table, $uid, $fieldName, $flexPointer, $deleted, $items)
Definition: ReferenceIndex.php:511
‪TYPO3\CMS\Core\Database\ConnectionPool\DEFAULT_CONNECTION_NAME
‪const DEFAULT_CONNECTION_NAME
Definition: ConnectionPool.php:50
‪TYPO3\CMS\Core\Database\ReferenceIndex\isReferenceField
‪bool isReferenceField(array $configuration)
Definition: ReferenceIndex.php:1020
‪TYPO3\CMS\Backend\Utility\BackendUtility\isTableWorkspaceEnabled
‪static bool isTableWorkspaceEnabled($table)
Definition: BackendUtility.php:4021
‪TYPO3\CMS\Core\Database\ReferenceIndex\createEntryDataUsingRecord
‪array bool createEntryDataUsingRecord(string $tableName, array $record, string $fieldName, string $flexPointer, int $deleted, string $referencedTable, int $referencedUid, string $referenceString='', int $sort=-1, string $softReferenceKey='', string $softReferenceId='')
Definition: ReferenceIndex.php:475
‪TYPO3\CMS\Core\Database\ReferenceIndex\setWorkspaceId
‪setWorkspaceId($workspaceId)
Definition: ReferenceIndex.php:161
‪TYPO3\CMS\Core\Database\ReferenceIndex\$workspaceId
‪int $workspaceId
Definition: ReferenceIndex.php:129
‪TYPO3\CMS\Core\Database\ReferenceIndex\getBackendUser
‪TYPO3 CMS Core Authentication BackendUserAuthentication getBackendUser()
Definition: ReferenceIndex.php:1422
‪TYPO3\CMS\Core\Database\ReferenceIndex\updateRefIndexTable
‪array updateRefIndexTable($tableName, $uid, $testOnly=false)
Definition: ReferenceIndex.php:190
‪TYPO3\CMS\Core\Database\ReferenceIndex\isDbReferenceField
‪bool isDbReferenceField(array $configuration)
Definition: ReferenceIndex.php:1003
‪TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools
Definition: FlexFormTools.php:38
‪TYPO3\CMS\Core\Database\ReferenceIndex\setReferenceValue_dbRels
‪string setReferenceValue_dbRels($refRec, $itemArray, $newValue, &$dataArray, $flexPointer='')
Definition: ReferenceIndex.php:921
‪TYPO3\CMS\Core\Cache\CacheManager
Definition: CacheManager.php:35
‪TYPO3\CMS\Core\Database\ReferenceIndex\$hashVersion
‪int $hashVersion
Definition: ReferenceIndex.php:123
‪TYPO3\CMS\Backend\Utility\BackendUtility
Definition: BackendUtility.php:75
‪TYPO3\CMS\Backend\Utility\BackendUtility\explodeSoftRefParserList
‪static array bool explodeSoftRefParserList($parserList)
Definition: BackendUtility.php:3252
‪TYPO3\CMS\Core\Database\ReferenceIndex\createEntryDataForDatabaseRelationsUsingRecord
‪createEntryDataForDatabaseRelationsUsingRecord(string $tableName, array $record, string $fieldName, string $flexPointer, int $deleted, array $items)
Definition: ReferenceIndex.php:537
‪$errors
‪$errors
Definition: annotationChecker.php:121
‪TYPO3\CMS\Core\Versioning\VersionState
Definition: VersionState.php:24
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static string[] trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:1059
‪TYPO3\CMS\Core\Database\ReferenceIndex\generateDataUsingRecord
‪array generateDataUsingRecord(string $tableName, array $record)
Definition: ReferenceIndex.php:371
‪TYPO3\CMS\Backend\View\ProgressListenerInterface
Definition: ProgressListenerInterface.php:31
‪TYPO3\CMS\Core\Database\ReferenceIndex\$runtimeCache
‪TYPO3 CMS Core Cache Frontend FrontendInterface $runtimeCache
Definition: ReferenceIndex.php:135
‪TYPO3\CMS\Core\Database\ReferenceIndex\getRelations_flexFormCallBack
‪getRelations_flexFormCallBack($dsArr, $dataValue, $PA, $structurePath)
Definition: ReferenceIndex.php:698
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Core\Database\Platform\PlatformInformation
Definition: PlatformInformation.php:33
‪TYPO3\CMS\Core\Database\ReferenceIndex\setReferenceValue_softreferences
‪string setReferenceValue_softreferences($refRec, $softref, $newValue, &$dataArray, $flexPointer='')
Definition: ReferenceIndex.php:961
‪TYPO3\CMS\Core\Database\ReferenceIndex\updateIndex
‪array updateIndex($testOnly, $cli_echo=null)
Definition: ReferenceIndex.php:1072
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪TYPO3\CMS\Core\Database\ReferenceIndex\getWorkspaceId
‪int getWorkspaceId()
Definition: ReferenceIndex.php:173
‪TYPO3\CMS\Core\Database
Definition: Connection.php:18
‪TYPO3\CMS\Core\Database\ReferenceIndex\setReferenceValue
‪string bool array setReferenceValue($hash, $newValue, $returnDataArray=false, $bypassWorkspaceAdminCheck=false)
Definition: ReferenceIndex.php:803