You are here

AddMediaFormBase.php in Media Directories 3.x

File

modules/media_directories_ui/src/Form/AddMediaFormBase.php
View source
<?php

namespace Drupal\media_directories_ui\Form;

use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\InvokeCommand;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\media\MediaTypeInterface;
use Drupal\media_library\Form\AddFormBase;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Class AddMediaFormBase
 *
 * Uses code and logic from core. We could try to integrate core directly,
 * but it might be too unstable in this stage.
 *
 * @package Drupal\media_directories_ui\Form
 */
abstract class AddMediaFormBase extends AddFormBase {

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static($container
      ->get('entity_type.manager'), $container
      ->get('media_directories_ui.ui_builder'), $container
      ->get('media_library.opener_resolver'));
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'media_directories_add_form';
  }
  public function buildForm(array $form, FormStateInterface $form_state) {
    $form = parent::buildForm($form, $form_state);
    $form['#action'] = Url::fromRoute('media_directories_library.ui', [], [
      'query' => $this
        ->getMediaLibraryState($form_state)
        ->all(),
    ])
      ->toString();
    $added_media = $this
      ->getAddedMediaItems($form_state);

    // Add back button to cancel uploading items.
    if (empty($added_media)) {
      $form['actions'] = [
        '#type' => 'actions',
        'back' => [
          '#type' => 'submit',
          '#value' => $this
            ->t('Back to the library'),
          '#ajax' => [
            'callback' => '::backToLibraryCallback',
            'wrapper' => 'media-library-wrapper',
          ],
        ],
      ];
    }
    return $form;
  }

  /**
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *
   * @return int|null
   */
  protected function getDirectory(FormStateInterface $form_state) {
    $state = $this
      ->getMediaLibraryState($form_state);
    $directory_id = (int) $state
      ->get('directory');
    if ($directory_id === MEDIA_DIRECTORY_ROOT) {
      $directory_id = NULL;
    }
    return $directory_id;
  }

  /**
   * AJAX callback to update the entire form based on source field input.
   *
   * @param array $form
   *   The complete form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current form state.
   *
   * @return \Drupal\Core\Ajax\AjaxResponse|array
   *   The form render array or an AJAX response object.
   */
  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');
    $response = new AjaxResponse();

    // When the source field input contains errors, replace the existing form to
    // let the user change the source field input. If the user input is valid,
    // the entire modal is replaced with the second step of the form to show the
    // form fields for each media item.
    if ($form_state::hasAnyErrors()) {
      $response
        ->addCommand(new ReplaceCommand('#media-library-add-form-wrapper', $form));
      return $response;
    }

    // Check if the remove button is clicked.
    if (end($triggering_element['#parents']) === 'remove_button') {

      // When the list of added media is empty, return to the media library and
      // shift focus back to the first tabbable element (which should be the
      // source field).
      if (empty($added_media)) {
        $form_state
          ->setRebuild();
        $response
          ->addCommand(new ReplaceCommand('#media-library-add-form-wrapper', $this
          ->buildMediaLibraryUi($form_state)));
        $response
          ->addCommand(new InvokeCommand('#media-library-add-form-wrapper :tabbable', 'focus'));
      }
      else {
        $response
          ->addCommand(new ReplaceCommand("#{$wrapper_id}", $form));

        // Find the delta of the next media item. If there is no item with a
        // bigger delta, we automatically use the delta of the previous item and
        // shift the focus there.
        $removed_delta = array_slice($triggering_element['#array_parents'], -2, 1)[0];
        $delta_to_focus = 0;
        foreach ($added_media as $delta => $media) {
          $delta_to_focus = $delta;
          if ($delta > $removed_delta) {
            break;
          }
        }
        $response
          ->addCommand(new InvokeCommand(".media-library-add-form__media[data-media-library-added-delta={$delta_to_focus}]", 'focus'));
      }
    }
    else {
      $response
        ->addCommand(new ReplaceCommand("#{$wrapper_id}", $form));
      $response
        ->addCommand(new InvokeCommand('.media-library-add-form__added-media', 'focus'));
    }
    return $response;
  }

  /**
   * Go back to the library view.
   *
   * @param $form
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *
   * @return \Drupal\Core\Ajax\AjaxResponse
   */
  public function backToLibraryCallback(&$form, FormStateInterface $form_state) {
    $response = new AjaxResponse();
    $response
      ->addCommand(new ReplaceCommand('#media-library-wrapper', $this
      ->buildMediaLibraryUi($form_state)));
    $response
      ->addCommand(new InvokeCommand('#media-library-wrapper :tabbable', 'focus'));
    $form_state
      ->setRebuild();
    return $response;
  }
  protected function buildUploadUi(FormStateInterface $form_state) {

    // Get the render array for the media library. The media library state might
    // contain the 'media_library_content' when it has been opened from a
    // vertical tab. We need to remove that to make sure the render array
    // contains the vertical tabs. Besides that, we also need to force the media
    // library to create a new instance of the media add form.
    // @see \Drupal\media_library\MediaLibraryUiBuilder::buildMediaTypeAddForm()
    $state = $this
      ->getMediaLibraryState($form_state);
    $state
      ->remove('media_library_content');

    //$state->set('_media_library_form_rebuild', TRUE);
    return $this->libraryUiBuilder
      ->buildUploadUi($state);
  }

  /**
   * Creates media items from source field input values.
   *
   * @param mixed[] $source_field_values
   *   The values for source fields of the media items.
   * @param array $form
   *   The complete form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current form state.
   */
  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);

    // Re-key the media items before setting them in the form state.
    $form_state
      ->set('media', array_values($media));

    // Save the selected items in the form state so they are remembered when an
    // item is removed.
    $form_state
      ->set('current_selection', array_filter(explode(',', $form_state
      ->getValue('current_selection'))));
    $form_state
      ->setRebuild();
  }

  /**
   * Creates a new, unsaved media item from a source field value.
   *
   * @param \Drupal\media\MediaTypeInterface $media_type
   *   The media type of the media item.
   * @param \Drupal\Core\Entity\EntityStorageInterface $media_storage
   *   The media storage.
   * @param string $source_field_name
   *   The name of the media type's source field.
   * @param mixed $source_field_value
   *   The value for the source field of the media item.
   *
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *
   * @return \Drupal\media\MediaInterface
   *   An unsaved media entity.
   */
  protected function createMediaFromValue(MediaTypeInterface $media_type, EntityStorageInterface $media_storage, $source_field_name, $source_field_value, FormStateInterface $form_state = NULL) {
    $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;
  }
  protected function getMediaLibraryState(FormStateInterface $form_state) {
    $state = parent::getMediaLibraryState($form_state);
    $state
      ->remove('ajax_form');
    $state
      ->remove('_wrapper_format');
    return $state;
  }

}

Classes

Namesort descending Description
AddMediaFormBase Class AddMediaFormBase