Quantcast
Channel: Issues for Drupal core
Viewing all articles
Browse latest Browse all 293729

Media Library edge case: selecting already existing media programmatically

$
0
0

Problem/Motivation

Can't select programmatically already existing media within the custom implementation of AddFormBase class.

Description

We are building integration between PicturePark DAM and Drupal Media Library.
Our business case is allowing media to be selected from DAM that was previously imported into Drupal by using DAM asset browser.
The logic behind this decision is that DAM asset browser has much more powerful filters to search needed assets.

So basically we are trying to achieve the next scenario:
- custom migration brings lots of external assets and stores them as media,
- Content Manager (CM) uses Media Library and custom upload form to pick some assets and import them into Drupal,
- this upload form triggers the external DAM asset browser,
- CM submit a Media Library form to bring media on the page,

We want to prevent CM from creating media duplicates.

For that, we override \Drupal\media_library\Form\AddFormBase::processInputValues method.
The key is here:

$media = array_map(function ($source_field_value) use ($media_type, $media_storage, $source_field_name) {
  // Try to find existing media and reuse them instead of creating new.
  $query = $media_storage->getQuery();
  $query->condition($source_field_name, $source_field_value);
  $existingMedia = $query->execute();

  if (!empty($existingMedia)) {
    $ppMedia = $media_storage->load(array_values($existingMedia)[0]);
    if ($ppMedia instanceof MediaInterface) {
      // Special "hack" to select already existing media.
      // The trick that media_library view (widget display)
      // has sorter by created datetime,
      // so any newly added media will be placed in the top of the media.
      // The original problem:
      // > Already imported medias that were selected in PP asset browser
      // > are marked as "0 of N items selected".
      // > That's caused by view being rendered only active page,
      // > and then applying selection based on ids stored on FE side.
      // > But if asset were uploaded long time ago then it will be located
      // > far from then current page and won't be preselected by JS.
      // Other potential solutions:
      // - trigger form error and loose ability importing new media,
      //   together with already imported medias.
      // - provide ajax command to place existing selected media
      //   on top of the list; unknown consequences.
      // - create ajax command to update #media-library-modal-selection
      //   with all selected elements.
      //$ppMedia->setCreatedTime(time());
      return $ppMedia;
    }
  }

  return $this->createMediaFromValue($media_type, $media_storage, $source_field_name, $source_field_value);
}, $source_field_values);

Basically, we try to find existing media by remote_id. Otherwise, fallback to default behavior (creating media).

Then on media upload \Drupal\media_library\Form\AddFormBase::updateLibrary
will trigger UpdateSelectionCommand which will populate media selection registry.
This registry will be used by Drupal.behaviors.MediaLibraryItemSelection on ajax response to check media elements in view:

      currentSelection.forEach(function (value) {
        $form.find("input[type=\"checkbox\"][value=\"".concat(value, "\"]")).prop('checked', true).trigger('change');
      });

(Link to D11 code)

The actual memorizing of all selected media happens in:

$(once('media-item-change', $mediaItems)).on('change', function (e) {
    var id = e.currentTarget.value;
    var position = currentSelection.indexOf(id);
    if (e.currentTarget.checked) {
      if (position === -1) {
        currentSelection.push(id);
      }
    } else if (position !== -1) {
      currentSelection.splice(position, 1);
    }
    var mediaLibraryModalSelection = document.querySelector('#media-library-modal-selection');
    if (mediaLibraryModalSelection) {
      mediaLibraryModalSelection.value = currentSelection.join();
      $(mediaLibraryModalSelection).trigger('change');
      console.log(currentSelection);
    }
    document.querySelectorAll('.js-media-library-add-form-current-selection').forEach(function (item) {
      item.value = currentSelection.join();
    });
});

(Link to D11 code)

This means on each media click update the selected media registry and store selection in dom: #media-library-modal-selection hidden form element (which is created by media library views widget).

But selected media elements that are not located on the same page won't be stored inside #media-library-modal-selection
Currently, the only way (out of the box) to browse to the views page where this media is located, then it will be selected by JS.

Steps to reproduce

Create a custom implementation of AddFormBase class and override processInputValues method to bring some existing media.
Open your custom media upload form and select externally some already imported media.
Expect to see selected media in the field. Real result - no items.

Proposed resolution

Modify Drupal.behaviors.MediaLibraryItemSelection behaviour to cover such case.

Remaining tasks

TBD

User interface changes

TBD

Other discovered related issues:

There is no check for unique values that go into Drupal.behaviors.MediaLibraryItemSelection and in #media-library-modal-selection also.


Viewing all articles
Browse latest Browse all 293729

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>