forked from alxp/islandora
-
Notifications
You must be signed in to change notification settings - Fork 118
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix/batch upload children, with validation according to default widget (
#896) * Add ctools, prior to using it. * Fix up all the dependency references. ... before the colon is the project name, so should only be "drupal" for modules shipped in core. * Some more together. * Decent progress... getting things actually rendering... ... bit of refactoring stuff making a mess. * More worky. ... as in, basically functional. Still needs coding standards pass, and testing with more/all types of content. * Coding standards, and warning of validation issues. * Pull the batch out to a separate service. * Something of namespacing the child-specific batch... ... 'cause need to slap together a media-specific batch similarly? * All together, I think... Both the child-uploading, and media-uploading forms. * It is not necessary to explicitly mark the files as permanent. * Further generalizing... ... no longer necessarily trying to load files, where files might not be present (for non-file media... oEmbed things?). * Adjust class comment. * Get rid of the deprecation flags. * Remove unused constant. ... is defined instead at the "FileSelectionForm" level, accidentally left it here from intermediate implementation state. * Pass the renderer along, with the version constraint. * Add update hook to enable ctools in sites where it may not be. ... as it's now required. * Cover ALL the exits. * Refine message. * Excessively long line in comment... ... whoops. * Bump spec up to allow ctools 4. Gave it a run through here, and seemed to work fine; however, ctools' project page still seems to suggest the 3 major version should be preferred... but let's allow 4, if people are using or want to test it out? * Fix undefined "count" index.
1 parent
bdbef45
commit 3f7ca2c
Showing
21 changed files
with
1,441 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,258 @@ | ||
<?php | ||
|
||
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; | ||
use Drupal\Core\Session\AccountProxyInterface; | ||
use Drupal\Core\StringTranslation\StringTranslationTrait; | ||
use Drupal\Core\Url; | ||
use Drupal\file\FileInterface; | ||
use Drupal\islandora\IslandoraUtils; | ||
use Drupal\media\MediaInterface; | ||
use Drupal\node\NodeInterface; | ||
use Symfony\Component\HttpKernel\Exception\HttpException; | ||
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; | ||
|
||
/** | ||
* Abstract addition batch processor. | ||
*/ | ||
abstract class AbstractBatchProcessor { | ||
|
||
use FieldTrait; | ||
use DependencySerializationTrait; | ||
use StringTranslationTrait; | ||
|
||
/** | ||
* The entity type manager service. | ||
* | ||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface|null | ||
*/ | ||
protected ?EntityTypeManagerInterface $entityTypeManager = NULL; | ||
|
||
/** | ||
* The database connection serivce. | ||
* | ||
* @var \Drupal\Core\Database\Connection|null | ||
*/ | ||
protected ?Connection $database; | ||
|
||
/** | ||
* The current user. | ||
* | ||
* @var \Drupal\Core\Session\AccountProxyInterface|null | ||
*/ | ||
protected ?AccountProxyInterface $currentUser; | ||
|
||
/** | ||
* The messenger service. | ||
* | ||
* @var \Drupal\Core\Messenger\MessengerInterface | ||
*/ | ||
protected MessengerInterface $messenger; | ||
|
||
/** | ||
* The date formatter service. | ||
* | ||
* @var \Drupal\Core\Datetime\DateFormatterInterface | ||
*/ | ||
protected DateFormatterInterface $dateFormatter; | ||
|
||
/** | ||
* Constructor. | ||
*/ | ||
public function __construct( | ||
EntityTypeManagerInterface $entity_type_manager, | ||
Connection $database, | ||
AccountProxyInterface $current_user, | ||
MessengerInterface $messenger, | ||
DateFormatterInterface $date_formatter | ||
) { | ||
$this->entityTypeManager = $entity_type_manager; | ||
$this->database = $database; | ||
$this->currentUser = $current_user; | ||
$this->messenger = $messenger; | ||
$this->dateFormatter = $date_formatter; | ||
} | ||
|
||
/** | ||
* Implements callback_batch_operation() for our child addition batch. | ||
*/ | ||
public function batchOperation($delta, $info, array $values, &$context) { | ||
$transaction = $this->database->startTransaction(); | ||
|
||
try { | ||
$entities[] = $node = $this->getNode($info, $values); | ||
$entities[] = $this->createMedia($node, $info, $values); | ||
|
||
$context['results'] = array_merge_recursive($context['results'], [ | ||
'validation_violations' => $this->validationClassification($entities), | ||
]); | ||
$context['results']['count'] = ($context['results']['count'] ?? 0) + 1; | ||
} | ||
catch (HttpExceptionInterface $e) { | ||
$transaction->rollBack(); | ||
throw $e; | ||
} | ||
catch (\Exception $e) { | ||
$transaction->rollBack(); | ||
throw new HttpException(500, $e->getMessage(), $e); | ||
} | ||
} | ||
|
||
/** | ||
* Loads the file indicated. | ||
* | ||
* @param mixed $info | ||
* Widget values. | ||
* | ||
* @return \Drupal\file\FileInterface|null | ||
* The loaded file. | ||
* | ||
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException | ||
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException | ||
*/ | ||
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 mixed $info | ||
* Info from the widget used to create the request. | ||
* @param array $values | ||
* Additional form inputs. | ||
* | ||
* @return \Drupal\node\NodeInterface | ||
* The node to which to attach the created media. | ||
*/ | ||
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 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 | ||
* the media | ||
* - use: An array of the selected "media use" terms. | ||
* | ||
* @return \Drupal\media\MediaInterface | ||
* The created media entity. | ||
* | ||
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException | ||
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException | ||
* @throws \Drupal\Core\Entity\EntityStorageException | ||
*/ | ||
protected function createMedia(NodeInterface $node, $info, array $values) : MediaInterface { | ||
$taxonomy_term_storage = $this->entityTypeManager->getStorage('taxonomy_term'); | ||
|
||
// 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' => $this->getName($info, $values), | ||
IslandoraUtils::MEDIA_OF_FIELD => $node, | ||
IslandoraUtils::MEDIA_USAGE_FIELD => ($values['use'] ? | ||
$taxonomy_term_storage->loadMultiple($values['use']) : | ||
NULL), | ||
'uid' => $this->currentUser->id(), | ||
// XXX: Published... no constant? | ||
'status' => 1, | ||
], | ||
[ | ||
$field->getName() => [ | ||
$info, | ||
], | ||
] | ||
); | ||
$media = $this->entityTypeManager->getStorage('media')->create($media_values); | ||
if ($media->save() !== SAVED_NEW) { | ||
throw new \Exception("Failed to create media."); | ||
} | ||
|
||
return $media; | ||
} | ||
|
||
/** | ||
* Helper to bulk process validatable entities. | ||
* | ||
* @param array $entities | ||
* An array of entities to scan for validation violations. | ||
* | ||
* @return array | ||
* An associative array mapping entity type IDs to entity IDs to a count | ||
* of validation violations found on then given entity. | ||
*/ | ||
protected function validationClassification(array $entities) { | ||
$violations = []; | ||
|
||
foreach ($entities as $entity) { | ||
$entity_violations = $entity->validate(); | ||
if ($entity_violations->count() > 0) { | ||
$violations[$entity->getEntityTypeId()][$entity->id()] = $entity_violations->count(); | ||
} | ||
} | ||
|
||
return $violations; | ||
} | ||
|
||
/** | ||
* Implements callback_batch_finished() for our child addition batch. | ||
*/ | ||
public function batchProcessFinished($success, $results, $operations): void { | ||
if ($success) { | ||
foreach ($results['validation_violations'] ?? [] as $entity_type => $info) { | ||
foreach ($info as $id => $count) { | ||
$this->messenger->addWarning($this->formatPlural( | ||
$count, | ||
'1 validation error present in <a target="_blank" href=":uri">bulk created entity of type %type, with ID %id</a>.', | ||
'@count validation errors present in <a target="_blank" href=":uri">bulk created entity of type %type, with ID %id</a>.', | ||
[ | ||
'%type' => $entity_type, | ||
':uri' => Url::fromRoute("entity.{$entity_type}.canonical", [$entity_type => $id])->toString(), | ||
'%id' => $id, | ||
] | ||
)); | ||
} | ||
} | ||
} | ||
else { | ||
$this->messenger->addError($this->t('Encountered an error when processing.')); | ||
} | ||
} | ||
|
||
} |
157 changes: 157 additions & 0 deletions
157
src/Form/AddChildrenWizard/AbstractFileSelectionForm.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
<?php | ||
|
||
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; | ||
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; | ||
|
||
/** | ||
* Children addition wizard's second step. | ||
*/ | ||
abstract class AbstractFileSelectionForm extends FormBase { | ||
|
||
use WizardTrait; | ||
|
||
const BATCH_PROCESSOR = 'abstract.abstract'; | ||
|
||
/** | ||
* The current user. | ||
* | ||
* @var \Drupal\Core\Session\AccountProxyInterface|null | ||
*/ | ||
protected ?AccountProxyInterface $currentUser; | ||
|
||
/** | ||
* The batch processor service. | ||
* | ||
* @var \Drupal\islandora\Form\AddChildrenWizard\AbstractBatchProcessor|null | ||
*/ | ||
protected ?AbstractBatchProcessor $batchProcessor; | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public static function create(ContainerInterface $container): self { | ||
$instance = parent::create($container); | ||
|
||
$instance->entityTypeManager = $container->get('entity_type.manager'); | ||
$instance->widgetPluginManager = $container->get('plugin.manager.field.widget'); | ||
$instance->entityFieldManager = $container->get('entity_field.manager'); | ||
$instance->currentUser = $container->get('current_user'); | ||
|
||
$instance->batchProcessor = $container->get(static::BATCH_PROCESSOR); | ||
|
||
return $instance; | ||
} | ||
|
||
/** | ||
* Helper; get the media type, based off discovering from form state. | ||
* | ||
* @param \Drupal\Core\Form\FormStateInterface $form_state | ||
* The form state. | ||
* | ||
* @return \Drupal\media\MediaTypeInterface | ||
* The target media type. | ||
* | ||
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException | ||
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException | ||
*/ | ||
protected function getMediaTypeFromFormState(FormStateInterface $form_state): MediaTypeInterface { | ||
return $this->getMediaType($form_state->getTemporaryValue('wizard')); | ||
} | ||
|
||
/** | ||
* Helper; get field instance, based off discovering from form state. | ||
* | ||
* @param \Drupal\Core\Form\FormStateInterface $form_state | ||
* The form state. | ||
* | ||
* @return \Drupal\Core\Field\FieldDefinitionInterface | ||
* The field definition. | ||
*/ | ||
protected function getFieldFromFormState(FormStateInterface $form_state): FieldDefinitionInterface { | ||
$cached_values = $form_state->getTemporaryValue('wizard'); | ||
|
||
$field = $this->getField($cached_values); | ||
$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; | ||
} | ||
|
||
/** | ||
* Helper; get widget for the field, based on discovering from form state. | ||
* | ||
* @param \Drupal\Core\Form\FormStateInterface $form_state | ||
* The form state. | ||
* | ||
* @return \Drupal\Core\Field\WidgetInterface | ||
* The widget. | ||
*/ | ||
protected function getWidgetFromFormState(FormStateInterface $form_state): WidgetInterface { | ||
return $this->getWidget($this->getFieldFromFormState($form_state)); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function buildForm(array $form, FormStateInterface $form_state): array { | ||
// Using the media type selected in the previous step, grab the | ||
// media bundle's "source" field, and create a multi-file upload widget | ||
// for it, with the same kind of constraints. | ||
$field = $this->getFieldFromFormState($form_state); | ||
$items = FieldItemList::createInstance($field, $field->getName(), $this->getMediaTypeFromFormState($form_state)->getTypedData()); | ||
|
||
$form['#tree'] = TRUE; | ||
$form['#parents'] = []; | ||
$widget = $this->getWidgetFromFormState($form_state); | ||
$form['files'] = $widget->form( | ||
$items, | ||
$form, | ||
$form_state | ||
); | ||
|
||
return $form; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function submitForm(array &$form, FormStateInterface $form_state) { | ||
$cached_values = $form_state->getTemporaryValue('wizard'); | ||
|
||
$widget = $this->getWidgetFromFormState($form_state); | ||
$builder = (new BatchBuilder()) | ||
->setTitle($this->t('Bulk creating...')) | ||
->setInitMessage($this->t('Initializing...')) | ||
->setFinishCallback([$this->batchProcessor, 'batchProcessFinished']); | ||
$values = $form_state->getValue($this->getField($cached_values)->getName()); | ||
$massaged_values = $widget->massageFormValues($values, $form, $form_state); | ||
foreach ($massaged_values as $delta => $info) { | ||
$builder->addOperation( | ||
[$this->batchProcessor, 'batchOperation'], | ||
[$delta, $info, $cached_values] | ||
); | ||
} | ||
batch_set($builder->toArray()); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
<?php | ||
|
||
namespace Drupal\islandora\Form\AddChildrenWizard; | ||
|
||
use Drupal\Core\DependencyInjection\ClassResolverInterface; | ||
use Drupal\Core\Form\FormBuilderInterface; | ||
use Drupal\Core\Render\RendererInterface; | ||
use Drupal\Core\Routing\RouteMatchInterface; | ||
use Drupal\Core\Session\AccountProxyInterface; | ||
use Drupal\Core\TempStore\SharedTempStoreFactory; | ||
use Drupal\ctools\Wizard\FormWizardBase; | ||
use Drupal\islandora\IslandoraUtils; | ||
use Symfony\Component\EventDispatcher\EventDispatcherInterface; | ||
|
||
/** | ||
* Bulk children addition wizard base form. | ||
*/ | ||
abstract class AbstractForm extends FormWizardBase { | ||
|
||
const TEMPSTORE_ID = 'abstract.abstract'; | ||
const TYPE_SELECTION_FORM = MediaTypeSelectionForm::class; | ||
const FILE_SELECTION_FORM = AbstractFileSelectionForm::class; | ||
|
||
/** | ||
* The Islandora Utils service. | ||
* | ||
* @var \Drupal\islandora\IslandoraUtils | ||
*/ | ||
protected IslandoraUtils $utils; | ||
|
||
/** | ||
* The current node ID. | ||
* | ||
* @var mixed|null | ||
*/ | ||
protected $nodeId; | ||
|
||
/** | ||
* The current route match. | ||
* | ||
* @var \Drupal\Core\Routing\RouteMatchInterface | ||
*/ | ||
protected RouteMatchInterface $currentRoute; | ||
|
||
/** | ||
* The current user. | ||
* | ||
* @var \Drupal\Core\Session\AccountProxyInterface | ||
*/ | ||
protected AccountProxyInterface $currentUser; | ||
|
||
/** | ||
* Constructor. | ||
*/ | ||
public function __construct( | ||
SharedTempStoreFactory $tempstore, | ||
FormBuilderInterface $builder, | ||
ClassResolverInterface $class_resolver, | ||
EventDispatcherInterface $event_dispatcher, | ||
RouteMatchInterface $route_match, | ||
RendererInterface $renderer, | ||
$tempstore_id, | ||
AccountProxyInterface $current_user, | ||
$machine_name = NULL, | ||
$step = NULL | ||
) { | ||
parent::__construct($tempstore, $builder, $class_resolver, $event_dispatcher, $route_match, $renderer, $tempstore_id, | ||
$machine_name, $step); | ||
|
||
$this->nodeId = $this->routeMatch->getParameter('node'); | ||
$this->currentUser = $current_user; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public static function getParameters() : array { | ||
return array_merge( | ||
parent::getParameters(), | ||
[ | ||
'tempstore_id' => static::TEMPSTORE_ID, | ||
'current_user' => \Drupal::service('current_user'), | ||
] | ||
); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function getOperations($cached_values) { | ||
$ops = []; | ||
|
||
$ops['type_selection'] = [ | ||
'title' => $this->t('Type Selection'), | ||
'form' => static::TYPE_SELECTION_FORM, | ||
'values' => [ | ||
'node' => $this->nodeId, | ||
], | ||
]; | ||
$ops['file_selection'] = [ | ||
'title' => $this->t('Widget Input for Selected Type'), | ||
'form' => static::FILE_SELECTION_FORM, | ||
'values' => [ | ||
'node' => $this->nodeId, | ||
], | ||
]; | ||
|
||
return $ops; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function getNextParameters($cached_values) { | ||
return parent::getNextParameters($cached_values) + ['node' => $this->nodeId]; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function getPreviousParameters($cached_values) { | ||
return parent::getPreviousParameters($cached_values) + ['node' => $this->nodeId]; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
<?php | ||
|
||
namespace Drupal\islandora\Form\AddChildrenWizard; | ||
|
||
use Drupal\Core\Access\AccessResult; | ||
use Drupal\Core\Access\AccessResultInterface; | ||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface; | ||
use Drupal\Core\Routing\RouteMatch; | ||
use Drupal\islandora\IslandoraUtils; | ||
use Symfony\Component\DependencyInjection\ContainerInterface; | ||
|
||
/** | ||
* Access checker. | ||
* | ||
* The _wizard/_form route enhancers do not really allow for access checking | ||
* things, so let's roll it separately for now. | ||
*/ | ||
class Access implements ContainerInjectionInterface { | ||
|
||
/** | ||
* The Islandora utils service. | ||
* | ||
* @var \Drupal\islandora\IslandoraUtils | ||
*/ | ||
protected IslandoraUtils $utils; | ||
|
||
/** | ||
* Constructor. | ||
*/ | ||
public function __construct(IslandoraUtils $utils) { | ||
$this->utils = $utils; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public static function create(ContainerInterface $container) : self { | ||
return new static( | ||
$container->get('islandora.utils') | ||
); | ||
} | ||
|
||
/** | ||
* Check if the user can create any "Islandora" nodes and media. | ||
* | ||
* @param \Drupal\Core\Routing\RouteMatch $route_match | ||
* The current routing match. | ||
* | ||
* @return \Drupal\Core\Access\AccessResultInterface | ||
* Whether we can or cannot show the "thing". | ||
*/ | ||
public function childAccess(RouteMatch $route_match) : AccessResultInterface { | ||
return AccessResult::allowedIf($this->utils->canCreateIslandoraEntity('node', 'node_type')) | ||
->andIf($this->mediaAccess($route_match)); | ||
|
||
} | ||
|
||
/** | ||
* Check if the user can create any "Islandora" media. | ||
* | ||
* @param \Drupal\Core\Routing\RouteMatch $route_match | ||
* The current routing match. | ||
* | ||
* @return \Drupal\Core\Access\AccessResultInterface | ||
* Whether we can or cannot show the "thing". | ||
*/ | ||
public function mediaAccess(RouteMatch $route_match) : AccessResultInterface { | ||
return AccessResult::allowedIf($this->utils->canCreateIslandoraEntity('media', 'media_type')); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
<?php | ||
|
||
namespace Drupal\islandora\Form\AddChildrenWizard; | ||
|
||
use Drupal\islandora\IslandoraUtils; | ||
use Drupal\node\NodeInterface; | ||
|
||
/** | ||
* Children addition batch processor. | ||
*/ | ||
class ChildBatchProcessor extends AbstractBatchProcessor { | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
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']); | ||
|
||
// 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' => $this->getName($info, $values), | ||
IslandoraUtils::MEMBER_OF_FIELD => $parent, | ||
'uid' => $this->currentUser->id(), | ||
'status' => NodeInterface::PUBLISHED, | ||
IslandoraUtils::MODEL_FIELD => ($values['model'] ? | ||
$taxonomy_term_storage->load($values['model']) : | ||
NULL), | ||
]); | ||
|
||
if ($node->save() !== SAVED_NEW) { | ||
throw new \Exception("Failed to create node."); | ||
} | ||
|
||
return $node; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function batchProcessFinished($success, $results, $operations): void { | ||
if ($success) { | ||
$this->messenger->addMessage($this->formatPlural( | ||
$results['count'], | ||
'Added 1 child node.', | ||
'Added @count child nodes.' | ||
)); | ||
} | ||
|
||
parent::batchProcessFinished($success, $results, $operations); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?php | ||
|
||
namespace Drupal\islandora\Form\AddChildrenWizard; | ||
|
||
use Drupal\Core\Form\FormStateInterface; | ||
use Drupal\Core\Url; | ||
|
||
/** | ||
* Children addition wizard's second step. | ||
*/ | ||
class ChildFileSelectionForm extends AbstractFileSelectionForm { | ||
|
||
public const BATCH_PROCESSOR = 'islandora.upload_children.batch_processor'; | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function getFormId() { | ||
return 'islandora_add_children_wizard_file_selection'; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function submitForm(array &$form, FormStateInterface $form_state) { | ||
parent::submitForm($form, $form_state); | ||
|
||
$cached_values = $form_state->getTemporaryValue('wizard'); | ||
$form_state->setRedirectUrl(Url::fromUri("internal:/node/{$cached_values['node']}/members")); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<?php | ||
|
||
namespace Drupal\islandora\Form\AddChildrenWizard; | ||
|
||
/** | ||
* Bulk children addition wizard base form. | ||
*/ | ||
class ChildForm extends AbstractForm { | ||
|
||
const TEMPSTORE_ID = 'islandora.upload_children'; | ||
const TYPE_SELECTION_FORM = ChildTypeSelectionForm::class; | ||
const FILE_SELECTION_FORM = ChildFileSelectionForm::class; | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function getMachineName() { | ||
return strtr("islandora_add_children_wizard__{userid}__{nodeid}", [ | ||
'{userid}' => $this->currentUser->id(), | ||
'{nodeid}' => $this->nodeId, | ||
]); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
<?php | ||
|
||
namespace Drupal\islandora\Form\AddChildrenWizard; | ||
|
||
use Drupal\Core\Cache\CacheableMetadata; | ||
use Drupal\Core\Form\FormStateInterface; | ||
use Drupal\islandora\IslandoraUtils; | ||
|
||
/** | ||
* Children addition wizard's first step. | ||
*/ | ||
class ChildTypeSelectionForm extends MediaTypeSelectionForm { | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function getFormId() : string { | ||
return 'islandora_add_children_type_selection'; | ||
} | ||
|
||
/** | ||
* Memoization for ::getNodeBundleOptions(). | ||
* | ||
* @var array|null | ||
*/ | ||
protected ?array $nodeBundleOptions = NULL; | ||
|
||
/** | ||
* Indicate presence of model field on node bundles. | ||
* | ||
* Populated as a side effect of ::getNodeBundleOptions(). | ||
* | ||
* @var array|null | ||
*/ | ||
protected ?array $nodeBundleHasModelField = NULL; | ||
|
||
/** | ||
* Helper; get the node bundle options available to the current user. | ||
* | ||
* @return array | ||
* An associative array mapping node bundle machine names to their human- | ||
* readable labels. | ||
*/ | ||
protected function getNodeBundleOptions() : array { | ||
if ($this->nodeBundleOptions === NULL) { | ||
$this->nodeBundleOptions = []; | ||
$this->nodeBundleHasModelField = []; | ||
|
||
$access_handler = $this->entityTypeManager->getAccessControlHandler('node'); | ||
foreach ($this->entityTypeBundleInfo->getBundleInfo('node') as $bundle => $info) { | ||
$access = $access_handler->createAccess( | ||
$bundle, | ||
NULL, | ||
[], | ||
TRUE | ||
); | ||
$this->cacheableMetadata->addCacheableDependency($access); | ||
if (!$access->isAllowed()) { | ||
continue; | ||
} | ||
$this->nodeBundleOptions[$bundle] = $info['label']; | ||
$fields = $this->entityFieldManager->getFieldDefinitions('node', $bundle); | ||
$this->nodeBundleHasModelField[$bundle] = array_key_exists(IslandoraUtils::MODEL_FIELD, $fields); | ||
} | ||
} | ||
|
||
return $this->nodeBundleOptions; | ||
} | ||
|
||
/** | ||
* Generates a mapping of taxonomy term IDs to their names. | ||
* | ||
* @return \Generator | ||
* The mapping of taxonomy term IDs to their names. | ||
* | ||
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException | ||
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException | ||
*/ | ||
protected function getModelOptions() : \Generator { | ||
$terms = $this->entityTypeManager->getStorage('taxonomy_term') | ||
->loadTree('islandora_models', 0, NULL, TRUE); | ||
foreach ($terms as $term) { | ||
yield $term->id() => $term->getName(); | ||
} | ||
} | ||
|
||
/** | ||
* Helper; map node bundles supporting the "has model" field, for #states. | ||
* | ||
* @return \Generator | ||
* Yields associative array mapping the string 'value' to the bundles which | ||
* have the given field. | ||
*/ | ||
protected function mapModelStates() : \Generator { | ||
$this->getNodeBundleOptions(); | ||
foreach (array_keys(array_filter($this->nodeBundleHasModelField)) as $bundle) { | ||
yield ['value' => $bundle]; | ||
} | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function buildForm(array $form, FormStateInterface $form_state) { | ||
$this->cacheableMetadata = CacheableMetadata::createFromRenderArray($form) | ||
->addCacheContexts([ | ||
'url', | ||
'url.query_args', | ||
]); | ||
$cached_values = $form_state->getTemporaryValue('wizard'); | ||
|
||
$form['bundle'] = [ | ||
'#type' => 'select', | ||
'#title' => $this->t('Content Type'), | ||
'#description' => $this->t('Each child created will have this content type.'), | ||
'#empty_value' => '', | ||
'#default_value' => $cached_values['bundle'] ?? '', | ||
'#options' => $this->getNodeBundleOptions(), | ||
'#required' => TRUE, | ||
]; | ||
|
||
$model_states = iterator_to_array($this->mapModelStates()); | ||
$form['model'] = [ | ||
'#type' => 'select', | ||
'#title' => $this->t('Model'), | ||
'#description' => $this->t('Each child will be tagged with this model.'), | ||
'#options' => iterator_to_array($this->getModelOptions()), | ||
'#empty_value' => '', | ||
'#default_value' => $cached_values['model'] ?? '', | ||
'#states' => [ | ||
'visible' => [ | ||
':input[name="bundle"]' => $model_states, | ||
], | ||
'required' => [ | ||
':input[name="bundle"]' => $model_states, | ||
], | ||
], | ||
]; | ||
|
||
$this->cacheableMetadata->applyTo($form); | ||
return parent::buildForm($form, $form_state); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
protected static function keysToSave() : array { | ||
return array_merge( | ||
parent::keysToSave(), | ||
[ | ||
'bundle', | ||
'model', | ||
] | ||
); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
<?php | ||
|
||
namespace Drupal\islandora\Form\AddChildrenWizard; | ||
|
||
use Drupal\Core\Entity\EntityFieldManagerInterface; | ||
use Drupal\Core\Field\FieldDefinitionInterface; | ||
|
||
/** | ||
* Field lookup helper trait. | ||
*/ | ||
trait FieldTrait { | ||
|
||
use MediaTypeTrait; | ||
|
||
/** | ||
* The entity field manager service. | ||
* | ||
* @var \Drupal\Core\Entity\EntityFieldManagerInterface|null | ||
*/ | ||
protected ?EntityFieldManagerInterface $entityFieldManager = NULL; | ||
|
||
/** | ||
* Helper; get field instance, given our required values. | ||
* | ||
* @param array $values | ||
* See ::getMediaType() for which values are required. | ||
* | ||
* @return \Drupal\Core\Field\FieldDefinitionInterface | ||
* The target field. | ||
* | ||
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException | ||
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException | ||
*/ | ||
protected function getField(array $values): FieldDefinitionInterface { | ||
$media_type = $this->getMediaType($values); | ||
$media_source = $media_type->getSource(); | ||
$source_field = $media_source->getSourceFieldDefinition($media_type); | ||
|
||
$fields = $this->entityFieldManager()->getFieldDefinitions('media', $media_type->id()); | ||
|
||
return $fields[$source_field->getFieldStorageDefinition()->getName()] ?? | ||
$media_source->createSourceField($media_type); | ||
} | ||
|
||
/** | ||
* Lazy-initialization of the entity field manager service. | ||
* | ||
* @return \Drupal\Core\Entity\EntityFieldManagerInterface | ||
* The entity field manager service. | ||
*/ | ||
protected function entityFieldManager() : EntityFieldManagerInterface { | ||
if ($this->entityFieldManager === NULL) { | ||
$this->setEntityFieldManager(\Drupal::service('entity_field.manager')); | ||
} | ||
return $this->entityFieldManager; | ||
} | ||
|
||
/** | ||
* Setter for entity field manager. | ||
*/ | ||
public function setEntityFieldManager(EntityFieldManagerInterface $entity_field_manager) : self { | ||
$this->entityFieldManager = $entity_field_manager; | ||
return $this; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
<?php | ||
|
||
namespace Drupal\islandora\Form\AddChildrenWizard; | ||
|
||
use Drupal\node\NodeInterface; | ||
|
||
/** | ||
* Media addition batch processor. | ||
*/ | ||
class MediaBatchProcessor extends AbstractBatchProcessor { | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
protected function getNode($info, array $values) : NodeInterface { | ||
return $this->entityTypeManager->getStorage('node')->load($values['node']); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function batchProcessFinished($success, $results, $operations): void { | ||
if ($success) { | ||
$this->messenger->addMessage($this->formatPlural( | ||
$results['count'], | ||
'Added 1 media.', | ||
'Added @count media.' | ||
)); | ||
} | ||
|
||
parent::batchProcessFinished($success, $results, $operations); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?php | ||
|
||
namespace Drupal\islandora\Form\AddChildrenWizard; | ||
|
||
use Drupal\Core\Form\FormStateInterface; | ||
use Drupal\Core\Url; | ||
|
||
/** | ||
* Media addition wizard's second step. | ||
*/ | ||
class MediaFileSelectionForm extends AbstractFileSelectionForm { | ||
|
||
public const BATCH_PROCESSOR = 'islandora.upload_media.batch_processor'; | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function getFormId() { | ||
return 'islandora_add_media_wizard_file_selection'; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function submitForm(array &$form, FormStateInterface $form_state) { | ||
parent::submitForm($form, $form_state); | ||
|
||
$cached_values = $form_state->getTemporaryValue('wizard'); | ||
$form_state->setRedirectUrl(Url::fromUri("internal:/node/{$cached_values['node']}/media")); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<?php | ||
|
||
namespace Drupal\islandora\Form\AddChildrenWizard; | ||
|
||
/** | ||
* Bulk children addition wizard base form. | ||
*/ | ||
class MediaForm extends AbstractForm { | ||
|
||
const TEMPSTORE_ID = 'islandora.upload_media'; | ||
const TYPE_SELECTION_FORM = MediaTypeSelectionForm::class; | ||
const FILE_SELECTION_FORM = MediaFileSelectionForm::class; | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function getMachineName() { | ||
return strtr("islandora_add_media_wizard__{userid}__{nodeid}", [ | ||
'{userid}' => $this->currentUser->id(), | ||
'{nodeid}' => $this->nodeId, | ||
]); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,227 @@ | ||
<?php | ||
|
||
namespace Drupal\islandora\Form\AddChildrenWizard; | ||
|
||
use Drupal\Core\Cache\CacheableMetadata; | ||
use Drupal\Core\Entity\EntityFieldManagerInterface; | ||
use Drupal\Core\Entity\EntityTypeBundleInfoInterface; | ||
use Drupal\Core\Entity\EntityTypeManagerInterface; | ||
use Drupal\Core\Form\FormBase; | ||
use Drupal\Core\Form\FormStateInterface; | ||
use Drupal\islandora\IslandoraUtils; | ||
use Symfony\Component\DependencyInjection\ContainerInterface; | ||
|
||
/** | ||
* Children addition wizard's first step. | ||
*/ | ||
class MediaTypeSelectionForm extends FormBase { | ||
|
||
/** | ||
* Cacheable metadata that is instantiated and used internally. | ||
* | ||
* @var \Drupal\Core\Cache\CacheableMetadata|null | ||
*/ | ||
protected ?CacheableMetadata $cacheableMetadata = NULL; | ||
|
||
/** | ||
* The entity type bundle info service. | ||
* | ||
* @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface|null | ||
*/ | ||
protected ?EntityTypeBundleInfoInterface $entityTypeBundleInfo; | ||
|
||
/** | ||
* The entity type manager service. | ||
* | ||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface|null | ||
*/ | ||
protected ?EntityTypeManagerInterface $entityTypeManager; | ||
|
||
/** | ||
* The entity field manager service. | ||
* | ||
* @var \Drupal\Core\Entity\EntityFieldManagerInterface|null | ||
*/ | ||
protected ?EntityFieldManagerInterface $entityFieldManager; | ||
|
||
/** | ||
* The Islandora Utils service. | ||
* | ||
* @var \Drupal\islandora\IslandoraUtils|null | ||
*/ | ||
protected ?IslandoraUtils $utils; | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
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; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function getFormId() : string { | ||
return 'islandora_add_media_type_selection'; | ||
} | ||
|
||
/** | ||
* Memoization for ::getMediaBundleOptions(). | ||
* | ||
* @var array|null | ||
*/ | ||
protected ?array $mediaBundleOptions = NULL; | ||
|
||
/** | ||
* Indicate presence of usage field on media bundles. | ||
* | ||
* Populated as a side effect in ::getMediaBundleOptions(). | ||
* | ||
* @var array|null | ||
*/ | ||
protected ?array $mediaBundleUsageField = NULL; | ||
|
||
/** | ||
* Helper; get options for media types. | ||
* | ||
* @return array | ||
* An associative array mapping the machine name of the media type to its | ||
* human-readable label. | ||
*/ | ||
protected function getMediaBundleOptions() : array { | ||
if ($this->mediaBundleOptions === NULL) { | ||
$this->mediaBundleOptions = []; | ||
$this->mediaBundleUsageField = []; | ||
|
||
$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, | ||
[], | ||
TRUE | ||
); | ||
$this->cacheableMetadata->addCacheableDependency($access); | ||
if (!$access->isAllowed()) { | ||
continue; | ||
} | ||
$this->mediaBundleOptions[$bundle] = $info['label']; | ||
$fields = $this->entityFieldManager->getFieldDefinitions('media', $bundle); | ||
$this->mediaBundleUsageField[$bundle] = array_key_exists(IslandoraUtils::MEDIA_USAGE_FIELD, $fields); | ||
} | ||
} | ||
|
||
return $this->mediaBundleOptions; | ||
} | ||
|
||
/** | ||
* Helper; list the terms of the "islandora_media_use" vocabulary. | ||
* | ||
* @return \Generator | ||
* Generates term IDs as keys mapping to term names. | ||
* | ||
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException | ||
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException | ||
*/ | ||
protected function getMediaUseOptions() : \Generator { | ||
/** @var \Drupal\taxonomy\TermInterface[] $terms */ | ||
$terms = $this->entityTypeManager->getStorage('taxonomy_term') | ||
->loadTree('islandora_media_use', 0, NULL, TRUE); | ||
|
||
foreach ($terms as $term) { | ||
yield $term->id() => $term->getName(); | ||
} | ||
} | ||
|
||
/** | ||
* Helper; map media types supporting the usage field for use with #states. | ||
* | ||
* @return \Generator | ||
* Yields associative array mapping the string 'value' to the bundles which | ||
* have the given field. | ||
*/ | ||
protected function mapUseStates(): \Generator { | ||
$this->getMediaBundleOptions(); | ||
foreach (array_keys(array_filter($this->mediaBundleUsageField)) as $bundle) { | ||
yield ['value' => $bundle]; | ||
} | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function buildForm(array $form, FormStateInterface $form_state) { | ||
$this->cacheableMetadata = CacheableMetadata::createFromRenderArray($form) | ||
->addCacheContexts([ | ||
'url', | ||
'url.query_args', | ||
]); | ||
$cached_values = $form_state->getTemporaryValue('wizard'); | ||
|
||
$form['media_type'] = [ | ||
'#type' => 'select', | ||
'#title' => $this->t('Media Type'), | ||
'#description' => $this->t('Each media created will have this type.'), | ||
'#empty_value' => '', | ||
'#default_value' => $cached_values['media_type'] ?? '', | ||
'#options' => $this->getMediaBundleOptions(), | ||
'#required' => TRUE, | ||
]; | ||
$use_states = iterator_to_array($this->mapUseStates()); | ||
$form['use'] = [ | ||
'#type' => 'checkboxes', | ||
'#title' => $this->t('Usage'), | ||
'#description' => $this->t('Defined by <a target="_blank" href=":url">Portland Common Data Model: Use Extension</a>. "Original File" will trigger creation of derivatives.', [ | ||
':url' => 'https://pcdm.org/2015/05/12/use', | ||
]), | ||
'#options' => iterator_to_array($this->getMediaUseOptions()), | ||
'#default_value' => $cached_values['use'] ?? [], | ||
'#states' => [ | ||
'visible' => [ | ||
':input[name="media_type"]' => $use_states, | ||
], | ||
'required' => [ | ||
':input[name="media_type"]' => $use_states, | ||
], | ||
], | ||
]; | ||
|
||
$this->cacheableMetadata->applyTo($form); | ||
return $form; | ||
} | ||
|
||
/** | ||
* Helper; enumerate keys to persist in form state. | ||
* | ||
* @return string[] | ||
* The keys to be persisted in our temp value in form state. | ||
*/ | ||
protected static function keysToSave() : array { | ||
return [ | ||
'media_type', | ||
'use', | ||
]; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function submitForm(array &$form, FormStateInterface $form_state) { | ||
$cached_values = $form_state->getTemporaryValue('wizard'); | ||
foreach (static::keysToSave() as $key) { | ||
$cached_values[$key] = $form_state->getValue($key); | ||
} | ||
$form_state->setTemporaryValue('wizard', $cached_values); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
<?php | ||
|
||
namespace Drupal\islandora\Form\AddChildrenWizard; | ||
|
||
use Drupal\Core\Entity\EntityTypeManagerInterface; | ||
use Drupal\media\MediaTypeInterface; | ||
|
||
/** | ||
* Media type lookup helper trait. | ||
*/ | ||
trait MediaTypeTrait { | ||
|
||
/** | ||
* The entity type manager service. | ||
* | ||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface|null | ||
*/ | ||
protected ?EntityTypeManagerInterface $entityTypeManager = NULL; | ||
|
||
/** | ||
* Helper; get media type, given our required values. | ||
* | ||
* @param array $values | ||
* An associative array which must contain at least: | ||
* - media_type: The machine name of the media type to load. | ||
* | ||
* @return \Drupal\media\MediaTypeInterface | ||
* The loaded media type. | ||
* | ||
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException | ||
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException | ||
*/ | ||
protected function getMediaType(array $values): MediaTypeInterface { | ||
return $this->entityTypeManager()->getStorage('media_type')->load($values['media_type']); | ||
} | ||
|
||
/** | ||
* Lazy-initialization of the entity type manager service. | ||
* | ||
* @return \Drupal\Core\Entity\EntityTypeManagerInterface | ||
* The entity type manager service. | ||
*/ | ||
protected function entityTypeManager() : EntityTypeManagerInterface { | ||
if ($this->entityTypeManager === NULL) { | ||
$this->setEntityTypeManager(\Drupal::service('entity_type.manager')); | ||
} | ||
return $this->entityTypeManager; | ||
} | ||
|
||
/** | ||
* Setter for the entity type manager service. | ||
*/ | ||
public function setEntityTypeManager(EntityTypeManagerInterface $entity_type_manager) : self { | ||
$this->entityTypeManager = $entity_type_manager; | ||
return $this; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
<?php | ||
|
||
namespace Drupal\islandora\Form\AddChildrenWizard; | ||
|
||
use Drupal\Component\Plugin\PluginManagerInterface; | ||
use Drupal\Core\Field\FieldDefinitionInterface; | ||
use Drupal\Core\Field\WidgetInterface; | ||
|
||
/** | ||
* Wizard/widget lookup helper trait. | ||
*/ | ||
trait WizardTrait { | ||
|
||
use FieldTrait; | ||
|
||
/** | ||
* The widget plugin manager service. | ||
* | ||
* @var \Drupal\Core\Field\WidgetPluginManager | ||
*/ | ||
protected PluginManagerInterface $widgetPluginManager; | ||
|
||
/** | ||
* Helper; get the base widget for the given field. | ||
* | ||
* @param \Drupal\Core\Field\FieldDefinitionInterface $field | ||
* The field for which get obtain the widget. | ||
* | ||
* @return \Drupal\Core\Field\WidgetInterface | ||
* The widget. | ||
*/ | ||
protected function getWidget(FieldDefinitionInterface $field): WidgetInterface { | ||
return $this->widgetPluginManager->getInstance([ | ||
'field_definition' => $field, | ||
'form_mode' => 'default', | ||
'prepare' => TRUE, | ||
]); | ||
} | ||
|
||
} |