monster_menus-9.0.x-dev/modules/mm_media/src/Form/MMMediaLibrary.php
modules/mm_media/src/Form/MMMediaLibrary.php
<?php
namespace Drupal\mm_media\Form;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\AlertCommand;
use Drupal\Core\Ajax\CloseDialogCommand;
use Drupal\Core\Ajax\CloseModalDialogCommand;
use Drupal\Core\Ajax\HtmlCommand;
use Drupal\Core\Ajax\OpenDialogCommand;
use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormBuilderInterface;
use Drupal\Core\Form\FormState;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Url;
use Drupal\editor\Ajax\EditorDialogSave;
use Drupal\editor\EditorInterface;
use Drupal\file\Entity\File;
use Drupal\media\Entity\Media;
use Drupal\media_library\MediaLibraryState;
use Drupal\mm_media\Ajax\MediaUpdatedCommand;
use Drupal\mm_media\Plugin\EntityBrowser\Widget\MMTree;
use Drupal\mm_media\TemporaryMediaTrait;
use Drupal\monster_menus\Constants;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\HttpFoundation\Request;
class MMMediaLibrary extends FormBase {
use TemporaryMediaTrait;
/**
* The entity repository.
*
* @var \Drupal\Core\Entity\EntityRepositoryInterface
*/
protected $entityRepository;
/**
* The entity display repository.
*
* @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface
*/
protected $entityDisplayRepository;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The form builder.
*
* @var \Drupal\Core\Form\FormBuilderInterface
*/
protected $formBuilder;
/**
* Constructs a EditorMediaDialog object.
*
* @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
* The entity repository.
* @param \Drupal\Core\Entity\EntityDisplayRepositoryInterface $entity_display_repository
* The entity display repository.
*/
public function __construct(EntityRepositoryInterface $entity_repository, EntityDisplayRepositoryInterface $entity_display_repository, EntityTypeManagerInterface $entity_type_manager, FormBuilderInterface $form_builder) {
$this->entityRepository = $entity_repository;
$this->entityDisplayRepository = $entity_display_repository;
$this->entityTypeManager = $entity_type_manager;
$this->formBuilder = $form_builder;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity.repository'),
$container->get('entity_display.repository'),
$container->get('entity_type.manager'),
$container->get('form_builder')
);
}
/**
* @inheritDoc
*/
public function getFormId() {
return 'mm_media_library';
}
/**
* @param array $form
* A nested array form elements comprising the form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
* @param \Drupal\editor\EditorInterface|null $editor
* The text editor to which this dialog corresponds.
*/
public function buildForm(array $form, FormStateInterface $form_state, EditorInterface $editor = NULL) {
$this_mmtid = $this->getRouteMatch()->getParameter('mm_tree') ?: mm_home_mmtid();
$pop_start = implode('/', mm_content_get_parents_with_self($this_mmtid));
$form['#attached']['library'][] = 'mm_media/mmmedialibrary_editing';
$form['#attached']['library'][] = 'editor/drupal.editor.dialog';
$state = MediaLibraryState::fromRequest($this->getRequest());
$allowed_types = implode(',', $state->getAllowedTypeIds()) . ',' . MMTree::FILE2MEDIA_TYPE;
$form['errors'] = [
'#prefix' => '<div id="mm-media-library-errors">',
'#suffix' => '</div>',
];
$form['browser'] = [
'#title' => $this->t('Media'),
'#type' => 'mm_medialist',
'#default_value' => ['' => $this->t('(choose a media item)')],
'#mm_list_popup_start' => $pop_start,
'#mm_list_selectable' => Constants::MM_PERMS_READ,
'#mm_list_file_types' => $allowed_types,
'#mm_list_min' => 1,
'#mm_list_max' => 1,
'#mm_list_auto_choose' => TRUE,
'#mm_list_instance_start' => 100,
'#mm_list_hide_left_pane' => TRUE,
'#ajax' => [
'callback' => [static::class, 'updatePreview'],
'event' => 'change',
'wrapper' => 'mmmedialibrary-preview',
]
];
$form['actions'] = [
'#type' => 'actions',
];
$form['actions']['insert'] = [
'#type' => 'button',
'#value' => t('Insert'),
'#button_type' => 'button',
'#ajax' => [
'callback' => '::submitForm',
'event' => 'click',
],
];
$form['actions']['cancel'] = [
'#type' => 'button',
'#value' => t('Cancel'),
'#button_type' => 'button',
];
$media_embed_filter = $editor->getFilterFormat()->filters()->get('media_embed');
$current_view_mode = $form_state->getValue(['attributes', 'data-view-mode']) ?: $media_embed_filter->settings['default_view_mode'];
// Store the default from the MediaEmbed filter, so that if the selected
// view mode matches the default, we can drop the 'data-view-mode'
// attribute.
$form_state->set('filter_default_view_mode', $media_embed_filter->settings['default_view_mode']);
$attributes = [
'#tree' => TRUE,
'data-view-mode' => [
'#type' => 'hidden',
'#value' => $current_view_mode,
],
];
$preview = [];
$settings = [
'#type' => 'submit',
'#access' => FALSE,
];
if ($media = $this->getMedia($form_state)) {
$form_state->set('mm_media', $media);
[$mid, $fid] = $this->getMediaIDs($form_state);
$settings = [
'#type' => 'submit',
'#value' => $this->t('Edit Properties'),
'#name' => 'mm_media_library_edit_media',
'#ajax' => [
'url' => Url::fromRoute('mm_media_library.edit_media', ['media_id' => $mid, 'file_id' => $fid]),
'disable-refocus' => TRUE,
],
'#attributes' => [
'class' => ['edit-button'],
],
'#access' => $media->access('update'),
];
$view_mode_options = array_intersect_key($this->entityDisplayRepository->getViewModeOptionsByBundle($media->getEntityTypeId(), $media->bundle()), $editor->getFilterFormat()->filters()->get('media_embed')->settings['allowed_view_modes']);
$attributes['data-view-mode'] = [
'#title' => $this->t('Display'),
'#type' => 'select',
'#options' => $view_mode_options,
'#default_value' => $current_view_mode,
'#access' => count($view_mode_options) >= 2,
'#ajax' => [
'callback' => '::updatePreview',
'event' => 'change',
'wrapper' => 'mmmedialibrary-preview',
]
];
$preview = $this->entityTypeManager
->getViewBuilder($media->getEntityTypeId())
->view($media, $current_view_mode);
$preview['#weight'] = 10;
}
$form['media'] = [
'#prefix' => '<div id="mmmedialibrary-preview" style="clear: both">',
'settings' => $settings,
'attributes' => $attributes,
'preview' => $preview,
'#suffix' => '</div>',
];
return $form;
}
/**
* @inheritDoc
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$response = new AjaxResponse();
// When the `alt` attribute is set to two double quotes, transform it to the
// empty string: two double quotes signify "empty alt attribute". See above.
if (trim($form_state->getValue(['attributes', 'alt'], '')) === '""') {
$form_state->setValue(['attributes', 'alt'], '""');
}
// The `alt` attribute is optional: if it isn't set, the default value
// simply will not be overridden. It's important to set it to FALSE
// instead of unsetting the value. This way we explicitly inform
// the client side about the new value.
if ($form_state->hasValue(['attributes', 'alt']) && trim($form_state->getValue(['attributes', 'alt'])) === '') {
$form_state->setValue(['attributes', 'alt'], FALSE);
}
// If the selected view mode matches the default on the filter, remove the
// attribute.
if (!empty($form_state->get('filter_default_view_mode')) && $form_state->getValue(['attributes', 'data-view-mode']) === $form_state->get('filter_default_view_mode')) {
$form_state->setValue(['attributes', 'data-view-mode'], FALSE);
}
if ($form_state->hasAnyErrors()) {
$form['status_messages'] = [
'#type' => 'status_messages',
'#weight' => -1000,
];
$response->addCommand(new HtmlCommand('#mm-media-library-errors', $form['status_messages']));
}
else {
if ($media = $this->getMedia($form_state)) {
if ($media->isNew()) {
// ::getMedia() created a temporary Media item, so save it now.
$media->save();
}
// Only send back the relevant values.
$values = [
'hasCaption' => $form_state->getValue('hasCaption'),
'attributes' => $form_state->getValue('attributes') + [
'data-entity-type' => $media->getEntityTypeId(),
'data-entity-uuid' => $media->uuid(),
'data-align' => 'left',
],
];
$response->addCommand(new EditorDialogSave($values));
}
$response->addCommand(new CloseModalDialogCommand());
}
return $response;
}
public static function updatePreview(array $form, FormStateInterface $form_state) {
return $form['media'];
}
public function editMedia($media_id, $file_id, Request $request) {
$trigger_name = $request->request->get('_triggering_element_name');
$edit_button = $trigger_name && str_contains($trigger_name, 'edit_button');
if ($edit_button) {
// Remove posted values from original form to prevent
// data leakage into this form when the form is of the same bundle.
$original_request = $request->request;
$request->request = new ParameterBag();
}
if ($media_id) {
$entity = Media::load($media_id);
}
else {
$entity = $this->createTemporaryMedia(File::load($file_id));
// Copy mapped fields from the File to the Media.
$media_source = $entity->getSource();
foreach (array_keys($entity->getTranslationLanguages()) as $langcode) {
if ($entity->hasTranslation($langcode)) {
$translation = $entity->getTranslation($langcode);
// Try to set fields provided by the media source and mapped in
// media type config.
foreach ($translation->get('bundle')->entity->getFieldMap() as $metadata_attribute_name => $entity_field_name) {
// Only save value in the entity if the field is empty or if the
// source field changed.
if ($translation->hasField($entity_field_name) && $translation->get($entity_field_name)->isEmpty()) {
$translation->set($entity_field_name, $media_source->getMetadata($translation, $metadata_attribute_name));
}
}
// Try to set a default name for this media item if no name is provided.
if ($translation->get('name')->isEmpty()) {
$translation->setName($translation->getName());
}
}
}
}
if (empty($entity)) {
return;
}
// Use edit form class if it exists, otherwise use default form class.
$entity_type = $entity->getEntityType();
if ($entity_type->getFormClass('edit')) {
$operation = 'edit';
}
elseif ($entity_type->getFormClass('default')) {
$operation = 'default';
}
if (!empty($operation)) {
// Build the entity edit form.
$form_object = $this->entityTypeManager->getFormObject($entity->getEntityTypeId(), $operation);
$form_object->setEntity($entity);
$form_state = (new FormState())
->setFormObject($form_object)
->disableRedirect();
// Building the form also submits.
$form = $this->formBuilder->buildForm($form_object, $form_state);
}
// Restore original request now that the edit form is built.
// This fixes a bug where closing modal and re-opening it would
// cause two modals to open.
if ($edit_button) {
$request->request = $original_request;
}
// Return a response, depending on whether it's successfully submitted.
if (!empty($operation) && $form_state && !$form_state->isExecuted()) {
// Return the form as a modal dialog.
$form['#id'] = 'mm-media-edit-form';
$form['#attached']['library'][] = 'core/drupal.dialog.ajax';
$title = $this->t('Edit @entity', ['@entity' => $entity->label()]);
return (new AjaxResponse())->addCommand(new OpenDialogCommand('#mm-media-edit-form', $title, $form, ['modal' => TRUE, 'width' => 800]));
}
// Return command for closing the modal.
$response = (new AjaxResponse())->addCommand(new CloseDialogCommand('#mm-media-edit-form'));
// Also refresh the preview.
$response->addCommand(new MediaUpdatedCommand($form_object->getEntity()->id()));
// Remove previous status messages.
if (!empty($form_state) && $form_state->getFormObject()) {
$form_state->getFormObject()->messenger()->deleteByType(MessengerInterface::TYPE_STATUS);
}
// Show error messages.
$form['status_messages'] = [
'#type' => 'status_messages',
'#weight' => -1000,
];
$response->addCommand(new HtmlCommand('#mm-media-library-errors', $form['status_messages']));
if (empty($operation)) {
$response->addCommand(new AlertCommand($this->t("An edit form couldn't be found.")));
}
return $response;
}
public function accessEditMedia($media_id, $file_id) {
if ($media_id) {
return ($media = Media::load($media_id)) ? $media->access('update', NULL, TRUE) : AccessResult::forbidden();
}
return ($file = File::load($file_id)) ? $file->access('view', NULL, TRUE) : AccessResult::forbidden();
}
private function getMediaIDs(FormStateInterface $form_state) {
if ($item = mm_ui_mmlist_key0($form_state->getValue('browser'))) {
[, $fid, $mid] = explode('/', $item);
return $mid > 0 ? [$mid, 0] : [0, $fid];
}
}
private function getMedia(FormStateInterface $form_state) {
if ([$mid, $fid] = $this->getMediaIDs($form_state)) {
if ($mid) {
return Media::load($mid);
}
if ($file = File::load($fid)) {
return $this->createTemporaryMedia($file);
}
}
}
}
