Loading modules/tome_sync/src/CleanFilesTrait.php 0 → 100644 +54 −0 Original line number Diff line number Diff line <?php namespace Drupal\tome_sync; use Drupal\Core\StreamWrapper\StreamWrapperManager; /** * Contains shared methods for cleaning files. */ trait CleanFilesTrait { /** * Assembles a list of files that are unused. * * @return array * An associative array mapping file UUIDs to their URIs. */ protected function getUnusedFiles() { $files = []; $names = $this->contentStorage->listAll('file.'); foreach ($names as $name) { $data = $this->contentStorage->read($name); list(, $uuid) = TomeSyncHelper::getPartsFromContentName($name); $files[$uuid] = StreamWrapperManager::getTarget($data['uri'][0]['value']); } $callback = function ($value) use (&$files) { if (is_string($value)) { foreach ($files as $uuid => $filename) { if (strpos($value, $uuid) !== FALSE || strpos($value, $filename) !== FALSE) { unset($files[$uuid]); } } } }; $names = array_diff($this->contentStorage->listAll(), $names); foreach ($names as $name) { if (!$files) { break; } $data = $this->contentStorage->read($name); array_walk_recursive($data, $callback); } $names = $this->configStorage->listAll(); foreach ($names as $name) { if (!$files) { break; } $data = $this->configStorage->read($name); array_walk_recursive($data, $callback); } return $files; } } modules/tome_sync/src/Commands/CleanFilesCommand.php +7 −45 Original line number Diff line number Diff line Loading @@ -4,13 +4,13 @@ namespace Drupal\tome_sync\Commands; use Drupal\tome_base\PathTrait; use Drupal\tome_base\CommandBase; use Drupal\tome_sync\TomeSyncHelper; use Drupal\tome_sync\FileSyncInterface; use Drupal\Core\Config\StorageInterface; use Drupal\Core\File\FileSystemInterface; use Drupal\tome_sync\CleanFilesTrait; use Drupal\tome_sync\ContentIndexerTrait; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Drupal\Core\StreamWrapper\StreamWrapperManager; /** * Contains the tome:clean-files command. Loading @@ -21,6 +21,7 @@ class CleanFilesCommand extends CommandBase { use PathTrait; use ContentIndexerTrait; use CleanFilesTrait; /** * The target content storage. Loading Loading @@ -59,12 +60,15 @@ class CleanFilesCommand extends CommandBase { * The target config storage. * @param \Drupal\tome_sync\FileSyncInterface $file_sync * The file sync service. * @param \Drupal\Core\File\FileSystemInterface $file_system * The file system. */ public function __construct(StorageInterface $content_storage, StorageInterface $config_storage, FileSyncInterface $file_sync) { public function __construct(StorageInterface $content_storage, StorageInterface $config_storage, FileSyncInterface $file_sync, FileSystemInterface $file_system) { parent::__construct(); $this->contentStorage = $content_storage; $this->configStorage = $config_storage; $this->fileSync = $file_sync; $this->fileSystem = $file_system; } /** Loading Loading @@ -97,46 +101,4 @@ class CleanFilesCommand extends CommandBase { $this->io()->success('Deleted all unused files.'); } /** * Assembles a list of files that should be unused. * * @return array * An associative array mapping file UUIDs to their URIs. */ protected function getUnusedFiles() { $files = []; $names = $this->contentStorage->listAll('file.'); foreach ($names as $name) { $data = $this->contentStorage->read($name); list(, $uuid) = TomeSyncHelper::getPartsFromContentName($name); $files[$uuid] = StreamWrapperManager::getTarget($data['uri'][0]['value']); } $callback = function ($value) use (&$files) { if (is_string($value)) { foreach ($files as $uuid => $filename) { if (strpos($value, $uuid) !== FALSE || strpos($value, $filename) !== FALSE) { unset($files[$uuid]); } } } }; $names = array_diff($this->contentStorage->listAll(), $names); foreach ($names as $name) { if (!$files) { break; } $data = $this->contentStorage->read($name); array_walk_recursive($data, $callback); } $names = $this->configStorage->listAll(); foreach ($names as $name) { if (!$files) { break; } $data = $this->configStorage->read($name); array_walk_recursive($data, $callback); } return $files; } } modules/tome_sync/src/Form/CleanFilesForm.php 0 → 100644 +148 −0 Original line number Diff line number Diff line <?php namespace Drupal\tome_sync\Form; use Drupal\Core\Config\StorageInterface; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\Core\File\FileSystemInterface; use Drupal\tome_base\PathTrait; use Drupal\tome_sync\CleanFilesTrait; use Drupal\tome_sync\ContentIndexerTrait; use Drupal\tome_sync\FileSyncInterface; /** * Contains a form for deleting unused files. * * @internal */ class CleanFilesForm extends FormBase { use PathTrait; use ContentIndexerTrait; use CleanFilesTrait; /** * The target content storage. * * @var \Drupal\Core\Config\StorageInterface */ protected $contentStorage; /** * The config storage. * * @var \Drupal\Core\Config\StorageInterface */ protected $configStorage; /** * The file system. * * @var \Drupal\Core\File\FileSystemInterface */ protected $fileSystem; /** * The file sync service. * * @var \Drupal\tome_sync\FileSyncInterface */ protected $fileSync; /** * Creates a CleanFilesForm object. * * @param \Drupal\Core\Config\StorageInterface $content_storage * The target content storage. * @param \Drupal\Core\Config\StorageInterface $config_storage * The target config storage. * @param \Drupal\tome_sync\FileSyncInterface $file_sync * The file sync service. * @param \Drupal\Core\File\FileSystemInterface $file_system * The file system. */ public function __construct(StorageInterface $content_storage, StorageInterface $config_storage, FileSyncInterface $file_sync, FileSystemInterface $file_system) { $this->contentStorage = $content_storage; $this->configStorage = $config_storage; $this->fileSync = $file_sync; $this->fileSystem = $file_system; } /** * {@inheritdoc} */ public static function create(ContainerInterface $container) { return new static( $container->get('tome_sync.storage.content'), $container->get('config.storage.sync'), $container->get('tome_sync.file_sync'), $container->get('file_system'), ); } /** * {@inheritdoc} */ public function getFormId() { return 'tome_sync_clean_files_form'; } /** * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state) { $files = $this->getUnusedFiles(); if (empty($files)) { \Drupal::messenger()->addStatus('No unused files found!'); return $form; } $form['warning'] = [ '#theme' => 'status_messages', '#message_list' => [ 'warning' => [t('The files below appear to be unused and will be deleted. This operation is permanent.')], ], '#status_headings' => ['warning' => t('Review list below before proceeding')], ]; $form['file_list'] = [ '#type' => 'html_tag', '#tag' => 'ul', ]; asort($files); foreach ($files as $uuid => $filename) { $form['file_list'][] = [ '#type' => 'html_tag', '#tag' => 'li', '#value' => "$filename ($uuid)", ]; } $form['actions'] = [ '#type' => 'actions', ]; $form['actions']['submit'] = [ '#type' => 'submit', '#value' => t('Delete @count files above', ['@count' => count($files)]), ]; return $form; } /** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { $files = $this->getUnusedFiles(); foreach ($files as $uuid => $filename) { $this->contentStorage->delete("file.$uuid"); $this->unIndexContentByName("file.$uuid"); $this->fileSync->deleteFile($filename); } \Drupal::messenger()->addMessage('All unused files have been deleted.'); } } modules/tome_sync/tome_sync.links.menu.yml +7 −0 Original line number Diff line number Diff line Loading @@ -9,3 +9,10 @@ tome_sync.import_partial: description: 'Updates or deletes content and files based on what has changed in the export.' route_name: tome_sync.import_partial weight: 0 tome_sync.clean_files: title: 'Remove unused files' parent: tome_sync.main description: 'Finds files not referenced in config or content exports and deletes them.' route_name: tome_sync.clean_files weight: 1 modules/tome_sync/tome_sync.routing.yml +8 −0 Original line number Diff line number Diff line Loading @@ -13,3 +13,11 @@ tome_sync.import_partial: _title: 'Synchronize content and files' requirements: _permission: 'use tome sync' tome_sync.clean_files: path: '/admin/config/tome/sync/clean-files' defaults: _form: 'Drupal\tome_sync\Form\CleanFilesForm' _title: 'Remove unused files' requirements: _permission: 'use tome sync' Loading
modules/tome_sync/src/CleanFilesTrait.php 0 → 100644 +54 −0 Original line number Diff line number Diff line <?php namespace Drupal\tome_sync; use Drupal\Core\StreamWrapper\StreamWrapperManager; /** * Contains shared methods for cleaning files. */ trait CleanFilesTrait { /** * Assembles a list of files that are unused. * * @return array * An associative array mapping file UUIDs to their URIs. */ protected function getUnusedFiles() { $files = []; $names = $this->contentStorage->listAll('file.'); foreach ($names as $name) { $data = $this->contentStorage->read($name); list(, $uuid) = TomeSyncHelper::getPartsFromContentName($name); $files[$uuid] = StreamWrapperManager::getTarget($data['uri'][0]['value']); } $callback = function ($value) use (&$files) { if (is_string($value)) { foreach ($files as $uuid => $filename) { if (strpos($value, $uuid) !== FALSE || strpos($value, $filename) !== FALSE) { unset($files[$uuid]); } } } }; $names = array_diff($this->contentStorage->listAll(), $names); foreach ($names as $name) { if (!$files) { break; } $data = $this->contentStorage->read($name); array_walk_recursive($data, $callback); } $names = $this->configStorage->listAll(); foreach ($names as $name) { if (!$files) { break; } $data = $this->configStorage->read($name); array_walk_recursive($data, $callback); } return $files; } }
modules/tome_sync/src/Commands/CleanFilesCommand.php +7 −45 Original line number Diff line number Diff line Loading @@ -4,13 +4,13 @@ namespace Drupal\tome_sync\Commands; use Drupal\tome_base\PathTrait; use Drupal\tome_base\CommandBase; use Drupal\tome_sync\TomeSyncHelper; use Drupal\tome_sync\FileSyncInterface; use Drupal\Core\Config\StorageInterface; use Drupal\Core\File\FileSystemInterface; use Drupal\tome_sync\CleanFilesTrait; use Drupal\tome_sync\ContentIndexerTrait; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Drupal\Core\StreamWrapper\StreamWrapperManager; /** * Contains the tome:clean-files command. Loading @@ -21,6 +21,7 @@ class CleanFilesCommand extends CommandBase { use PathTrait; use ContentIndexerTrait; use CleanFilesTrait; /** * The target content storage. Loading Loading @@ -59,12 +60,15 @@ class CleanFilesCommand extends CommandBase { * The target config storage. * @param \Drupal\tome_sync\FileSyncInterface $file_sync * The file sync service. * @param \Drupal\Core\File\FileSystemInterface $file_system * The file system. */ public function __construct(StorageInterface $content_storage, StorageInterface $config_storage, FileSyncInterface $file_sync) { public function __construct(StorageInterface $content_storage, StorageInterface $config_storage, FileSyncInterface $file_sync, FileSystemInterface $file_system) { parent::__construct(); $this->contentStorage = $content_storage; $this->configStorage = $config_storage; $this->fileSync = $file_sync; $this->fileSystem = $file_system; } /** Loading Loading @@ -97,46 +101,4 @@ class CleanFilesCommand extends CommandBase { $this->io()->success('Deleted all unused files.'); } /** * Assembles a list of files that should be unused. * * @return array * An associative array mapping file UUIDs to their URIs. */ protected function getUnusedFiles() { $files = []; $names = $this->contentStorage->listAll('file.'); foreach ($names as $name) { $data = $this->contentStorage->read($name); list(, $uuid) = TomeSyncHelper::getPartsFromContentName($name); $files[$uuid] = StreamWrapperManager::getTarget($data['uri'][0]['value']); } $callback = function ($value) use (&$files) { if (is_string($value)) { foreach ($files as $uuid => $filename) { if (strpos($value, $uuid) !== FALSE || strpos($value, $filename) !== FALSE) { unset($files[$uuid]); } } } }; $names = array_diff($this->contentStorage->listAll(), $names); foreach ($names as $name) { if (!$files) { break; } $data = $this->contentStorage->read($name); array_walk_recursive($data, $callback); } $names = $this->configStorage->listAll(); foreach ($names as $name) { if (!$files) { break; } $data = $this->configStorage->read($name); array_walk_recursive($data, $callback); } return $files; } }
modules/tome_sync/src/Form/CleanFilesForm.php 0 → 100644 +148 −0 Original line number Diff line number Diff line <?php namespace Drupal\tome_sync\Form; use Drupal\Core\Config\StorageInterface; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\Core\File\FileSystemInterface; use Drupal\tome_base\PathTrait; use Drupal\tome_sync\CleanFilesTrait; use Drupal\tome_sync\ContentIndexerTrait; use Drupal\tome_sync\FileSyncInterface; /** * Contains a form for deleting unused files. * * @internal */ class CleanFilesForm extends FormBase { use PathTrait; use ContentIndexerTrait; use CleanFilesTrait; /** * The target content storage. * * @var \Drupal\Core\Config\StorageInterface */ protected $contentStorage; /** * The config storage. * * @var \Drupal\Core\Config\StorageInterface */ protected $configStorage; /** * The file system. * * @var \Drupal\Core\File\FileSystemInterface */ protected $fileSystem; /** * The file sync service. * * @var \Drupal\tome_sync\FileSyncInterface */ protected $fileSync; /** * Creates a CleanFilesForm object. * * @param \Drupal\Core\Config\StorageInterface $content_storage * The target content storage. * @param \Drupal\Core\Config\StorageInterface $config_storage * The target config storage. * @param \Drupal\tome_sync\FileSyncInterface $file_sync * The file sync service. * @param \Drupal\Core\File\FileSystemInterface $file_system * The file system. */ public function __construct(StorageInterface $content_storage, StorageInterface $config_storage, FileSyncInterface $file_sync, FileSystemInterface $file_system) { $this->contentStorage = $content_storage; $this->configStorage = $config_storage; $this->fileSync = $file_sync; $this->fileSystem = $file_system; } /** * {@inheritdoc} */ public static function create(ContainerInterface $container) { return new static( $container->get('tome_sync.storage.content'), $container->get('config.storage.sync'), $container->get('tome_sync.file_sync'), $container->get('file_system'), ); } /** * {@inheritdoc} */ public function getFormId() { return 'tome_sync_clean_files_form'; } /** * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state) { $files = $this->getUnusedFiles(); if (empty($files)) { \Drupal::messenger()->addStatus('No unused files found!'); return $form; } $form['warning'] = [ '#theme' => 'status_messages', '#message_list' => [ 'warning' => [t('The files below appear to be unused and will be deleted. This operation is permanent.')], ], '#status_headings' => ['warning' => t('Review list below before proceeding')], ]; $form['file_list'] = [ '#type' => 'html_tag', '#tag' => 'ul', ]; asort($files); foreach ($files as $uuid => $filename) { $form['file_list'][] = [ '#type' => 'html_tag', '#tag' => 'li', '#value' => "$filename ($uuid)", ]; } $form['actions'] = [ '#type' => 'actions', ]; $form['actions']['submit'] = [ '#type' => 'submit', '#value' => t('Delete @count files above', ['@count' => count($files)]), ]; return $form; } /** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { $files = $this->getUnusedFiles(); foreach ($files as $uuid => $filename) { $this->contentStorage->delete("file.$uuid"); $this->unIndexContentByName("file.$uuid"); $this->fileSync->deleteFile($filename); } \Drupal::messenger()->addMessage('All unused files have been deleted.'); } }
modules/tome_sync/tome_sync.links.menu.yml +7 −0 Original line number Diff line number Diff line Loading @@ -9,3 +9,10 @@ tome_sync.import_partial: description: 'Updates or deletes content and files based on what has changed in the export.' route_name: tome_sync.import_partial weight: 0 tome_sync.clean_files: title: 'Remove unused files' parent: tome_sync.main description: 'Finds files not referenced in config or content exports and deletes them.' route_name: tome_sync.clean_files weight: 1
modules/tome_sync/tome_sync.routing.yml +8 −0 Original line number Diff line number Diff line Loading @@ -13,3 +13,11 @@ tome_sync.import_partial: _title: 'Synchronize content and files' requirements: _permission: 'use tome sync' tome_sync.clean_files: path: '/admin/config/tome/sync/clean-files' defaults: _form: 'Drupal\tome_sync\Form\CleanFilesForm' _title: 'Remove unused files' requirements: _permission: 'use tome sync'