Übergeben der aktuellen Auswahl an die Auswahlansicht des Entitätsbrowsers

8

Ich verwende einen Entitätsbrowser (2.x-dev in Drupal 8) als Formular-Widget für das Entitätsreferenzbasisfeld einer benutzerdefinierten Entität. Der Entitätsbrowser ist konfiguriert

  • als modale Anzeige,
  • mit einem einzigen Widget,
  • und keine Auswahlanzeige,
  • Verwenden einer Ansicht mit einem Massenauswahlfeld des Entitätsbrowsers als Widget und
  • um ausgewählte Entitäten an die aktuelle Auswahl des Referenzfelds anzuhängen.

Die Auswahl der Entitäten funktioniert einwandfrei. Das Entitätsreferenzfeld darf jedoch keine Duplikate enthalten.

Um die Auswahl von Entitäten ohne Duplikate zu vereinfachen, möchte ich bereits ausgewählte Entitäten aus den Ergebnissen der Entitätsbrowser-Ansicht filtern. Benutzer sehen also nur nicht ausgewählte Entitäten.

Zu diesem Zweck habe ich ein Plugin für benutzerdefinierte Ansichten argument_default erstellt, das den Auswahlspeicher des Entitätsbrowsers als Kontextstandardargument für die Entitäts-ID verfügbar macht:

<?php

namespace Drupal\my_module\Plugin\views\argument_default;

use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
use Drupal\views\Plugin\views\argument_default\ArgumentDefaultPluginBase;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * The entity browser selection argument default handler.
 *
 * @ViewsArgumentDefault(
 *   id = "entity_browser_selection",
 *   title = @Translation("Entity Browser Selection")
 * )
 */
class EntityBrowserSelection extends ArgumentDefaultPluginBase {

  /**
   * The selection storage.
   *
   * @var \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface
   */
  protected $selectionStorage;

  /**
   * {@inheritdoc}
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, KeyValueStoreExpirableInterface $selection_storage) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->selectionStorage = $selection_storage;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('entity_browser.selection_storage')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function access() {
    return $this->view->getDisplay()->pluginId === 'entity_browser';
  }

  /**
   * {@inheritdoc}
   */
  public function getArgument() {
    $argument = NULL;
    $current_request = $this->view->getRequest();

    // Check if the widget context is available.
    if ($current_request->query->has('uuid')) {
      $uuid = $current_request->query->get('uuid');
      if ($storage = $this->selectionStorage->get($uuid)) {
        if (!empty($storage['selected_entities'])) {
          $argument = $storage['selected_entities'];
        }
      }
    }
    return $argument;
  }

}

Das Problem ist, dass die aktuelle Auswahl im Auswahlspeicher immer leer ist, unabhängig davon, wie viele Entitäten im Entitätsreferenzfeld ausgewählt wurden, und selbst nachdem ich die modale Auswahl abgeschlossen und den Entitätsbrowser erneut geöffnet habe.

Was muss ich tun, damit die aktuelle Auswahl im Auswahlspeicher des Entitätsbrowsers angezeigt wird?

Mario Steinitz
quelle
Warten Sie, damit Sie meinen, wenn Sie einen Artikel vollständig ausgewählt (und gespeichert) haben, möchten Sie nicht, dass der Artikel im Modal als auswählbarer Artikel angezeigt wird? oder meinst du damit, dass du keine doppelte Auswahl im laufenden Betrieb zulässt ... oder meinst du, du willst eindeutige Daten für deinen gesamten Inhalt, wenn sie ausgewählt sind, und dann vor der Ansicht ausblenden?
TaggartJ
Beide Fälle. Wenn die Entität neu ist und das Modal zur Auswahl verwandter Entitäten verwendet wird, wird die getroffene Auswahl bereits aus dem Entitätsbrowser gefiltert, sobald Sie erneut auf die Schaltfläche "Auswählen" klicken (bevor die Entität gespeichert wurde). Und natürlich muss die aktuelle Auswahl ( #default_value) nach dem Speichern und der erneuten Bearbeitung auch als Filter betrachtet werden.
Mario Steinitz

Antworten:

4

Der Entitätsbrowser übergibt derzeit kein aktuelles Standardwertelementfeld in persistenten Daten, aber es ist einfach, es hinzuzufügen.

1) Fügen Sie persistente Daten mit field_widget_form_alter () hinzu

/**
 * Implements hook_field_widget_form_alter().
 */
function mymodule_field_widget_form_alter(&$element, FormStateInterface &$form_state, $context) {
  if (!empty($element['entity_browser'])) {
    $default_value =  $element['entity_browser']['#default_value'];
    $ids = [];
    foreach ($default_value as $entity) {
      $ids[] = $entity->id();
    }
    $element['entity_browser']['#widget_context']['current_ids'] = implode('+', $ids);
  }
}

2) Aktualisieren Sie Ihre Auswahl so, dass, wenn leer, alle angezeigt werden:

  /**
   * {@inheritdoc}
   */
  public function getArgument() {
    $argument = NULL;
    $current_request = $this->view->getRequest();

    // Check if the widget context is available.
    if ($current_request->query->has('uuid')) {
      $uuid = $current_request->query->get('uuid');
      if ($storage = $this->selectionStorage->get($uuid)) {
        if (!empty($storage['widget_context']['current_ids'])) {
          $argument = $storage['widget_context']['current_ids'];
        }
        else {
          $argument = 'all';
        }
      }
    }
    return $argument;
  }

3) Stellen Sie sicher, dass bei Ihrer Auswahl die Option "Ausschließen" und "Mehrere zulassen" aktiviert ist.

