$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'];
}
}