Classes/Console/Service/Persistence/PersistenceIntegrityService.php
protected function checkOrUpdateReferenceIndex($dryRun, ReferenceIndexIntegrityDelegateInterface $delegate = null)
    {
        $processedTables = [];
        $errorCount = 0;
        $recordCount = 0;

        $this->callDelegateForEvent($delegate, 'willStartOperation', [$this->persistenceContext->countAllRecordsOfAllTables()]);

        // Traverse all tables:
        foreach ($this->persistenceContext->getPersistenceConfiguration() as $tableName => $_) {
            // Traverse all records in tables, including deleted records:
            try {
                $records = $this->persistenceContext->getAllRecordsOfTable($tableName);
            } catch (TableDoesNotExistException $e) {
                $this->delegateLog($delegate, 'warning', $e->getMessage());
                continue;
            }
            if (!is_array($records) && !$records instanceof \Traversable) {
                $this->delegateLog($delegate, 'error', 'Table "%s" exists in $TCA but fetching records from database failed. Check the Database Analyzer in Install Tool for missing fields.', [$tableName]);
                continue;
            }
            $processedTables[] = $tableName;
            foreach ($records as $record) {
                $this->callDelegateForEvent($delegate, 'willUpdateRecord', [$tableName, $record]);

                /** @var $refIndexObj ReferenceIndex */
                $refIndexObj = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ReferenceIndex::class);
                if (isset($record['t3ver_wsid'])) {
                    $refIndexObj->setWorkspaceId($record['t3ver_wsid']);
                }
                $result = $refIndexObj->updateRefIndexTable($tableName, $record['uid'], $dryRun);
                $recordCount++;
                if ($result['addedNodes'] || $result['deletedNodes']) {
                    $errorMessage = 'Record ' . $tableName . ':' . $record['uid'];
                    if ($dryRun) {
                        $errorMessage .= ' has ' . $result['addedNodes'] . ' missing indexes and ' . $result['deletedNodes'] . ' stale indexes.';
                    } else {
                        $errorMessage .= ' ' . $result['addedNodes'] . ' indexes were added and ' . $result['deletedNodes'] . ' stale indexes were removed.';
                    }
                    $errorCount++;
                    $this->delegateLog($delegate, 'notice', $errorMessage);
                }
            }
            try {
                // Searching lost indexes for this table:
                $lostIndexCount = $this->persistenceContext->countLostIndexesOfRecordsInTable($tableName);
                if ($lostIndexCount > 0) {
                    $errorMessage = 'Table ' . $tableName . ' has ' . $lostIndexCount;
                    if ($dryRun) {
                        $errorMessage .= ' which need to be deleted.';
                    } else {
                        $errorMessage .= ' which have been deleted.';
                    }
                    $errorCount++;
                    $this->delegateLog($delegate, 'notice', $errorMessage);
                    if (!$dryRun) {
                        $this->persistenceContext->deleteLostIndexesOfRecordsInTable($tableName);
                    }
                }
            } catch (TableDoesNotExistException $e) {
                $this->delegateLog($delegate, 'warning', $e->getMessage());
                continue;
            }
        }

        // Searching lost indexes for non-existing tables:
        $lostTablesCount = $this->persistenceContext->countLostTables($processedTables);
        if ($lostTablesCount > 0) {
            $errorCount++;
            $this->delegateLog($delegate, 'notice', 'Found ' . $lostTablesCount . ' indexes for not existing tables.');
            if (!$dryRun) {
                $this->persistenceContext->deleteLostTables($processedTables);
                $this->delegateLog($delegate, 'info', 'Removed indexes for not existing tables.');
            }
        }

        $this->callDelegateForEvent($delegate, 'operationHasEnded');

        return [$errorCount, $recordCount, $processedTables];
    }
protected function checkOrUpdateReferenceIndex($dryRun, ReferenceIndexIntegrityDelegateInterface $delegate = null)
    {
        $processedTables = [];
        $errorCount = 0;
        $recordCount = 0;

        $this->callDelegateForEvent($delegate, 'willStartOperation', [$this->persistenceContext->countAllRecordsOfAllTables()]);

        // Traverse all tables:
        foreach ($this->persistenceContext->getPersistenceConfiguration() as $tableName => $_) {
            // Traverse all records in tables, including deleted records:
            try {
                $records = $this->persistenceContext->getAllRecordsOfTable($tableName);
            } catch (TableDoesNotExistException $e) {
                $this->delegateLog($delegate, 'warning', $e->getMessage());
                continue;
            }
            if (!is_array($records) && !$records instanceof \Traversable) {
                $this->delegateLog($delegate, 'error', 'Table "%s" exists in $TCA but fetching records from database failed. Check the Database Analyzer in Install Tool for missing fields.', [$tableName]);
                continue;
            }
            $processedTables[] = $tableName;
            foreach ($records as $record) {
                $this->callDelegateForEvent($delegate, 'willUpdateRecord', [$tableName, $record]);

                /** @var $refIndexObj ReferenceIndex */
                $refIndexObj = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ReferenceIndex::class);
                if (isset($record['t3ver_wsid'])) {
                    $refIndexObj->setWorkspaceId($record['t3ver_wsid']);
                }
                $result = $refIndexObj->updateRefIndexTable($tableName, $record['uid'], $dryRun);
                $recordCount++;
                if ($result['addedNodes'] || $result['deletedNodes']) {
                    $errorMessage = 'Record ' . $tableName . ':' . $record['uid'];
                    if ($dryRun) {
                        $errorMessage .= ' has ' . $result['addedNodes'] . ' missing indexes and ' . $result['deletedNodes'] . ' stale indexes.';
                    } else {
                        $errorMessage .= ' ' . $result['addedNodes'] . ' indexes were added and ' . $result['deletedNodes'] . ' stale indexes were removed.';
                    }
                    $errorCount++;
                    $this->delegateLog($delegate, 'notice', $errorMessage);
                }
            }
            try {
                // Searching lost indexes for this table:
                $lostIndexCount = $this->persistenceContext->countLostIndexesOfRecordsInTable($tableName);
                if ($lostIndexCount > 0) {
                    $errorMessage = 'Table ' . $tableName . ' has ' . $lostIndexCount;
                    if ($dryRun) {
                        $errorMessage .= ' which need to be deleted.';
                    } else {
                        $errorMessage .= ' which have been deleted.';
                    }
                    $errorCount++;
                    $this->delegateLog($delegate, 'notice', $errorMessage);
                    if (!$dryRun) {
                        $this->persistenceContext->deleteLostIndexesOfRecordsInTable($tableName);
                    }
                }
            } catch (TableDoesNotExistException $e) {
                $this->delegateLog($delegate, 'warning', $e->getMessage());
                continue;
            }
        }

        // Searching lost indexes for non-existing tables:
        $lostTablesCount = $this->persistenceContext->countLostTables($processedTables);
        if ($lostTablesCount > 0) {
            $errorCount++;
            $this->delegateLog($delegate, 'notice', 'Found ' . $lostTablesCount . ' indexes for not existing tables.');
            if (!$dryRun) {
                $this->persistenceContext->deleteLostTables($processedTables);
                $this->delegateLog($delegate, 'info', 'Removed indexes for not existing tables.');
            }
        }

        $this->callDelegateForEvent($delegate, 'operationHasEnded');

        return [$errorCount, $recordCount, $processedTables];
    }
Updating or checking Reference Index

@param bool $dryRun
@param ReferenceIndexIntegrityDelegateInterface|null $delegate
@return array Tuple ($errorCount, $recordCount, $processedTables)