diff --git a/Classes/Widgets/DuplicateFilesWidget.php b/Classes/Widgets/DuplicateFilesWidget.php index 268613d..5568156 100644 --- a/Classes/Widgets/DuplicateFilesWidget.php +++ b/Classes/Widgets/DuplicateFilesWidget.php @@ -1,83 +1,130 @@ options = array_merge([ + 'showThumbnails' => true, + 'thumbnailWidth' => '200m', + 'thumbnailHeight' => '70m', + 'duplicateLimit' => 200, + ], $options); } - public function renderWidgetContent(): string + { + $duplicates = $this->getDuplicates($this->getFileUidsFromSha1($this->getDuplicatedSha1())); + $view = $this->backendViewFactory->create($this->request, ['sitegeist/editor-widgets']); + $view->assignMultiple([ + 'duplicates' => $duplicates, + 'options' => $this->options, + 'configuration' => $this->configuration, + ]); + return $view->render('DuplicateFilesWidget'); + } + public function getDuplicatedSha1(): array { $queryBuilder = $this->connectionPool->getConnectionForTable('sys_file')->createQueryBuilder(); - $queryBuilder->getRestrictions()->removeAll(); - - $duplicates = $queryBuilder - ->selectLiteral('GROUP_CONCAT(uid) as uids', 'sha1', 'count(*) as counting') + return $queryBuilder + ->select('sha1') ->from('sys_file') - ->where('missing = 0') - ->andWhere('storage > 0') - ->andWhere('name != "index.html"') - ->andWhere('identifier NOT LIKE "%_recycler_%"') - ->orderBy('counting', 'desc') - ->addOrderBy('size', 'desc') - ->groupBy('sha1') - ->having('counting > 1') - ->setMaxResults(200) + ->where( + $queryBuilder->expr()->eq('missing', $queryBuilder->createNamedParameter(0, Connection::PARAM_INT)), + $queryBuilder->expr()->gt('storage', $queryBuilder->createNamedParameter(0, Connection::PARAM_INT)), + $queryBuilder->expr()->neq('name', $queryBuilder->createNamedParameter('index.html')), + $queryBuilder->expr()->notLike('identifier', $queryBuilder->quote('%_recycler_%')), + ) + ->groupBy('sha1', 'size') + ->having('COUNT(*) > 1') + ->setMaxResults((int)$this->options['duplicateLimit']) ->executeQuery() - ->fetchAllAssociative(); - - foreach ($duplicates as &$duplicate) { - $duplicate['files'] = array_map( + ->fetchFirstColumn(); + } + public function getFileUidsFromSha1(array $duplicatedSha1): array + { + $queryBuilder = $this->connectionPool->getConnectionForTable('sys_file')->createQueryBuilder(); + $uids = []; + foreach ($duplicatedSha1 as $sha1) { + $uids[] = $queryBuilder + ->select('uid') + ->from('sys_file') + ->where( + $queryBuilder->expr()->eq('sha1', $queryBuilder->createNamedParameter($sha1, Connection::PARAM_STR)) + ) + ->executeQuery() + ->fetchFirstColumn(); + } + return $uids; + } + private function getDuplicates(array $fileUidGroups): array + { + $duplicates = []; + foreach ($fileUidGroups as $fileUidList) { + $duplicates[] = array_filter(array_map( function ($uid) { - $file = $this->resourceFactory->getFileObject($uid); - try { + $file = $this->resourceFactory->getFileObject((int)$uid); + if (!$file->exists() || $file->isMissing()) { + return null; + } $file->getParentFolder(); - } catch (\Throwable $th) { - $file->setMissing(1); + } catch (FileDoesNotExistException | InsufficientFolderAccessPermissionsException | \Exception) { + return null; } - return [ 'file' => $file, 'referenceCount' => BackendUtility::referenceCount('sys_file', $file->getUid()), - 'isImage' => $file->isImage(), ]; }, - GeneralUtility::trimExplode(',', $duplicate['uids']) - ); + $fileUidList + )); } - - $view = $this->backendViewFactory->create($this->request, ['sitegeist/editor-widgets']); - $view->assignMultiple([ - 'duplicates' => $duplicates, - 'configuration' => $this->configuration, - ]); - - return $view->render('DuplicateFilesWidget'); + return array_filter($duplicates, static function ($files) { return count($files) >= 2; }); + } + public function getOptions(): array + { + return $this->options; + } + public function setRequest(ServerRequestInterface $request): void + { + $this->request = $request; } - public function getCssFiles(): array { return [ diff --git a/Resources/Private/Language/locallang.xlf b/Resources/Private/Language/locallang.xlf index e9a2567..f3aec2d 100644 --- a/Resources/Private/Language/locallang.xlf +++ b/Resources/Private/Language/locallang.xlf @@ -25,27 +25,25 @@ No unused files found - + Duplicate files - - Displays all files that are duplicates + + Displays files that exists multiple times - - Open original file in new window + + No duplicate files found - + + File + + Control - + References - - Search in folder - - - No duplicates found - + Last changed pages diff --git a/Resources/Private/Templates/DuplicateFilesWidget.html b/Resources/Private/Templates/DuplicateFilesWidget.html index 7f2a7aa..67bc7dd 100644 --- a/Resources/Private/Templates/DuplicateFilesWidget.html +++ b/Resources/Private/Templates/DuplicateFilesWidget.html @@ -1,100 +1,79 @@ - + - + - - - - + + - - - - - - - - - - - {duplicate.file.identifier} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {duplicate.referenceCount} - - - - - - + + + + + + + + + + {duplicate.file.storage.storageRecord.name}: {duplicate.file.identifier} + : {duplicate.referenceCount} + + + + + + + + + + + + + + + + - - - + + + + + + + - + - diff --git a/Resources/Public/Css/backend.css b/Resources/Public/Css/backend.css index c8d62f7..fa96335 100644 --- a/Resources/Public/Css/backend.css +++ b/Resources/Public/Css/backend.css @@ -19,3 +19,5 @@ } } } + +.widget-table-group-striped>tbody>tr.group-even>*{--typo3-table-bg-type:color-mix(in srgb, var(--typo3-table-bg), var(--typo3-table-color) 3%)}
- +