如何将当前选择传递给实体浏览器选择视图


8

我正在使用实体浏览器(在Drupal 8中为2.x-dev)作为自定义实体的实体引用基础字段的表单小部件。实体浏览器已配置

  • 作为模式显示
  • 使用单个小部件,
  • 没有选择显示,
  • 使用带有实体浏览器批量选择字段的视图作为小部件,以及
  • 将所选实体附加到参考字段的当前选择中。

选择实体工作正常。但是实体参考字段不得重复。

为了简化没有重复项的实体的选择,我想从实体浏览器视图结果中过滤已经选择的实体。因此,用户将仅看到未选择的实体。

为此,我创建了一个自定义视图arguments_default插件,该插件将实体浏览器选择存储公开为实体ID的上下文默认参数:

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

}

我面临的问题是,无论在实体参考字段中选择了多少个实体,即使在我完成模式选择并再次打开实体浏览器之后,选择存储中的当前选择始终为空。

要在实体浏览器的选择存储中公开当前选择,我该怎么办?


等待,所以您的意思是,如果您已经选择(并保存了)一个项目,那么您不希望该项目作为可选项目在模式中显示吗?还是意味着不允许即时选择重复...还是意味着您希望所有内容都具有唯一数据(如果选中)然后从视图中隐藏?
taggartJ

两种情况。如果实体是新实体,并且使用模态来选择相关实体,则再次单击“选择”按钮(在保存实体之前),就应该已经从实体浏览器中过滤了所做的选择。当然,在将其保存并要重新编辑之后,也需要将当前选择(#default_value)视为过滤器。
Mario Steinitz

Answers:


4

实体浏览器当前不会在持久性数据中传递当前默认值项目字段,但是添加起来很容易。

1)使用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)更新您的选择,以使其空白显示所有内容:

  /**
   * {@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)确保选中了“排除”和“允许多个”。

在此处输入图片说明

顺便说一句,如果您更新到最新的dev_entry_browser开发版本,则不需要自定义插件。有一个可配置的新的entity_browser_widget_context默认值视图插件。

我还添加了一个问题到Entity_browser队列中,以在widget_context中添加此信息。


2

我使用了默认的参数类并进行了调试。这是我的方法:

current当使用现有实体/选择打开实体表单时,实体浏览器窗口小部件将所选值存储在其属性中,该属性将被填充。当模式关闭并且相应地current更新属性时,小部件还使用AJAX 。

因此,您可以在实体表单/表单alter中使用类似以下内容的方法来获取选定的实体ID:

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

表单中可用的另一个窗口小部件属性是所用实体浏览器的窗口小部件上下文。您可以简单地将当前选择添加到窗口小部件上下文中,并将此信息与您的视图默认参数一起使用(在窗口小部件/表单每次重新加载AJAX时,选择存储中的窗口小部件上下文都会更新):

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

然后更改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;
  }

通过这些更改,我可以使用针对实体ID的上下文过滤器从视图中过滤选定的项目,选择

  • 当筛选器不可用时:提供一个默认值,键入“实体浏览器选择”
  • 更多:排除

希望能帮助到你!


0

我无法使用默认过滤器,但在执行以下令人恐惧的工作时我确实取得了一些成功:

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

这确实有效。但是,有许多假设。好东西实体浏览器允许您选择哪个视图。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.