$this->getMissingFilesStatus(), 'ConsistencyCheck' => $this->getConsistencyCheckStatus(), ]; } public function getDetailedStatus(): array { return [ 'ConsistencyCheck' => $this->getConsistencyCheckStatus(), ]; } public function getLabel(): string { return 'fal'; } /** * Checks if there are files marked as missed. * * @return \TYPO3\CMS\Reports\Status An object representing whether there are files marked as missed or not */ protected function getMissingFilesStatus() { $value = $this->getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_none'); $count = 0; $maxFilesToShow = 100; $message = ''; $severity = ContextualFeedbackSeverity::OK; $storages = $this->getBrowsableStorages(); if (!empty($storages)) { $queryBuilder = $this->connectionPool->getQueryBuilderForTable('sys_file'); $count = $queryBuilder ->count('*') ->from('sys_file') ->where( $queryBuilder->expr()->eq( 'missing', $queryBuilder->createNamedParameter(1, Connection::PARAM_INT) ), $queryBuilder->expr()->in( 'storage', $queryBuilder->createNamedParameter(array_keys($storages), Connection::PARAM_INT_ARRAY) ) ) ->executeQuery() ->fetchOne(); } if ($count) { $value = sprintf($this->getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_missingFilesCount'), $count); $severity = ContextualFeedbackSeverity::WARNING; $queryBuilder = $this->connectionPool->getQueryBuilderForTable('sys_file'); $files = $queryBuilder ->select('identifier', 'storage') ->from('sys_file') ->where( $queryBuilder->expr()->eq( 'missing', $queryBuilder->createNamedParameter(1, Connection::PARAM_INT) ), $queryBuilder->expr()->in( 'storage', $queryBuilder->createNamedParameter(array_keys($storages), Connection::PARAM_INT_ARRAY) ) ) ->setMaxResults($maxFilesToShow) ->executeQuery() ->fetchAllAssociative(); $message = '

' . $this->getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_missingFilesMessage') . '

'; foreach ($files as $file) { $message .= $storages[$file['storage']]->getName() . ' ' . $file['identifier'] . '
'; } if ($count > $maxFilesToShow) { $message .= '...
'; } } return new ReportStatus($this->getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_missingFiles'), $value, $message, $severity); } protected function getConsistencyCheckStatus(): ReportStatus { // @todo for performance reasons, consider using this only in CLI context as `ExtendedStatusProviderInterface` $storages = $this->getBrowsableStorages(); $inconsistenciesMessage = ''; foreach ($storages as $storage) { $inconsistencies = $this->checkFolderConsistency($storage->getRootLevelFolder()); if ($inconsistencies !== []) { $inconsistenciesMessage .= sprintf( '
%s
%s', htmlspecialchars(sprintf( 'Storage "%s" (id:%d)', $storage->getName(), $storage->getUid() )), $this->wrapInHtmlUnorderedList($inconsistencies) ); } } if ($inconsistenciesMessage === '') { return new ReportStatus( 'Consistency check', 'No inconsistencies found in these storages', // make sure we have a list of strings (0… index) with `array_values` to ensure correct rendering $this->wrapInHtmlUnorderedList(array_values(array_map( static fn(ResourceStorage $storage): string => sprintf( '%s (id: %d)', $storage->getName(), $storage->getUid() ), $storages, ))), ContextualFeedbackSeverity::OK, ); } return new ReportStatus( 'Consistency Status', 'Inconsistent files have been found', $inconsistenciesMessage, ContextualFeedbackSeverity::ERROR, ); } private function checkFolderConsistency(FolderInterface $folder): array { $inconsistencies = []; foreach ($folder->getFiles() as $file) { if (!$file instanceof File) { continue; } try { $this->resourceConsistencyService->validate($file->getStorage(), $file); } catch (ResultException $exception) { $inconsistencies[$file->getCombinedIdentifier()] = $this->compileResultMessages( $exception->messages, $this->getLanguageService() ); } } foreach ($folder->getSubfolders() as $subFolder) { $inconsistencies = [...$inconsistencies, ...$this->checkFolderConsistency($subFolder)]; } return $inconsistencies; } /** * @param list|array> $items */ protected function wrapInHtmlUnorderedList(array $items): string { if (array_is_list($items)) { return sprintf( '', implode('', array_map( static fn(string $item): string => '
  • ' . htmlspecialchars($item) . '
  • ', $items )) ); } return sprintf( '', implode('', array_map( fn(string $key, array $values): string => sprintf( '
  • %s%s
  • ', htmlspecialchars($key), $this->wrapInHtmlUnorderedList($values) ), array_keys($items), array_values($items) )) ); } /** * Filter available storages that are actually browsable * * @return array */ protected function getBrowsableStorages(): array { $storages = []; foreach ($this->storageRepository->findAll() as $storageObject) { if ($storageObject->isBrowsable()) { $storages[$storageObject->getUid()] = $storageObject; } } return $storages; } protected function getLanguageService(): LanguageService { return $GLOBALS['LANG']; } }