Come passare la selezione corrente alla vista di selezione del browser entità


8

Sto usando un Entity Browser (2.x-dev in Drupal 8) come widget di modulo per il campo base di riferimento di entità di un'entità personalizzata. Il browser entità è configurato

  • come display modale,
  • con widget singolo,
  • e nessun display di selezione,
  • utilizzando una vista con il campo di selezione in blocco del browser entità come widget e
  • per aggiungere le entità scelte alla selezione corrente del campo di riferimento.

La selezione delle entità funziona correttamente. Ma il campo di riferimento dell'entità non deve avere duplicati.

Per facilitare la selezione di entità senza duplicati, vorrei filtrare le entità già scelte dai risultati di visualizzazione del browser delle entità. Quindi gli utenti vedranno solo entità non selezionate.

A tale scopo, ho creato un plug-in viste personalizzate argomento_default che espone la memoria di selezione del browser entità come argomento predefinito del contesto per l'ID entità:

<?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;
  }

}

Il problema che devo affrontare è che la selezione corrente all'interno dell'archivio di selezione è sempre vuota, indipendentemente dal numero di entità selezionate nel campo di riferimento dell'entità e anche dopo aver completato la selezione modale e aperto nuovamente il browser entità.

Cosa devo fare per visualizzare la selezione corrente nella memoria di selezione del browser entità?


aspetta quindi intendi se hai selezionato (e salvato) un oggetto pronto per essere visualizzato nel modale come elemento selezionabile? o vuoi dire non consentire la selezione duplicata al volo ... o intendi che vuoi dati unici su tutti i tuoi contenuti se selezionati, quindi nascondili dalla vista?
TaggartJ

Entrambi i casi. Se l'entità è nuova e il modale viene utilizzato per selezionare entità correlate, la selezione effettuata deve già essere filtrata dal browser entità, facendo nuovamente clic sul pulsante "Seleziona" (prima che l'entità sia stata salvata). E ovviamente, dopo che è stato salvato e sta per essere modificato, l'attuale selezione ( #default_value) deve essere considerata anche come filtro.
Mario Steinitz,

Risposte:


4

Entity Browser non passa attualmente il campo degli elementi del valore predefinito corrente nei dati persistenti, ma è facile aggiungerlo.

1) Aggiungi dati persistenti usando field_widget_form_alter ()

/**
 * 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) Aggiorna la tua selezione in modo che se in bianco mostra tutto:

  /**
   * {@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) Assicurati di aver selezionato "escludi" e "consenti più" sulla selezione.

inserisci qui la descrizione dell'immagine

A proposito, se aggiorni all'ultima versione di sviluppo di entity_browser, non hai bisogno del tuo plugin personalizzato. Esiste un nuovo plug-in viste valore predefinito entity_browser_widget_context che è configurabile.

Ho anche aggiunto un problema alla coda entity_browser per aggiungere queste informazioni in widget_context.


2

Ho usato la tua classe di argomenti predefinita e ho eseguito il debug un po '. Questo è il mio approccio:

Il widget del browser entità memorizza i valori selezionati nella sua currentproprietà, che viene riempita quando il modulo entità viene aperto con un'entità / selezione esistente. Il widget utilizza anche AJAX quando il modale si chiude e la currentproprietà viene aggiornata di conseguenza.

Quindi puoi ottenere gli ID entità selezionati usando qualcosa come il seguente nel tuo modulo entità / modifica modulo:

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'];
    }
  }
}

Un'altra proprietà del widget disponibile nel modulo è il contesto del widget del browser dell'entità utilizzato. È possibile semplicemente aggiungere la selezione corrente al contesto del widget e utilizzare queste informazioni con l'argomento predefinito delle viste (il contesto del widget viene aggiornato nella memoria di selezione su ogni ricarica AJAX del widget / modulo):

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

Quindi modifica il tuo 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;
  }

Con queste modifiche sono stato in grado di filtrare gli elementi selezionati dalla mia vista con un filtro contestuale per gli ID entità, scegliendo

  • Quando il filtro non è disponibile: fornire un valore predefinito, digitare "Selezione browser entità"
  • Altro: escludi

Spero che sia d'aiuto!


0

Non sono riuscito a far funzionare il filtro predefinito, ma ho avuto un certo successo facendo la seguente paura:

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;
        }
      }
    }
  }
}

Questo funziona. Tuttavia, ci sono alcune ipotesi fatte ... Buona cosa il browser delle entità ti consente di selezionare quale vista.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.