diff --git a/islandora.services.yml b/islandora.services.yml index 6dfa158d..4108e244 100644 --- a/islandora.services.yml +++ b/islandora.services.yml @@ -66,6 +66,7 @@ services: - '@database' - '@current_user' - '@messenger' + - '@date.formatter' islandora.upload_media.batch_processor: class: Drupal\islandora\Form\AddChildrenWizard\MediaBatchProcessor arguments: @@ -73,3 +74,4 @@ services: - '@database' - '@current_user' - '@messenger' + - '@date.formatter' diff --git a/src/Form/AddChildrenWizard/AbstractBatchProcessor.php b/src/Form/AddChildrenWizard/AbstractBatchProcessor.php index 6ea426e3..359db27e 100644 --- a/src/Form/AddChildrenWizard/AbstractBatchProcessor.php +++ b/src/Form/AddChildrenWizard/AbstractBatchProcessor.php @@ -3,6 +3,7 @@ namespace Drupal\islandora\Form\AddChildrenWizard; use Drupal\Core\Database\Connection; +use Drupal\Core\Datetime\DateFormatterInterface; use Drupal\Core\DependencyInjection\DependencySerializationTrait; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Messenger\MessengerInterface; @@ -53,6 +54,13 @@ abstract class AbstractBatchProcessor { */ protected MessengerInterface $messenger; + /** + * The date formatter service. + * + * @var \Drupal\Core\Datetime\DateFormatterInterface + */ + protected DateFormatterInterface $dateFormatter; + /** * Constructor. */ @@ -60,12 +68,14 @@ abstract class AbstractBatchProcessor { EntityTypeManagerInterface $entity_type_manager, Connection $database, AccountProxyInterface $current_user, - MessengerInterface $messenger + MessengerInterface $messenger, + DateFormatterInterface $date_formatter ) { $this->entityTypeManager = $entity_type_manager; $this->database = $database; $this->currentUser = $current_user; $this->messenger = $messenger; + $this->dateFormatter = $date_formatter; } /** @@ -96,24 +106,25 @@ abstract class AbstractBatchProcessor { /** * Loads the file indicated. * - * @param array $info - * An associative array containing at least: - * - target_id: The id of the file to load. + * @param mixed $info + * Widget values. * - * @return \Drupal\file\FileInterface + * @return \Drupal\file\FileInterface|null * The loaded file. * * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ - protected function getFile(array $info) : FileInterface { - return $this->entityTypeManager->getStorage('file')->load($info['target_id']); + protected function getFile($info) : ?FileInterface { + return (is_array($info) && isset($info['target_id'])) ? + $this->entityTypeManager->getStorage('file')->load($info['target_id']) : + NULL; } /** * Get the node to which to attach our media. * - * @param array $info + * @param mixed $info * Info from the widget used to create the request. * @param array $values * Additional form inputs. @@ -121,16 +132,36 @@ abstract class AbstractBatchProcessor { * @return \Drupal\node\NodeInterface * The node to which to attach the created media. */ - abstract protected function getNode(array $info, array $values) : NodeInterface; + abstract protected function getNode($info, array $values) : NodeInterface; + + /** + * Get a name to use for bulk-created assets. + * + * @param mixed $info + * Widget values. + * @param array $values + * Form values. + * + * @return string + * An applicable name. + * + * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException + * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException + */ + protected function getName($info, array $values) : string { + $file = $this->getFile($info); + return $file ? $file->getFilename() : strtr('Bulk ingest, {date}', [ + '{date}' => $this->dateFormatter->format(time(), 'long'), + ]); + } /** * Create a media referencing the given file, associated with the given node. * * @param \Drupal\node\NodeInterface $node * The node to which the media should be associated. - * @param array $info - * The widget info, which should have a 'target_id' identifying the target - * file. + * @param mixed $info + * The widget info for the media source field. * @param array $values * Values from the wizard, which should contain at least: * - media_type: The machine name/ID of the media type as which to create @@ -144,18 +175,16 @@ abstract class AbstractBatchProcessor { * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException * @throws \Drupal\Core\Entity\EntityStorageException */ - protected function createMedia(NodeInterface $node, array $info, array $values) : MediaInterface { + protected function createMedia(NodeInterface $node, $info, array $values) : MediaInterface { $taxonomy_term_storage = $this->entityTypeManager->getStorage('taxonomy_term'); - $file = $this->getFile($info); - // Create a media with the file attached and also pointing at the node. $field = $this->getField($values); $media_values = array_merge( [ 'bundle' => $values['media_type'], - 'name' => $file->getFilename(), + 'name' => $this->getName($info, $values), IslandoraUtils::MEDIA_OF_FIELD => $node, IslandoraUtils::MEDIA_USAGE_FIELD => ($values['use'] ? $taxonomy_term_storage->loadMultiple($values['use']) : @@ -172,7 +201,7 @@ abstract class AbstractBatchProcessor { ); $media = $this->entityTypeManager->getStorage('media')->create($media_values); if ($media->save() !== SAVED_NEW) { - throw new \Exception("Failed to create media for file '{$file->id()}."); + throw new \Exception("Failed to create media."); } return $media; diff --git a/src/Form/AddChildrenWizard/AbstractFileSelectionForm.php b/src/Form/AddChildrenWizard/AbstractFileSelectionForm.php index c8436a1a..6aeed879 100644 --- a/src/Form/AddChildrenWizard/AbstractFileSelectionForm.php +++ b/src/Form/AddChildrenWizard/AbstractFileSelectionForm.php @@ -3,6 +3,7 @@ namespace Drupal\islandora\Form\AddChildrenWizard; use Drupal\Core\Batch\BatchBuilder; +use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldItemList; use Drupal\Core\Field\FieldStorageDefinitionInterface; @@ -10,6 +11,7 @@ use Drupal\Core\Field\WidgetInterface; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Session\AccountProxyInterface; +use Drupal\field\FieldStorageConfigInterface; use Drupal\media\MediaTypeInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -81,7 +83,16 @@ abstract class AbstractFileSelectionForm extends FormBase { $cached_values = $form_state->getTemporaryValue('wizard'); $field = $this->getField($cached_values); - $field->getFieldStorageDefinition()->set('cardinality', FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED); + $def = $field->getFieldStorageDefinition(); + if ($def instanceof FieldStorageConfigInterface) { + $def->set('cardinality', FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED); + } + elseif ($def instanceof BaseFieldDefinition) { + $def->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED); + } + else { + throw new \Exception('Unable to remove cardinality limit.'); + } return $field; } @@ -129,7 +140,7 @@ abstract class AbstractFileSelectionForm extends FormBase { $widget = $this->getWidgetFromFormState($form_state); $builder = (new BatchBuilder()) - ->setTitle($this->t('Creating children...')) + ->setTitle($this->t('Bulk creating...')) ->setInitMessage($this->t('Initializing...')) ->setFinishCallback([$this->batchProcessor, 'batchProcessFinished']); $values = $form_state->getValue($this->getField($cached_values)->getName()); diff --git a/src/Form/AddChildrenWizard/AbstractForm.php b/src/Form/AddChildrenWizard/AbstractForm.php index 251953f6..23f511e0 100644 --- a/src/Form/AddChildrenWizard/AbstractForm.php +++ b/src/Form/AddChildrenWizard/AbstractForm.php @@ -31,9 +31,9 @@ abstract class AbstractForm extends FormWizardBase { /** * The current node ID. * - * @var string|mixed|null + * @var mixed|null */ - protected string $nodeId; + protected $nodeId; /** * The current route match. @@ -90,14 +90,14 @@ abstract class AbstractForm extends FormWizardBase { $ops = []; $ops['type_selection'] = [ - 'title' => $this->t('Type of children'), + 'title' => $this->t('Type Selection'), 'form' => static::TYPE_SELECTION_FORM, 'values' => [ 'node' => $this->nodeId, ], ]; $ops['file_selection'] = [ - 'title' => $this->t('Files for children'), + 'title' => $this->t('Widget Input for Selected Type'), 'form' => static::FILE_SELECTION_FORM, 'values' => [ 'node' => $this->nodeId, diff --git a/src/Form/AddChildrenWizard/ChildBatchProcessor.php b/src/Form/AddChildrenWizard/ChildBatchProcessor.php index 9be9902a..084e7816 100644 --- a/src/Form/AddChildrenWizard/ChildBatchProcessor.php +++ b/src/Form/AddChildrenWizard/ChildBatchProcessor.php @@ -13,18 +13,17 @@ class ChildBatchProcessor extends AbstractBatchProcessor { /** * {@inheritdoc} */ - protected function getNode(array $info, array $values) : NodeInterface { + protected function getNode($info, array $values) : NodeInterface { $taxonomy_term_storage = $this->entityTypeManager->getStorage('taxonomy_term'); $node_storage = $this->entityTypeManager->getStorage('node'); $parent = $node_storage->load($values['node']); - $file = $this->getFile($info); // Create a node (with the filename?) (and also belonging to the target // node). /** @var \Drupal\node\NodeInterface $node */ $node = $node_storage->create([ 'type' => $values['bundle'], - 'title' => $file->getFilename(), + 'title' => $this->getName($info, $values), IslandoraUtils::MEMBER_OF_FIELD => $parent, 'uid' => $this->currentUser->id(), 'status' => NodeInterface::PUBLISHED, @@ -34,7 +33,7 @@ class ChildBatchProcessor extends AbstractBatchProcessor { ]); if ($node->save() !== SAVED_NEW) { - throw new \Exception("Failed to create node for file '{$file->id()}'."); + throw new \Exception("Failed to create node."); } return $node; diff --git a/src/Form/AddChildrenWizard/ChildTypeSelectionForm.php b/src/Form/AddChildrenWizard/ChildTypeSelectionForm.php index 843cc85b..f5795997 100644 --- a/src/Form/AddChildrenWizard/ChildTypeSelectionForm.php +++ b/src/Form/AddChildrenWizard/ChildTypeSelectionForm.php @@ -14,7 +14,7 @@ class ChildTypeSelectionForm extends MediaTypeSelectionForm { /** * {@inheritdoc} */ - public function getFormId() { + public function getFormId() : string { return 'islandora_add_children_type_selection'; } @@ -144,7 +144,7 @@ class ChildTypeSelectionForm extends MediaTypeSelectionForm { /** * {@inheritdoc} */ - protected static function keysToSave() { + protected static function keysToSave() : array { return array_merge( parent::keysToSave(), [ diff --git a/src/Form/AddChildrenWizard/FieldTrait.php b/src/Form/AddChildrenWizard/FieldTrait.php index 743fc619..830f95cd 100644 --- a/src/Form/AddChildrenWizard/FieldTrait.php +++ b/src/Form/AddChildrenWizard/FieldTrait.php @@ -39,7 +39,7 @@ trait FieldTrait { $fields = $this->entityFieldManager()->getFieldDefinitions('media', $media_type->id()); return $fields[$source_field->getFieldStorageDefinition()->getName()] ?? - $media_source->createSourceField(); + $media_source->createSourceField($media_type); } /** diff --git a/src/Form/AddChildrenWizard/MediaBatchProcessor.php b/src/Form/AddChildrenWizard/MediaBatchProcessor.php index f069d0bf..9a54f03b 100644 --- a/src/Form/AddChildrenWizard/MediaBatchProcessor.php +++ b/src/Form/AddChildrenWizard/MediaBatchProcessor.php @@ -12,7 +12,7 @@ class MediaBatchProcessor extends AbstractBatchProcessor { /** * {@inheritdoc} */ - protected function getNode(array $info, array $values) : NodeInterface { + protected function getNode($info, array $values) : NodeInterface { return $this->entityTypeManager->getStorage('node')->load($values['node']); } diff --git a/src/Form/AddChildrenWizard/MediaTypeSelectionForm.php b/src/Form/AddChildrenWizard/MediaTypeSelectionForm.php index 0e687d58..b06d004d 100644 --- a/src/Form/AddChildrenWizard/MediaTypeSelectionForm.php +++ b/src/Form/AddChildrenWizard/MediaTypeSelectionForm.php @@ -44,15 +44,23 @@ class MediaTypeSelectionForm extends FormBase { */ protected ?EntityFieldManagerInterface $entityFieldManager; + /** + * The Islandora Utils service. + * + * @var \Drupal\islandora\IslandoraUtils|null + */ + protected ?IslandoraUtils $utils; + /** * {@inheritdoc} */ - public static function create(ContainerInterface $container) { + public static function create(ContainerInterface $container) : self { $instance = parent::create($container); $instance->entityTypeBundleInfo = $container->get('entity_type.bundle.info'); $instance->entityTypeManager = $container->get('entity_type.manager'); $instance->entityFieldManager = $container->get('entity_field.manager'); + $instance->utils = $container->get('islandora.utils'); return $instance; } @@ -60,7 +68,7 @@ class MediaTypeSelectionForm extends FormBase { /** * {@inheritdoc} */ - public function getFormId() { + public function getFormId() : string { return 'islandora_add_media_type_selection'; } @@ -94,6 +102,9 @@ class MediaTypeSelectionForm extends FormBase { $access_handler = $this->entityTypeManager->getAccessControlHandler('media'); foreach ($this->entityTypeBundleInfo->getBundleInfo('media') as $bundle => $info) { + if (!$this->utils->isIslandoraType('media', $bundle)) { + continue; + } $access = $access_handler->createAccess( $bundle, NULL, @@ -122,7 +133,7 @@ class MediaTypeSelectionForm extends FormBase { * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ - protected function getMediaUseOptions() { + protected function getMediaUseOptions() : \Generator { /** @var \Drupal\taxonomy\TermInterface[] $terms */ $terms = $this->entityTypeManager->getStorage('taxonomy_term') ->loadTree('islandora_media_use', 0, NULL, TRUE); @@ -195,7 +206,7 @@ class MediaTypeSelectionForm extends FormBase { * @return string[] * The keys to be persisted in our temp value in form state. */ - protected static function keysToSave() { + protected static function keysToSave() : array { return [ 'media_type', 'use', diff --git a/src/Form/AddChildrenWizard/MediaTypeTrait.php b/src/Form/AddChildrenWizard/MediaTypeTrait.php index 5600210b..36cf6ff2 100644 --- a/src/Form/AddChildrenWizard/MediaTypeTrait.php +++ b/src/Form/AddChildrenWizard/MediaTypeTrait.php @@ -31,7 +31,6 @@ trait MediaTypeTrait { * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ protected function getMediaType(array $values): MediaTypeInterface { - /** @var \Drupal\media\MediaTypeInterface $media_type */ return $this->entityTypeManager()->getStorage('media_type')->load($values['media_type']); }