diff --git a/auditfiles.services.yml b/auditfiles.services.yml index a86c2987639dad0969b838a90508aa888a7a25a8..149ee730c121ad31348ef0b249bbfd3e31ca96e4 100644 --- a/auditfiles.services.yml +++ b/auditfiles.services.yml @@ -11,6 +11,9 @@ services: class: Drupal\auditfiles\Services\AuditFilesExclusions Drupal\auditfiles\Services\AuditFilesExclusions: '@auditfiles.exclusions' + auditfiles.export: + class: Drupal\auditfiles\Services\AuditFilesExport + Drupal\auditfiles\AuditFilesListener: arguments: $fileMimeTypeGuesser: '@file.mime_type.guesser' diff --git a/composer.json b/composer.json index 6a56a2d2e73b3b8aa3b563fc680eb1010044bba5..85556abc69586b314d66064ba3a0eb59573575a4 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,8 @@ "minimum-stability": "dev", "require": { "php": ">=8.1", - "drupal/core": "^10.3 || ^11" + "drupal/core": "^10.3 || ^11", + "league/csv": "^9.2" }, "require-dev": { "composer/installers": "^2", diff --git a/src/Form/AuditFilesManagedNotUsedForm.php b/src/Form/AuditFilesManagedNotUsedForm.php index 4863e25c13de90fd2d66efca737e9012bdfb43af..c6d5f046838bcd8a5283b7750304b0bdeb11a65b 100644 --- a/src/Form/AuditFilesManagedNotUsedForm.php +++ b/src/Form/AuditFilesManagedNotUsedForm.php @@ -8,6 +8,7 @@ use Drupal\auditfiles\Auditor\AuditFilesManagedNotUsed; use Drupal\auditfiles\Batch\AuditFilesDeleteFileEntityBatchProcess; use Drupal\auditfiles\Reference\FileEntityReference; use Drupal\auditfiles\Services\AuditFilesConfigInterface; +use Drupal\auditfiles\Services\AuditFilesExport; use Drupal\Core\Batch\BatchBuilder; use Drupal\Core\Datetime\DateFormatterInterface; use Drupal\Core\File\FileSystemInterface; @@ -47,6 +48,7 @@ final class AuditFilesManagedNotUsedForm extends FormBase implements AuditFilesA protected DateFormatterInterface $dateFormatter, protected FileSystemInterface $fileSystem, protected FileUrlGeneratorInterface $fileUrlGenerator, + protected AuditFilesExport $export, ) { } @@ -58,6 +60,7 @@ final class AuditFilesManagedNotUsedForm extends FormBase implements AuditFilesA $container->get('date.formatter'), $container->get('file_system'), $container->get('file_url_generator'), + $container->get('auditfiles.export'), ); } @@ -174,6 +177,33 @@ final class AuditFilesManagedNotUsedForm extends FormBase implements AuditFilesA } $form['actions'] = ['#type' => 'actions']; + + // Write all data to the CSV file. + $header = [ + $this->t('File ID'), + $this->t('User ID'), + $this->t('Name'), + $this->t('URI'), + $this->t('Path'), + $this->t('MIME'), + $this->t('Size'), + $this->t('When added'), + $this->t('Status'), + ]; + $data = $rows; + foreach ($data as &$row) { + $row['uri'] = $row['uri']->toString(); + } + $this->export->write($header, $data); + + $form['actions']['export'] = [ + '#type' => 'submit', + '#value' => $this->t('Export all results'), + '#submit' => [ + $this->export(...), + ], + ]; + $form['actions']['submit'] = [ '#type' => 'submit', '#value' => $this->t('Delete selected items from the file_managed table'), @@ -201,6 +231,13 @@ final class AuditFilesManagedNotUsedForm extends FormBase implements AuditFilesA } } + /** + * Submit for downloading data. + */ + public function export(array &$form, FormStateInterface $form_state): void { + $this->export->download('Managed not used'); + } + /** * Delete record from files. */ diff --git a/src/Form/AuditFilesMergeFileReferencesForm.php b/src/Form/AuditFilesMergeFileReferencesForm.php index 62302638a549d0cf786847a7cb0b281ff735a230..b61c5d4ff0989a184ad8a5db1f717eef908a590c 100644 --- a/src/Form/AuditFilesMergeFileReferencesForm.php +++ b/src/Form/AuditFilesMergeFileReferencesForm.php @@ -8,12 +8,14 @@ use Drupal\auditfiles\Auditor\AuditFilesMergeFileReferences; use Drupal\auditfiles\Batch\AuditFilesMergeFileReferencesBatchProcess; use Drupal\auditfiles\Reference\FileEntityReference; use Drupal\auditfiles\Services\AuditFilesConfigInterface; +use Drupal\auditfiles\Services\AuditFilesExport; use Drupal\Core\Batch\BatchBuilder; use Drupal\Core\Datetime\DateFormatterInterface; use Drupal\Core\Form\ConfirmFormHelper; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Pager\PagerManagerInterface; +use Drupal\Core\Render\RendererInterface; use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\Core\Url; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -42,6 +44,8 @@ final class AuditFilesMergeFileReferencesForm extends FormBase implements AuditF protected PagerManagerInterface $pagerManager, protected AuditFilesMergeFileReferences $mergeFileReferences, protected DateFormatterInterface $dateFormatter, + protected AuditFilesExport $export, + protected RendererInterface $renderer, ) { } @@ -51,6 +55,8 @@ final class AuditFilesMergeFileReferencesForm extends FormBase implements AuditF $container->get('pager.manager'), $container->get('auditfiles.auditor.merge_file_references'), $container->get('date.formatter'), + $container->get('auditfiles.export'), + $container->get('renderer'), ); } @@ -189,6 +195,27 @@ final class AuditFilesMergeFileReferencesForm extends FormBase implements AuditF } $form['actions'] = ['#type' => 'actions']; + + // Write all data to the CSV file. + $header = [$this->t('Name'), $this->t('File IDs using the filename')]; + $data = $rows; + foreach ($data as &$row) { + $items = !empty($row['references']['data']['#items']) ? $row['references']['data']['#items'] : []; + foreach ($items as $key => $item) { + $items[$key] = $this->renderer->render($item)->__toString(); + } + $row['references'] = implode(PHP_EOL, $items); + } + $this->export->write($header, $data); + + $form['actions']['export'] = [ + '#type' => 'submit', + '#value' => $this->t('Export all results'), + '#submit' => [ + $this->export(...), + ], + ]; + $form['actions']['submit'] = [ '#type' => 'submit', '#value' => $this->t('Merge selected items'), @@ -216,6 +243,13 @@ final class AuditFilesMergeFileReferencesForm extends FormBase implements AuditF } } + /** + * Submit for downloading data. + */ + public function export(array &$form, FormStateInterface $form_state): void { + $this->export->download('Merge file references'); + } + /** * Submit form handler for Merge Records. */ diff --git a/src/Form/AuditFilesNotInDatabaseForm.php b/src/Form/AuditFilesNotInDatabaseForm.php index 9f672134ed43f4c6420147a230800ff3627fab19..6f47bf0ecb9eeb2c019c365ef24cfd2b727035d2 100644 --- a/src/Form/AuditFilesNotInDatabaseForm.php +++ b/src/Form/AuditFilesNotInDatabaseForm.php @@ -8,6 +8,7 @@ use Drupal\auditfiles\AuditFilesAuditorInterface; use Drupal\auditfiles\Batch\AuditFilesNotInDatabaseBatchProcess; use Drupal\auditfiles\Reference\DiskReference; use Drupal\auditfiles\Services\AuditFilesConfigInterface; +use Drupal\auditfiles\Services\AuditFilesExport; use Drupal\Core\Batch\BatchBuilder; use Drupal\Core\Datetime\DateFormatterInterface; use Drupal\Core\Form\ConfirmFormHelper; @@ -50,6 +51,7 @@ final class AuditFilesNotInDatabaseForm extends FormBase implements AuditFilesAu RequestStack $requestStack, private DateFormatterInterface $dateFormatter, private MimeTypeGuesserInterface $mimeTypeGuesser, + protected AuditFilesExport $export, ) { $this->setRequestStack($requestStack); } @@ -62,6 +64,7 @@ final class AuditFilesNotInDatabaseForm extends FormBase implements AuditFilesAu $container->get('request_stack'), $container->get('date.formatter'), $container->get('file.mime_type.guesser'), + $container->get('auditfiles.export'), ); } @@ -156,7 +159,6 @@ final class AuditFilesNotInDatabaseForm extends FormBase implements AuditFilesAu ], '#empty' => $this->t('No items found.'), '#options' => $pages[$currentPage] ?? $rows, - '#required' => TRUE, ]; if (0 === \count($rows)) { @@ -164,6 +166,19 @@ final class AuditFilesNotInDatabaseForm extends FormBase implements AuditFilesAu } $form['actions'] = ['#type' => 'actions']; + + // Write all data to the CSV file. + $header = [$this->t('File pathname'), $this->t('MIME'), $this->t('Size (in bytes)'), $this->t('Last modified')]; + $this->export->write($header, $rows); + + $form['actions']['export'] = [ + '#type' => 'submit', + '#value' => $this->t('Export all results'), + '#submit' => [ + $this->export(...), + ], + ]; + $form['actions']['add'] = [ '#type' => 'submit', '#value' => $this->t('Add selected items to the database'), @@ -202,6 +217,13 @@ final class AuditFilesNotInDatabaseForm extends FormBase implements AuditFilesAu } } + /** + * Submit for downloading data. + */ + public function export(array &$form, FormStateInterface $form_state): void { + $this->export->download('Not in database'); + } + /** * Add record to database. */ diff --git a/src/Form/AuditFilesNotOnServerForm.php b/src/Form/AuditFilesNotOnServerForm.php index 32ea8865e2b6c56ecb3f2ca8b81d7ea5fba3627a..b6fa5e5e73ddc3a1c5a5b85921539d276883b9a6 100644 --- a/src/Form/AuditFilesNotOnServerForm.php +++ b/src/Form/AuditFilesNotOnServerForm.php @@ -8,6 +8,7 @@ use Drupal\auditfiles\Auditor\AuditFilesNotOnServer; use Drupal\auditfiles\Batch\AuditFilesDeleteFileEntityBatchProcess; use Drupal\auditfiles\Reference\FileEntityReference; use Drupal\auditfiles\Services\AuditFilesConfigInterface; +use Drupal\auditfiles\Services\AuditFilesExport; use Drupal\Core\Batch\BatchBuilder; use Drupal\Core\Datetime\DateFormatterInterface; use Drupal\Core\File\FileSystemInterface; @@ -43,6 +44,7 @@ final class AuditFilesNotOnServerForm extends FormBase implements AuditFilesAudi protected PagerManagerInterface $pagerManager, protected FileSystemInterface $fileSystem, protected DateFormatterInterface $dateFormatter, + protected AuditFilesExport $export, ) { } @@ -53,6 +55,7 @@ final class AuditFilesNotOnServerForm extends FormBase implements AuditFilesAudi $container->get('pager.manager'), $container->get('file_system'), $container->get('date.formatter'), + $container->get('auditfiles.export'), ); } @@ -172,6 +175,29 @@ final class AuditFilesNotOnServerForm extends FormBase implements AuditFilesAudi } $form['actions'] = ['#type' => 'actions']; + + // Write all data to the CSV file. + $header = [ + $this->t('File ID'), + $this->t('User ID'), + $this->t('Name'), + $this->t('URI'), + $this->t('Path'), + $this->t('MIME'), + $this->t('Size'), + $this->t('When added'), + $this->t('Status'), + ]; + $this->export->write($header, $rows); + + $form['actions']['export'] = [ + '#type' => 'submit', + '#value' => $this->t('Export all results'), + '#submit' => [ + $this->export(...), + ], + ]; + $form['actions']['submit'] = [ '#type' => 'submit', '#value' => $this->t('Delete selected items from the database'), @@ -199,6 +225,13 @@ final class AuditFilesNotOnServerForm extends FormBase implements AuditFilesAudi } } + /** + * Submit for downloading data. + */ + public function export(array &$form, FormStateInterface $form_state): void { + $this->export->download('Not on server'); + } + /** * Delete record to database. */ diff --git a/src/Form/AuditFilesReferencedNotUsedForm.php b/src/Form/AuditFilesReferencedNotUsedForm.php index 39abcfd7a94cc67720203ae239f519b0e9960bf2..36bcd158a535de688960255a647dabac12c3bac7 100644 --- a/src/Form/AuditFilesReferencedNotUsedForm.php +++ b/src/Form/AuditFilesReferencedNotUsedForm.php @@ -8,6 +8,7 @@ use Drupal\auditfiles\Auditor\AuditFilesReferencedNotUsed; use Drupal\auditfiles\Batch\AuditFilesReferencedNotUsedBatchProcess; use Drupal\auditfiles\Reference\FileFieldReference; use Drupal\auditfiles\Services\AuditFilesConfigInterface; +use Drupal\auditfiles\Services\AuditFilesExport; use Drupal\Core\Batch\BatchBuilder; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\File\FileUrlGeneratorInterface; @@ -46,6 +47,7 @@ final class AuditFilesReferencedNotUsedForm extends FormBase implements AuditFil protected PagerManagerInterface $pagerManager, protected FileUrlGeneratorInterface $fileUrlGenerator, protected EntityTypeManagerInterface $entityTypeManager, + protected AuditFilesExport $export, ) { } @@ -56,6 +58,7 @@ final class AuditFilesReferencedNotUsedForm extends FormBase implements AuditFil $container->get('pager.manager'), $container->get('file_url_generator'), $container->get('entity_type.manager'), + $container->get('auditfiles.export'), ); } @@ -213,6 +216,39 @@ final class AuditFilesReferencedNotUsedForm extends FormBase implements AuditFil } $form['actions'] = ['#type' => 'actions']; + + // Write all data to the CSV file. + $header = [ + $this->t('File ID'), + $this->t('Referencing entity type'), + $this->t('Referencing entity ID'), + $this->t('Field referenced in'), + $this->t('URI'), + $this->t('MIME'), + $this->t('Size (in bytes)'), + ]; + $data = $rows; + $columns = array_keys($form['files']['#header']); + foreach ($data as &$row) { + foreach ($row as $key => $value) { + if (!\in_array($key, $columns)) { + unset($row[$key]); + } + } + + $row['entity_id_display'] = $row['entity_id_display'] instanceof Link ? $row['entity_id_display']->toString() : $row['entity_id_display']; + $row['uri'] = $row['uri'] instanceof Link ? $row['uri']->toString() : $row['uri']; + } + $this->export->write($header, $data); + + $form['actions']['export'] = [ + '#type' => 'submit', + '#value' => $this->t('Export all results'), + '#submit' => [ + $this->export(...), + ], + ]; + $form['actions']['add'] = [ '#type' => 'submit', '#value' => $this->t('Add selected items to the file_usage table'), @@ -251,6 +287,13 @@ final class AuditFilesReferencedNotUsedForm extends FormBase implements AuditFil } } + /** + * Submit for downloading data. + */ + public function export(array &$form, FormStateInterface $form_state): void { + $this->export->download('Referenced not used'); + } + /** * Submit form. */ diff --git a/src/Form/AuditFilesUsedNotManagedForm.php b/src/Form/AuditFilesUsedNotManagedForm.php index bd80c8768b9228c9a081202a50dcd46bba5b0a32..6be301283923c62f797b07bc802c0667247250a4 100644 --- a/src/Form/AuditFilesUsedNotManagedForm.php +++ b/src/Form/AuditFilesUsedNotManagedForm.php @@ -9,6 +9,7 @@ use Drupal\auditfiles\Batch\AuditFilesDeleteFileUsageBatchProcess; use Drupal\auditfiles\Reference\FileEntityReference; use Drupal\auditfiles\Reference\FileUsageReference; use Drupal\auditfiles\Services\AuditFilesConfigInterface; +use Drupal\auditfiles\Services\AuditFilesExport; use Drupal\Component\Plugin\Exception\PluginNotFoundException; use Drupal\Core\Batch\BatchBuilder; use Drupal\Core\Entity\EntityTypeManagerInterface; @@ -43,6 +44,7 @@ final class AuditFilesUsedNotManagedForm extends FormBase implements AuditFilesA protected AuditFilesUsedNotManaged $filesUsedNotManaged, protected PagerManagerInterface $pagerManager, protected EntityTypeManagerInterface $entityTypeManager, + protected AuditFilesExport $export, ) { } @@ -52,6 +54,7 @@ final class AuditFilesUsedNotManagedForm extends FormBase implements AuditFilesA $container->get('auditfiles.auditor.used_not_managed'), $container->get('pager.manager'), $container->get('entity_type.manager'), + $container->get('auditfiles.export'), ); } @@ -160,6 +163,19 @@ final class AuditFilesUsedNotManagedForm extends FormBase implements AuditFilesA } $form['actions'] = ['#type' => 'actions']; + + // Write all data to the CSV file. + $header = [$this->t('Missing-File ID'), $this->t('Used by'), $this->t('Used in'), $this->t('Count')]; + $this->export->write($header, $rows); + + $form['actions']['export'] = [ + '#type' => 'submit', + '#value' => $this->t('Export all results'), + '#submit' => [ + $this->export(...), + ], + ]; + $form['actions']['submit'] = [ '#type' => 'submit', '#value' => $this->t('Delete selected items from the file_usage table'), @@ -187,6 +203,13 @@ final class AuditFilesUsedNotManagedForm extends FormBase implements AuditFilesA } } + /** + * Submit for downloading data. + */ + public function export(array &$form, FormStateInterface $form_state): void { + $this->export->download('Used not managed'); + } + /** * Submit for confirmation. */ diff --git a/src/Form/AuditFilesUsedNotReferencedForm.php b/src/Form/AuditFilesUsedNotReferencedForm.php index 4a6018c64ced821f7b306a1c5b36b19eb7b2c45d..ea6b3ed4f4693452bd0eebce319c5319de669de5 100644 --- a/src/Form/AuditFilesUsedNotReferencedForm.php +++ b/src/Form/AuditFilesUsedNotReferencedForm.php @@ -9,6 +9,7 @@ use Drupal\auditfiles\Batch\AuditFilesDeleteFileUsageBatchProcess; use Drupal\auditfiles\Reference\FileEntityReference; use Drupal\auditfiles\Reference\FileUsageReference; use Drupal\auditfiles\Services\AuditFilesConfigInterface; +use Drupal\auditfiles\Services\AuditFilesExport; use Drupal\Component\Plugin\Exception\PluginNotFoundException; use Drupal\Core\Batch\BatchBuilder; use Drupal\Core\Database\Connection; @@ -48,6 +49,7 @@ final class AuditFilesUsedNotReferencedForm extends FormBase implements AuditFil protected EntityTypeManagerInterface $entityTypeManager, protected FileUrlGeneratorInterface $fileUrlGenerator, protected Connection $connection, + protected AuditFilesExport $export, ) { } @@ -59,6 +61,7 @@ final class AuditFilesUsedNotReferencedForm extends FormBase implements AuditFil $container->get('entity_type.manager'), $container->get('file_url_generator'), $container->get('database'), + $container->get('auditfiles.export'), ); } @@ -202,6 +205,25 @@ final class AuditFilesUsedNotReferencedForm extends FormBase implements AuditFil } $form['actions'] = ['#type' => 'actions']; + + // Write all data to the CSV file. + $header = [$this->t('File ID'), $this->t('File URI'), $this->t('Usages')]; + $data = $rows; + foreach ($data as &$row) { + $row['uri'] = !empty($row['uri']) ? $row['uri']->toString() : ''; + $items = !empty($row['usage']['data']['#items']) ? $row['usage']['data']['#items'] : []; + $row['usage'] = implode(PHP_EOL, $items); + } + $this->export->write($header, $data); + + $form['actions']['export'] = [ + '#type' => 'submit', + '#value' => $this->t('Export all results'), + '#submit' => [ + $this->export(...), + ], + ]; + $form['actions']['submit'] = [ '#type' => 'submit', '#value' => $this->t('Delete selected items from the file_usage table'), @@ -229,6 +251,13 @@ final class AuditFilesUsedNotReferencedForm extends FormBase implements AuditFil } } + /** + * Submit for downloading data. + */ + public function export(array &$form, FormStateInterface $form_state): void { + $this->export->download('Used not referenced'); + } + /** * Submit for confirmation. */ diff --git a/src/Services/AuditFilesExport.php b/src/Services/AuditFilesExport.php new file mode 100644 index 0000000000000000000000000000000000000000..86fcc0cb3142df3ce18504e73a8f401ad47e0a5a --- /dev/null +++ b/src/Services/AuditFilesExport.php @@ -0,0 +1,49 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\auditfiles\Services; + +use League\Csv\Writer; + +/** + * Provides a service to export audit files as CSV file. + */ +class AuditFilesExport { + + /** + * CSV file to manage. + * + * @var mixed + */ + public $csv; + + /** + * Helper to write all data to the file. + * + * @param array $header + * An array of headers (first row). + * @param array $data + * An array of data. + */ + public function write(array $header, array $data = []): void { + $this->csv = Writer::createFromFileObject(new \SplTempFileObject()); + $this->csv->insertOne($header); + + if ($data) { + $this->csv->insertAll($data); + } + } + + /** + * Helper to download the file. + * + * @param string $name + * File name to download. + */ + public function download(string $name = 'output'): void { + $this->csv->download("{$name}.csv"); + die; + } + +}