Geben Sie hier die Bildbeschreibung ein

Übrigens, wenn Sie auf die neueste Entwicklungsversion von entity_browser aktualisieren, benötigen Sie Ihr benutzerdefiniertes Plugin nicht. Es gibt ein neues Plugin für Standardwertansichten von entity_browser_widget_context , das konfiguriert werden kann.

Ich habe der Entity_Browser-Warteschlange auch ein Problem hinzugefügt , um diese Informationen im Widget-Kontext hinzuzufügen.

oknate
quelle
2

Ich habe Ihre Standardargumentklasse verwendet und ein wenig debuggt. Das ist mein Ansatz:

Das Entitätsbrowser-Widget speichert ausgewählte Werte in seiner currentEigenschaft, die gefüllt wird, wenn das Entitätsformular mit einer vorhandenen Entität / Auswahl geöffnet wird. Das Widget verwendet AJAX auch, wenn das Modal geschlossen wird und die currentEigenschaft entsprechend aktualisiert wird.

So können Sie die ausgewählten Entitäts-IDs mithilfe der folgenden Angaben in Ihrem Entitätsformular / Ihrer Formularänderung abrufen:

use Drupal\Core\Render\Element;

// Current selection. Replace 'field_references' with the actual
// name of your field.
$selection = [];
if (isset($form['field_references']['widget']['current'])) {
  $current = $form['time_records']['widget']['current'];
  foreach (Element::children($current) as $key) {
    if (isset($current[$key]['target_id']['#value'])) {
      $selection[] = $current[$key]['target_id']['#value'];
    }
  }
}

Eine weitere im Formular verfügbare Widget-Eigenschaft ist der Widget-Kontext des verwendeten Entitätsbrowsers. Sie können einfach die aktuelle Auswahl zum Widget-Kontext hinzufügen und diese Informationen mit dem Standardargument Ihrer Ansichten verwenden (der Widget-Kontext wird bei jedem AJAX-Neuladen des Widgets / Formulars im Auswahlspeicher aktualisiert):

$form['field_references']['widget']['entity_browser']['#widget_context']['current_selection'] = $selection;

Dann ändern Sie Ihre EntityBrowserSelection::getArgument():

  /**
   * {@inheritdoc}
   */
  public function getArgument() {
    $argument = NULL;
    $current_request = $this->view->getRequest();

    // Check if the widget context is available.
    if ($current_request->query->has('uuid')) {
      $uuid = $current_request->query->get('uuid');
      if ($storage = $this->selectionStorage->get($uuid)) {
        if (!empty($storage['widget_context']['current_selection'])) {
          $selection = $storage['widget_context']['current_selection'];
          if (is_string($selection)) {
            $argument = $selection;
          }
          elseif (is_array($selection)) {
            $non_scalar = array_filter($selection, function ($item) {
              return !is_scalar($item);
            });
            if (empty($non_scalar)) {
              // Replace the ',' with '+', if you like to have an
              // OR filter rather than an AND filter.
              $argument = implode(',', $selection);
            }
          }
        }
      }
    }
    return $argument;
  }

Mit diesen Änderungen konnte ich ausgewählte Elemente aus meiner Ansicht mit einem Kontextfilter für die Entitäts-IDs filtern und auswählen

  • Wenn der Filter nicht verfügbar ist: Geben Sie einen Standardwert ein. Geben Sie "Auswahl des Entitätsbrowsers" ein.
  • Mehr: Ausschließen

Ich hoffe es hilft!

Andreas W. Wylach
quelle
0

Ich konnte den Standardfilter nicht zum Laufen bringen, aber ich hatte einige Erfolge mit der folgenden Unheimlichkeit:

function mymodule_views_pre_render(\Drupal\views\ViewExecutable $view) {
  if ($view->id() == "media_entity_browser" && $view->current_display ==
    'entity_browser_1') {
    $request = \Drupal::request();
    $prams = $request->query->all();
    $is_edit = FALSE;
    if (!empty($prams['original_path'])) {
      // testing with "/node/1/edit"
      $check_explode = explode('/', $prams['original_path']);
      if (in_array('edit', $check_explode)) {
        $edit_key = array_search ( 'edit', $check_explode);
        $entity_id_key = $edit_key - 1;
        $entity_id = $check_explode[$entity_id_key];
        $entity_type_key = $edit_key - 2;
        $entity_type = $check_explode[$entity_type_key];
        $selected_ids = [];
        try {
          $entity = \Drupal::entityTypeManager()->getStorage($entity_type)->load($entity_id);
          // This sucks bacause field name is hardcoded.
          $media_entities = $entity->field_image->referencedEntities();
          if (!empty($media_entities)) {
            foreach ($media_entities as $media_entity) {
              $selected_ids[] = (int) $media_entity->id();
            }
          }
        }
        catch (\Exception $e) {
          // log this.
        }

        $my_results = [];
        // Now need to remove from view.
        if (!empty($selected_ids)) {
          $i = 0;
          foreach ($view->result as $key =>  $item) {
            $id = (int) $item->_entity->id();
            if (!in_array($id, $selected_ids)) {
              $my_results[] = new ResultRow([
                '_entity' => $item->_entity,
                'index' => $i,
                'mid' => $item->_entity->id(),
              ]);
              $i++;
            }
          }
          $view->result = $my_results;
        }
      }
    }
  }
}

Das funktioniert. Es werden jedoch einige Annahmen getroffen ... Gut, dass Sie mit dem Entity-Browser auswählen können, welche Ansicht Sie verwenden möchten.

taggartJ
quelle