Browse Source

abstracted media and file deletion

pull/1017/head
ajstanley 8 months ago
parent
commit
03293d8d2e
  1. 119
      islandora.module
  2. 2
      islandora.services.yml
  3. 118
      src/Form/ConfirmDeleteMediaAndFile.php
  4. 95
      src/IslandoraUtils.php

119
islandora.module

@ -408,132 +408,25 @@ function islandora_media_custom_form_submit(&$form, FormStateInterface $form_sta
* Implements a submit handler for the delete form.
*/
function islandora_object_delete_form_submit($form, FormStateInterface $form_state) {
$result = $form_state->getValues('delete_associated_content');
$utils = \Drupal::service('islandora.utils');
if ($result['delete_associated_content'] == 1) {
$utils = \Drupal::service('islandora.utils');
$node = $form_state->getFormObject()->getEntity();
$medias = $utils->getMedia($node);
$media_list = [];
$entity_field_manager = \Drupal::service('entity_field.manager');
$current_user = \Drupal::currentUser();
$results = $utils->deleteMediaAndFiles($medias);
$logger = \Drupal::logger('logger.channel.islandora');
$messenger = \Drupal::messenger();
$delete_media = [];
$media_translations = [];
$media_files = [];
$entity_protected_medias = [];
$inaccessible_entities = [];
foreach ($medias as $id => $media) {
$lang = $media->language()->getId();
$selected_langcodes[$lang] = $lang;
if (!$media->access('delete', $current_user)) {
$inaccessible_entities[] = $media;
continue;
}
// Check for files.
$fields = $entity_field_manager->getFieldDefinitions('media', $media->bundle());
foreach ($fields as $field) {
$type = $field->getType();
if ($type == 'file' || $type == 'image') {
$target_id = $media->get($field->getName())->target_id;
$file = File::load($target_id);
if ($file) {
if (!$file->access('delete', $current_user)) {
$inaccessible_entities[] = $file;
continue;
}
$media_files[$id][$file->id()] = $file;
}
}
}
foreach ($selected_langcodes as $langcode) {
// We're only working with media, which are translatable.
$entity = $media->getTranslation($langcode);
if ($entity->isDefaultTranslation()) {
$delete_media[$id] = $entity;
unset($media_translations[$id]);
}
elseif (!isset($delete_media[$id])) {
$media_translations[$id][] = $entity;
}
}
if (isset($results['inaccessible'])) {
$messenger->addWarning($results['inaccessible']);
}
if ($delete_media) {
foreach ($delete_media as $id => $media) {
try {
$media->delete();
$media_list[] = $id;
$logger->notice('The media %label has been deleted.', [
'%label' => $media->label(),
]);
}
catch (Exception $e) {
$entity_protected_medias[] = $id;
}
}
}
$delete_files = array_filter($media_files, function ($media) use ($entity_protected_medias) {
return !in_array($media, $entity_protected_medias);
}, ARRAY_FILTER_USE_KEY);
if ($delete_files) {
foreach ($delete_files as $files_array) {
foreach ($files_array as $file) {
$file->delete();
$logger->notice('The file %label has been deleted.', [
'%label' => $file->label(),
]);
}
}
}
$delete_media_translations = array_filter($media_translations, function ($media) use ($entity_protected_medias) {
return !in_array($media, $entity_protected_medias);
}, ARRAY_FILTER_USE_KEY);
if ($delete_media_translations) {
foreach ($delete_media_translations as $id => $translations) {
$media = $medias[$id];
foreach ($translations as $translation) {
$media->removeTranslation($translation->language()->getId());
}
$media->save();
foreach ($translations as $translation) {
$logger->notice('The media %label @language translation has been deleted', [
'%label' => $media->label(),
'@language' => $translation->language()->getName(),
]);
}
}
}
if ($inaccessible_entities) {
$messenger->addWarning("@count items have not been deleted because you do not have the necessary permissions.", [
'@count' => count($inaccessible_entities),
]);
}
$logger->notice($results['deleted']);
$build = [
'heading' => [
'#type' => 'html_tag',
'#tag' => 'div',
'#value' => t("The repository item @node and @media", [
'@node' => $node->getTitle(),
'@media' => \Drupal::translation()->formatPlural(
count($media_list), 'the media with the id @media has been deleted.',
'the medias with the ids @media have been deleted.',
['@media' => implode(", ", $media_list)],
),
'@media' => $results['deleted'],
]),
],
];

2
islandora.services.yml

@ -54,7 +54,7 @@ services:
arguments: ['@entity_type.manager', '@current_user', '@language_manager', '@file_system', '@islandora.utils']
islandora.utils:
class: Drupal\islandora\IslandoraUtils
arguments: ['@entity_type.manager', '@entity_field.manager', '@context.manager', '@flysystem_factory', '@language_manager']
arguments: ['@entity_type.manager', '@entity_field.manager', '@context.manager', '@flysystem_factory', '@language_manager', '@current_user']
islandora.entity_mapper:
class: Islandora\EntityMapper\EntityMapper
islandora.stomp.auth_header_listener:

118
src/Form/ConfirmDeleteMediaAndFile.php

@ -2,7 +2,6 @@
namespace Drupal\islandora\Form;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\Form\DeleteMultipleForm;
use Drupal\Core\Form\FormStateInterface;
@ -10,8 +9,7 @@ use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Drupal\Core\Url;
use Drupal\file\Entity\File;
use Drupal\islandora\MediaSource\MediaSourceService;
use Drupal\islandora\IslandoraUtils;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
@ -21,11 +19,11 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
class ConfirmDeleteMediaAndFile extends DeleteMultipleForm {
/**
* Media source service.
* The current user.
*
* @var \Drupal\islandora\MediaSource\MediaSourceService
* @var \Drupal\Core\Session\AccountInterface
*/
protected $mediaSourceService;
protected $currentUser;
/**
* Logger.
@ -42,23 +40,22 @@ class ConfirmDeleteMediaAndFile extends DeleteMultipleForm {
protected $selection = [];
/**
* Entity field manager.
* The Islandora Utils service.
*
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
* @var \Drupal\islandora\IslandoraUtils
*/
protected $entityFieldManager;
protected IslandoraUtils $utils;
/**
* {@inheritdoc}
*/
public function __construct(AccountInterface $current_user, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, PrivateTempStoreFactory $temp_store_factory, MessengerInterface $messenger, MediaSourceService $media_source_service, LoggerInterface $logger) {
public function __construct(AccountInterface $current_user, EntityTypeManagerInterface $entity_type_manager, PrivateTempStoreFactory $temp_store_factory, MessengerInterface $messenger, LoggerInterface $logger, IslandoraUtils $utils) {
$this->currentUser = $current_user;
$this->entityTypeManager = $entity_type_manager;
$this->entityFieldManager = $entity_field_manager;
$this->tempStore = $temp_store_factory->get('media_and_file_delete_confirm');
$this->messenger = $messenger;
$this->mediaSourceService = $media_source_service;
$this->logger = $logger;
$this->utils = $utils;
}
/**
@ -68,11 +65,11 @@ class ConfirmDeleteMediaAndFile extends DeleteMultipleForm {
return new static(
$container->get('current_user'),
$container->get('entity_type.manager'),
$container->get('entity_field.manager'),
$container->get('tempstore.private'),
$container->get('messenger'),
$container->get('islandora.media_source_service'),
$container->get('logger.channel.islandora'));
$container->get('logger.channel.islandora'),
$container->get('islandora.utils')
);
}
/**
@ -111,94 +108,13 @@ class ConfirmDeleteMediaAndFile extends DeleteMultipleForm {
public function submitForm(array &$form, FormStateInterface $form_state) {
// Similar to parent::submitForm(), but let's blend in the related files and
// optimize based on the fact that we know we're working with media.
$total_count = 0;
$delete_media = [];
$delete_media_translations = [];
$delete_files = [];
$inaccessible_entities = [];
$media_storage = $this->entityTypeManager->getStorage('media');
$file_storage = $this->entityTypeManager->getStorage('file');
$media = $media_storage->loadMultiple(array_keys($this->selection));
foreach ($this->selection as $id => $selected_langcodes) {
$entity = $media[$id];
if (!$entity->access('delete', $this->currentUser)) {
$inaccessible_entities[] = $entity;
continue;
}
// Check for files.
$fields = $this->entityFieldManager->getFieldDefinitions('media', $entity->bundle());
foreach ($fields as $field) {
if ($field->getName() == 'thumbnail') {
continue;
}
$type = $field->getType();
if ($type == 'file' || $type == 'image') {
$target_id = $entity->get($field->getName())->target_id;
$file = File::load($target_id);
if ($file) {
if (!$file->access('delete', $this->currentUser)) {
$inaccessible_entities[] = $file;
continue;
}
if (!array_key_exists($file->id(), $delete_files)) {
$delete_files[$file->id()] = $file;
$total_count++;
}
}
}
}
foreach ($selected_langcodes as $langcode) {
// We're only working with media, which are translatable.
$entity = $entity->getTranslation($langcode);
if ($entity->isDefaultTranslation()) {
$delete_media[$id] = $entity;
unset($delete_media_translations[$id]);
$total_count += count($entity->getTranslationLanguages());
}
elseif (!isset($delete_media[$id])) {
$delete_media_translations[$id][] = $entity;
}
}
}
if ($delete_media) {
$media_storage->delete($delete_media);
foreach ($delete_media as $entity) {
$this->logger->notice('The media %label has been deleted.', [
'%label' => $entity->label(),
]);
}
}
if ($delete_files) {
$file_storage->delete($delete_files);
foreach ($delete_files as $entity) {
$this->logger->notice('The file %label has been deleted.', [
'%label' => $entity->label(),
]);
}
}
if ($delete_media_translations) {
foreach ($delete_media_translations as $id => $translations) {
$entity = $media[$id];
foreach ($translations as $translation) {
$entity->removeTranslation($translation->language()->getId());
}
$entity->save();
foreach ($translations as $translation) {
$this->logger->notice('The media %label @language translation has been deleted', [
'%label' => $entity->label(),
'@language' => $translation->language()->getName(),
]);
}
$total_count += count($translations);
}
}
if ($total_count) {
$this->messenger->addStatus($this->getDeletedMessage($total_count));
}
if ($inaccessible_entities) {
$this->messenger->addWarning($this->getInaccessibleMessage(count($inaccessible_entities)));
$results = $this->utils->deleteMediaAndFiles($media);
$this->logger->notice($results['deleted']);
$this->messenger->addStatus($results['deleted']);
if (isset($results['inaccessible'])) {
$this->messenger->addWarning($results['inaccessible']);
}
$this->tempStore->delete($this->currentUser->id());
$form_state->setRedirectUrl($this->getCancelUrl());

95
src/IslandoraUtils.php

@ -10,7 +10,9 @@ use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\Query\QueryException;
use Drupal\Core\Entity\Query\QueryInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Site\Settings;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;
use Drupal\file\FileInterface;
use Drupal\flysystem\FlysystemFactory;
@ -26,13 +28,15 @@ use Drupal\taxonomy\TermInterface;
* Utility functions for figuring out when to fire derivative reactions.
*/
class IslandoraUtils {
use StringTranslationTrait;
const EXTERNAL_URI_FIELD = 'field_external_uri';
const MEDIA_OF_FIELD = 'field_media_of';
const MEDIA_USAGE_FIELD = 'field_media_use';
const MEMBER_OF_FIELD = 'field_member_of';
const MODEL_FIELD = 'field_model';
/**
@ -68,7 +72,14 @@ class IslandoraUtils {
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
protected LanguageManagerInterface $languageManager;
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected AccountInterface $currentUser;
/**
* Constructor.
@ -83,19 +94,23 @@ class IslandoraUtils {
* Flysystem factory.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* Language manager.
* @param \Drupal\Core\Session\AccountInterface $current_user
* The current user.
*/
public function __construct(
EntityTypeManagerInterface $entity_type_manager,
EntityFieldManagerInterface $entity_field_manager,
ContextManager $context_manager,
FlysystemFactory $flysystem_factory,
LanguageManagerInterface $language_manager
LanguageManagerInterface $language_manager,
AccountInterface $current_user
) {
$this->entityTypeManager = $entity_type_manager;
$this->entityFieldManager = $entity_field_manager;
$this->contextManager = $context_manager;
$this->flysystemFactory = $flysystem_factory;
$this->languageManager = $language_manager;
$this->currentUser = $current_user;
}
/**
@ -423,7 +438,6 @@ class IslandoraUtils {
* TRUE if the fields have changed.
*/
public function haveFieldsChanged(ContentEntityInterface $entity, ContentEntityInterface $original) {
$field_definitions = $this->entityFieldManager->getFieldDefinitions($entity->getEntityTypeId(), $entity->bundle());
$ignore_list = ['vid' => 1, 'changed' => 1, 'path' => 1];
@ -528,7 +542,8 @@ class IslandoraUtils {
* Array of fields.
*/
public function getReferencingFields($entity_type, $target_type) {
$fields = $this->entityTypeManager->getStorage('field_storage_config')->getQuery()
$fields = $this->entityTypeManager->getStorage('field_storage_config')
->getQuery()
->condition('entity_type', $entity_type)
->condition('settings.target_type', $target_type)
->execute();
@ -657,8 +672,6 @@ class IslandoraUtils {
public function canCreateIslandoraEntity($entity_type, $bundle_type) {
$bundles = $this->entityTypeManager->getStorage($bundle_type)->loadMultiple();
$access_control_handler = $this->entityTypeManager->getAccessControlHandler($entity_type);
$allowed = [];
foreach (array_keys($bundles) as $bundle) {
// Skip bundles that aren't 'Islandora' types.
if (!$this->isIslandoraType($entity_type, $bundle)) {
@ -755,4 +768,72 @@ class IslandoraUtils {
return $parents;
}
/**
* Deletes Media and all associated files.
*
* @param object $media_ids
* Ids of media to be deleted.
*
* @return array
* Associative array keyed 'deleted' and 'inaccessible'.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
* @throws \Drupal\Core\Entity\EntityStorageException
*/
public function deleteMediaAndFiles($media) {
$results = [];
$total_count = 0;
$delete_media = [];
$delete_files = [];
$inaccessible_entities = [];
$media_storage = $this->entityTypeManager->getStorage('media');
$file_storage = $this->entityTypeManager->getStorage('file');
foreach ($media as $entity) {
if (!$entity->access('delete', $this->currentUser)) {
$inaccessible_entities[] = $entity;
continue;
}
else {
$delete_media[$entity->id()] = $entity;
}
// Check for source and additional files.
$fields = $this->entityFieldManager->getFieldDefinitions('media', $entity->bundle());
foreach ($fields as $field) {
if ($field->getName() == 'thumbnail') {
continue;
}
$type = $field->getType();
if ($type == 'file' || $type == 'image') {
$target_id = $entity->get($field->getName())->target_id;
$file = $file_storage->load($target_id);
if ($file) {
if (!$file->access('delete', $this->currentUser)) {
$inaccessible_entities[] = $file;
continue;
}
if (!array_key_exists($file->id(), $delete_files)) {
$delete_files[$file->id()] = $file;
}
}
}
}
}
if ($delete_media) {
$media_storage->delete($delete_media);
}
if ($delete_files) {
$file_storage->delete($delete_files);
}
$results['deleted'] = $this->formatPlural(
count($delete_media), 'the media with the id @media has been deleted.',
'the medias with the ids @media have been deleted.',
['@media' => implode(", ", array_keys($delete_media))],
);
if ($inaccessible_entities) {
$results['inaccessible'] = $this->formatPlural($inaccessible_entities, "@count item has not been deleted because you do not have the necessary permissions.", "@count items have not been deleted because you do not have the necessary permissions.");
}
return $results;
}
}

Loading…
Cancel
Save