View source
<?php
namespace Drupal\media_directories_ui\Form;
use Drupal\Component\Render\PlainTextOutput;
use Drupal\Component\Utility\Environment;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\CloseModalDialogCommand;
use Drupal\Core\Ajax\OpenModalDialogCommand;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\TypedData\FieldItemDataDefinition;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Utility\Token;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\Theme\ThemeManagerInterface;
use Drupal\file\Plugin\Field\FieldType\FileItem;
use Drupal\media\MediaInterface;
use Drupal\media\MediaTypeInterface;
use Drupal\media_directories_ui\Ajax\RefreshDirectoryTree;
use Symfony\Component\DependencyInjection\ContainerInterface;
abstract class AddMediaFormBase extends FormBase {
protected $entityTypeManager;
protected $currentUser;
protected $token;
protected $themeManager;
public function __construct(EntityTypeManagerInterface $entity_type_manager, AccountProxyInterface $current_user, Token $token, ThemeManagerInterface $theme_manager) {
$this->entityTypeManager = $entity_type_manager;
$this->currentUser = $current_user;
$this->token = $token;
$this->themeManager = $theme_manager;
}
public static function create(ContainerInterface $container) {
return new static($container
->get('entity_type.manager'), $container
->get('current_user'), $container
->get('token'), $container
->get('theme.manager'));
}
public function getFormId() {
return 'media_directories_add_form';
}
protected function getMediaType(FormStateInterface $form_state) {
if (!$form_state
->get('media_type')) {
throw new \InvalidArgumentException("The media type does not exist.");
}
return $form_state
->get('media_type');
}
protected function getDirectory(FormStateInterface $form_state) {
$directory_id = $form_state
->get('active_directory');
if (empty($directory_id)) {
return MEDIA_DIRECTORY_ROOT;
}
return (int) $directory_id;
}
protected function getTargetBundles(FormStateInterface $form_state) {
$bundles = $form_state
->get('target_bundles');
return $bundles;
}
protected function getSelectionMode(FormStateInterface $form_state) {
$selection_mode = $form_state
->get('selection_mode');
return $selection_mode;
}
protected function getCardinality(FormStateInterface $form_state) {
$cardinality = intval($form_state
->get('cardinality'));
if ($cardinality == 0) {
return -1;
}
return $cardinality;
}
protected function getUploadLocation(array $settings) {
$destination = trim($settings['file_directory'], '/');
$destination = PlainTextOutput::renderFromHtml($this->token
->replace($destination, []));
return $settings['uri_scheme'] . '://' . $destination;
}
protected function getUploadValidators(MediaTypeInterface $media_type) {
$upload_validators = $this
->createFileItem($media_type)
->getUploadValidators();
$source_field = $media_type
->getSource()
->getConfiguration()['source_field'];
$field_config = $this->entityTypeManager
->getStorage('field_config')
->load('media.' . $media_type
->id() . '.' . $source_field);
if ($field_config
->getSetting('max_resolution') || $field_config
->getSetting('min_resolution')) {
$upload_validators['file_validate_is_image'] = [];
$upload_validators['file_validate_image_resolution'] = [
$field_config
->getSetting('max_resolution'),
$field_config
->getSetting('min_resolution'),
];
}
if (!isset($upload_validators['file_validate_size'])) {
$max_filesize = Environment::getUploadMaxSize();
$upload_validators['file_validate_size'] = [
$max_filesize,
];
}
return $upload_validators;
}
public function buildForm(array $form, FormStateInterface $form_state) {
$form['#prefix'] = '<div id="media-library-add-form-wrapper" class="media-library-add-form-wrapper">';
$form['#suffix'] = '</div>';
$theme_name = $this->themeManager
->getActiveTheme()
->getName();
if (in_array($theme_name, [
'claro',
'gin',
])) {
$form['#attached']['library'][] = 'claro/media_library.theme';
}
else {
$form['#attached']['library'][] = 'seven/media_library';
}
$form['status_messages'] = [
'#type' => 'status_messages',
];
$form['#attributes']['class'] = [
'media-library-add-form',
'js-media-library-add-form',
];
$added_media = $form_state
->get('media');
$form['active_directory'] = [
'#type' => 'hidden',
'#value' => $this
->getDirectory($form_state),
];
$media_type = $form_state
->get('media_type');
$form['media_type'] = [
'#type' => 'hidden',
'#value' => is_object($media_type) ? $media_type
->id() : $media_type,
];
$target_bundles = $this
->getTargetBundles($form_state);
$form['target_bundles'] = [
'#tree' => TRUE,
];
foreach ($target_bundles as $bundle) {
$form['target_bundles'][$bundle] = [
'#type' => 'hidden',
'#value' => $bundle,
];
}
$form['selection_mode'] = [
'#type' => 'hidden',
'#value' => $this
->getSelectionMode($form_state),
];
$form['cardinality'] = [
'#type' => 'hidden',
'#value' => $this
->getCardinality($form_state),
];
if (empty($added_media)) {
$form['#attributes']['class'][] = 'media-library-add-form--without-input';
$form = $this
->buildInputElement($form, $form_state);
}
else {
$form['#attributes']['class'][] = 'media-library-add-form--with-input';
$form['media'] = [
'#type' => 'container',
'#attributes' => [
'class' => [
'media-library-add-form__added-media',
],
'aria-label' => $this
->t('Added media items'),
'role' => 'list',
'tabindex' => '-1',
],
];
$form['media']['description'] = [
'#type' => 'html_tag',
'#tag' => 'p',
'#value' => $this
->formatPlural(count($added_media), 'The media item has been created but has not yet been saved. Fill in any required fields and save to add it to the media library.', 'The media items have been created but have not yet been saved. Fill in any required fields and save to add them to the media library.'),
'#attributes' => [
'class' => [
'media-library-add-form__description',
],
],
];
foreach ($added_media as $delta => $media) {
$form['media'][$delta] = $this
->buildEntityFormElement($media, $form, $form_state, $delta);
}
$form['actions'] = $this
->buildActions($form, $form_state);
}
$form['current_selection'] = [
'#type' => 'hidden',
'#default_value' => '',
'#attributes' => [
'class' => [
'js-media-library-add-form-current-selection',
],
],
];
return $form;
}
protected abstract function buildInputElement(array $form, FormStateInterface $form_state);
public function submitForm(array &$form, FormStateInterface $form_state) {
$added_media = $form_state
->get('media');
$tmp_tid_mids = [];
$all_mids = [];
foreach ($added_media as $delta => $media) {
EntityFormDisplay::collectRenderDisplay($media, 'media_library')
->extractFormValues($media, $form['media'][$delta]['fields'], $form_state);
$media
->save();
$tmp_tid_mids[isset($media
->get('directory')->target_id) ? $media
->get('directory')->target_id : MEDIA_DIRECTORY_ROOT][] = $media
->id();
$all_mids[] = $media
->id();
}
$tid_holding_most_mids = -1;
foreach ($tmp_tid_mids as $tid => $mids) {
if (!isset($tmp_tid_mids[$tid_holding_most_mids]) || count($tmp_tid_mids[$tid_holding_most_mids]) < count($tmp_tid_mids[$tid])) {
$tid_holding_most_mids = $tid;
}
}
$cardinality = $this
->getCardinality($form_state);
if ($form_state
->get('selection_mode') != 'keep') {
$newly_added_media_ids = $tmp_tid_mids[$tid_holding_most_mids];
if (count($newly_added_media_ids) < count($all_mids)) {
$this
->messenger()
->addStatus($this
->t('You uploaded medias to different folders. Only medias in the current folder (having the most uploaded media count) are selected.'));
}
if ($cardinality > -1 && $cardinality < count($newly_added_media_ids)) {
$newly_added_media_ids = array_slice($newly_added_media_ids, 0, $cardinality);
$this
->messenger()
->addStatus($this
->formatPlural(count($cardinality), 'As this field only accepts one media, only the first one uploaded is selected.', 'You uploaded more medias then allowed for the field, only the first @count are selected.'));
}
$form_state
->setValue('newly_added_media_ids', $newly_added_media_ids);
}
else {
if ($cardinality > -1 && $cardinality < count($all_mids)) {
$newly_added_media_ids = array_slice($all_mids, 0, $cardinality);
$this
->messenger()
->addStatus($this
->formatPlural(count($cardinality), 'As this field only accepts one media, only the first one uploaded is selected.', 'You uploaded more medias then allowed for the field, only the first @count are selected.'));
}
$form_state
->setValue('newly_added_media_ids', $all_mids);
}
$form_state
->setValue('most_choosen_directory_tid', $tid_holding_most_mids);
}
protected function buildEntityFormElement(MediaInterface $media, array $form, FormStateInterface $form_state, $delta) {
$parents = isset($form['#parents']) ? $form['#parents'] : '';
$id_suffix = $parents ? '-' . implode('-', $parents) : '';
$element = [
'#type' => 'container',
'#attributes' => [
'class' => [
'media-library-add-form__media',
],
'aria-label' => $media
->getName(),
'role' => 'listitem',
'tabindex' => '-1',
'data-media-library-added-delta' => $delta,
],
'preview' => [
'#type' => 'container',
'#weight' => 10,
'#attributes' => [
'class' => [
'media-library-add-form__preview',
],
],
],
'fields' => [
'#type' => 'container',
'#weight' => 20,
'#attributes' => [
'class' => [
'media-library-add-form__fields',
],
],
'#parents' => [
'media',
$delta,
'fields',
],
],
'remove_button' => [
'#type' => 'submit',
'#value' => $this
->t('Remove'),
'#name' => 'media-' . $delta . '-remove-button' . $id_suffix,
'#weight' => 30,
'#attributes' => [
'class' => [
'media-library-add-form__remove-button',
],
'aria-label' => $this
->t('Remove @label', [
'@label' => $media
->getName(),
]),
],
'#ajax' => [
'callback' => '::updateFormCallback',
'wrapper' => 'media-library-add-form-wrapper',
'message' => $this
->t('Removing @label.', [
'@label' => $media
->getName(),
]),
],
'#submit' => [
'::removeButtonSubmit',
],
'#limit_validation_errors' => [],
],
];
$source = $media
->getSource();
$plugin_definition = $source
->getPluginDefinition();
if ($thumbnail_uri = $source
->getMetadata($media, $plugin_definition['thumbnail_uri_metadata_attribute'])) {
$element['preview']['thumbnail'] = [
'#theme' => 'image_style',
'#style_name' => 'media_library',
'#uri' => $thumbnail_uri,
];
}
$form_display = EntityFormDisplay::collectRenderDisplay($media, 'media_library');
if (!$form_display
->getComponent('name')) {
$element['fields']['name'] = [
'#type' => 'item',
'#title' => $this
->t('Name'),
'#markup' => $media
->getName(),
];
}
$form_display
->buildForm($media, $element['fields'], $form_state);
$type = $this->entityTypeManager
->getStorage('media_type')
->load($media
->bundle());
$source_field_name = $this
->getSourceFieldName($type);
if (isset($element['fields'][$source_field_name])) {
$element['fields'][$source_field_name]['#attributes']['class'][] = 'media-library-add-form__source-field';
$element['fields'][$source_field_name]['widget'][0]['#process'][] = [
static::class,
'hideExtraSourceFieldComponents',
];
}
$element['fields']['#source_field_name'] = $source_field_name;
if (isset($element['fields']['revision_log_message'])) {
$element['fields']['revision_log_message']['#access'] = FALSE;
}
return $element;
}
public static function hideExtraSourceFieldComponents(array $element, FormStateInterface $form_state, array $form) {
if (!empty($element['remove_button'])) {
$element['remove_button']['#access'] = FALSE;
}
if (!empty($element['preview'])) {
$element['preview']['#access'] = FALSE;
}
$element['#title_display'] = 'none';
$element['#description_display'] = 'none';
foreach ($element['#files'] as $file) {
$element['file_' . $file
->id()]['filename']['#access'] = FALSE;
}
return $element;
}
protected function getSourceFieldName(MediaTypeInterface $media_type) {
return $media_type
->getSource()
->getSourceFieldDefinition($media_type)
->getName();
}
protected function createFileItem(MediaTypeInterface $media_type) {
$field_definition = $media_type
->getSource()
->getSourceFieldDefinition($media_type);
$data_definition = FieldItemDataDefinition::create($field_definition);
return new FileItem($data_definition);
}
protected function buildActions(array $form, FormStateInterface $form_state) {
return [
'#type' => 'actions',
'save_select' => [
'#type' => 'submit',
'#button_type' => 'primary',
'#value' => $this
->t('Save and select'),
'#ajax' => [
'callback' => '::updateLibrary',
'wrapper' => 'media-library-add-form-wrapper',
],
],
];
}
public function updateFormCallback(array &$form, FormStateInterface $form_state) {
$triggering_element = $form_state
->getTriggeringElement();
$wrapper_id = $triggering_element['#ajax']['wrapper'];
$added_media = $form_state
->get('media');
$media_type = $this
->getMediaType($form_state);
$response = new AjaxResponse();
if ($form_state::hasAnyErrors()) {
$response
->addCommand(new ReplaceCommand('#media-library-add-form-wrapper', $form));
return $response;
}
if (end($triggering_element['#parents']) === 'remove_button') {
if (empty($added_media)) {
$build = [
'#theme' => 'media_directories_add',
'#selected_type' => $media_type
->id(),
'#active_directory' => $this
->getDirectory($form_state),
'#target_bundles' => $this
->getTargetBundles($form_state),
'#media_library_form_rebuild' => TRUE,
];
$form_state
->setRebuild();
$response
->addCommand(new ReplaceCommand('#media-library-add-form-wrapper', $build));
}
else {
$response
->addCommand(new ReplaceCommand("#{$wrapper_id}", $form));
}
}
else {
$response
->addCommand(new ReplaceCommand("#{$wrapper_id}", $form));
}
return $response;
}
public function removeButtonSubmit(array $form, FormStateInterface $form_state) {
$triggering_element = $form_state
->getTriggeringElement();
$delta = array_slice($triggering_element['#array_parents'], -2, 1)[0];
$added_media = $form_state
->get('media');
$removed_media = $added_media[$delta];
unset($added_media[$delta]);
$form_state
->set('media', $added_media)
->setRebuild();
$this
->messenger()
->addStatus($this
->t('The media item %label has been removed.', [
'%label' => $removed_media
->label(),
]));
}
public function updateLibrary(array &$form, FormStateInterface $form_state) {
if ($form_state::hasAnyErrors()) {
return $form;
}
$form_state
->setStorage([]);
$form_state
->setRebuild();
$response = new AjaxResponse();
$response
->addCommand(new CloseModalDialogCommand());
$response
->addCommand(new RefreshDirectoryTree($form_state
->getValue('most_choosen_directory_tid'), $form_state
->getValue('newly_added_media_ids')));
$status_messages = [
'#type' => 'status_messages',
];
$messages = \Drupal::service('renderer')
->renderRoot($status_messages);
if (!empty($messages)) {
$response
->addCommand(new OpenModalDialogCommand('', $messages));
}
return $response;
}
protected function processInputValues(array $source_field_values, array $form, FormStateInterface $form_state) {
$media_type = $this
->getMediaType($form_state);
$media_storage = $this->entityTypeManager
->getStorage('media');
$source_field_name = $this
->getSourceFieldName($media_type);
$media = array_map(function ($source_field_value) use ($media_type, $media_storage, $source_field_name, $form_state) {
return $this
->createMediaFromValue($media_type, $media_storage, $source_field_name, $source_field_value, $form_state);
}, $source_field_values);
$form_state
->set('media', array_values($media));
$form_state
->setRebuild();
}
protected function createMediaFromValue(MediaTypeInterface $media_type, EntityStorageInterface $media_storage, $source_field_name, $source_field_value, FormStateInterface $form_state) {
$media = $media_storage
->create([
'bundle' => $media_type
->id(),
$source_field_name => $source_field_value,
'directory' => $this
->getDirectory($form_state),
]);
$media
->setName($media
->getName());
return $media;
}
}