/**
* Clean up resource registry
*
* This command checks the resource registry (that is the database tables) for orphaned resource objects which don't
* seem to have any corresponding data anymore (for example: the file in Data/Persistent/Resources has been deleted
* without removing the related PersistentResource object).
*
* If the Neos.Media package is active, this command will also detect any assets referring to broken resources
* and will remove the respective Asset object from the database when the broken resource is removed.
*
* This command will ask you interactively what to do before deleting anything.
*
* @return void
*/
public function cleanCommand()
{
$this->outputLine('Checking if resource data exists for all known resource objects ...');
$this->outputLine();
$mediaPackagePresent = $this->packageManager->isPackageActive('Neos.Media');
$resourcesCount = $this->resourceRepository->countAll();
$this->output->progressStart($resourcesCount);
$brokenResources = [];
$relatedAssets = new \SplObjectStorage();
$relatedThumbnails = new \SplObjectStorage();
$iterator = $this->resourceRepository->findAllIterator();
foreach ($this->resourceRepository->iterate($iterator, function ($iteration) {
$this->clearState($iteration);
}) as $resource) {
$this->output->progressAdvance(1);
/* @var PersistentResource $resource */
$stream = $resource->getStream();
if (!is_resource($stream)) {
$brokenResources[] = $resource->getSha1();
}
}
$this->output->progressFinish();
$this->outputLine();
if ($mediaPackagePresent && count($brokenResources) > 0) {
/* @var AssetRepository $assetRepository */
$assetRepository = $this->objectManager->get(AssetRepository::class);
/* @var ThumbnailRepository $thumbnailRepository */
$thumbnailRepository = $this->objectManager->get(ThumbnailRepository::class);
foreach ($brokenResources as $key => $resourceSha1) {
$resource = $this->resourceRepository->findOneBySha1($resourceSha1);
$brokenResources[$key] = $resource;
$assets = $assetRepository->findByResource($resource);
if ($assets !== null) {
$relatedAssets[$resource] = $assets;
}
$thumbnails = $thumbnailRepository->findByResource($resource);
if ($assets !== null) {
$relatedThumbnails[$resource] = $thumbnails;
}
}
}
if (count($brokenResources) > 0) {
$this->outputLine('<b>Found %s broken resource(s):</b>', [count($brokenResources)]);
$this->outputLine();
foreach ($brokenResources as $resource) {
$this->outputLine('%s (%s) from "%s" collection', [$resource->getFilename(), $resource->getSha1(), $resource->getCollectionName()]);
if (isset($relatedAssets[$resource])) {
foreach ($relatedAssets[$resource] as $asset) {
$this->outputLine(' -> %s (%s)', [get_class($asset), $asset->getIdentifier()]);
}
}
}
$response = null;
while (!in_array($response, ['y', 'n', 'c'])) {
$response = $this->output->ask('<comment>Do you want to remove all broken resource objects and related assets from the database? (y/n/c) </comment>');
}
switch ($response) {
case 'y':
$brokenAssetCounter = 0;
$brokenThumbnailCounter = 0;
foreach ($brokenResources as $sha1 => $resource) {
$this->outputLine('- delete %s (%s) from "%s" collection', [$resource->getFilename(), $resource->getSha1(), $resource->getCollectionName()]);
$resource->disableLifecycleEvents();
$this->resourceRepository->remove($resource);
if (isset($relatedAssets[$resource])) {
foreach ($relatedAssets[$resource] as $asset) {
$assetRepository->remove($asset);
$brokenAssetCounter++;
}
}
if (isset($relatedThumbnails[$resource])) {
foreach ($relatedThumbnails[$resource] as $thumbnail) {
$thumbnailRepository->remove($thumbnail);
$brokenThumbnailCounter++;
}
}
$this->persistenceManager->persistAll();
}
$brokenResourcesCounter = count($brokenResources);
if ($brokenResourcesCounter > 0) {
$this->outputLine('Removed %s resource object(s) from the database.', [$brokenResourcesCounter]);
}
if ($brokenAssetCounter > 0) {
$this->outputLine('Removed %s asset object(s) from the database.', [$brokenAssetCounter]);
}
if ($brokenThumbnailCounter > 0) {
$this->outputLine('Removed %s thumbnail object(s) from the database.', [$brokenThumbnailCounter]);
}
break;
case 'n':
$this->outputLine('Did not delete any resource objects.');
break;
case 'c':
$this->outputLine('Stopping. Did not delete any resource objects.');
$this->quit(0);
break;
}
}
}