View source
<?php
namespace Drupal\business_rules\Plugin\EntityReferenceSelection;
use Drupal\business_rules\Ajax\UpdateOptionsCommand;
use Drupal\business_rules\Util\BusinessRulesUtil;
use Drupal\Component\Utility\Html;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Database\Query\SelectInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityReferenceSelection\SelectionInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Plugin\PluginBase;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Drupal\views\ViewExecutable;
use Drupal\views\Views;
use Symfony\Component\DependencyInjection\ContainerInterface;
class BusinessRulesViewsSelection extends PluginBase implements SelectionInterface, ContainerFactoryPluginInterface {
protected $currentUser;
protected $entityManager;
protected $moduleHandler;
protected $util;
protected $view;
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler, AccountInterface $current_user, BusinessRulesUtil $util) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->entityManager = $entity_manager;
$this->moduleHandler = $module_handler;
$this->currentUser = $current_user;
$this->util = $util;
}
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container
->get('entity.manager'), $container
->get('module_handler'), $container
->get('current_user'), $container
->get('business_rules.util'));
}
public static function settingsFormValidate($element, FormStateInterface $form_state, $form) {
if (!empty($element['view_and_display']['#value'])) {
list($view, $display) = explode(':', $element['view_and_display']['#value']);
}
else {
$form_state
->setError($element, t('The views entity selection mode requires a view.'));
return;
}
$arguments_string = trim($element['arguments']['#value']);
if ($arguments_string === '') {
$arguments = [];
}
else {
$arguments = array_map('trim', explode(',', $arguments_string));
}
$value = [
'view_name' => $view,
'display_name' => $display,
'arguments' => $arguments,
'parent_field' => $element['parent_field']['#value'],
'reference_parent_by_uuid' => $element['reference_parent_by_uuid']['#value'],
];
$form_state
->setValueForElement($element, $value);
}
public static function updateDependentField(array $form, FormStateInterface $form_state) {
$entity = $form_state
->getFormObject()
->getEntity();
$trigger_field = $form_state
->getTriggeringElement();
$children = $trigger_field['#ajax']['br_children'];
$response = new AjaxResponse();
foreach ($children as $child) {
$field_definition = $entity
->getFieldDefinitions();
if ($field_definition[$child]
->getSetting('handler') == 'business_rules_views') {
$handler_settings = $field_definition[$child]
->getSetting('handler_settings');
$view = Views::getView($handler_settings['business_rules_view']['view_name']);
$parent_field_value = $trigger_field['#value'];
if ($trigger_field['#type'] === 'entity_autocomplete' && preg_match('/\\((\\d+)\\)$/', $parent_field_value, $matches)) {
$parent_field_value = $matches[1];
}
if (!empty($handler_settings['business_rules_view']['reference_parent_by_uuid'])) {
$parent_field_value = static::convertEntityIdsToUuids($parent_field_value, $view
->getBaseEntityType()
->id());
}
if (is_array($parent_field_value)) {
$parent_field_value = implode(",", $parent_field_value);
}
$arguments = $handler_settings['business_rules_view']['arguments'];
$view
->setArguments(!empty($parent_field_value) ? [
$parent_field_value,
] + $arguments : $arguments);
$view
->setDisplay($handler_settings['business_rules_view']['display_name']);
$view
->preExecute();
$view
->build();
$options = static::getViewOptions($view);
$form_field = $form[$child];
$form_field['widget']['#options'] = $options;
$html_field_id = explode('-wrapper-', $form_field['#id'])[0];
$html_field_id = substr($child, strlen($child) - 1, 1) == '_' ? $html_field_id . '-' : $html_field_id;
$formatter = $form_field['widget']['#type'];
$response
->addCommand(new UpdateOptionsCommand($html_field_id, $options, $formatter));
}
}
return $response;
}
protected static function convertEntityIdsToUuids($entity_ids, string $entity_type) {
if (!is_array($entity_ids)) {
$entity_ids = [
$entity_ids,
];
}
$uuids = [];
foreach ($entity_ids as $entity_id) {
$uuids[] = \Drupal::entityTypeManager()
->getStorage($entity_type)
->load($entity_id)
->uuid();
}
return $uuids;
}
protected static function getViewOptions(ViewExecutable $view) {
$options = [];
if ($view
->execute()) {
$renderer = \Drupal::service('renderer');
$render_array = $view->style_plugin
->render();
foreach ($render_array as $key => $value) {
$rendered_value = (string) $renderer
->render($value);
$options[] = [
'key' => $key,
'value' => Html::decodeEntities(strip_tags($rendered_value)),
];
}
}
uasort($options, function ($a, $b) {
return $a['value'] < $b['value'] ? -1 : 1;
});
array_unshift($options, [
'key' => '_none',
'value' => t('-Select-'),
]);
return $options;
}
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$handler_settings = $this
->getHandlerSettings();
$view_settings = !empty($handler_settings['business_rules_view']) ? $handler_settings['business_rules_view'] : [];
$displays = Views::getApplicableViews('entity_reference_display');
$entity_type = $this->entityManager
->getDefinition($this->configuration['target_type']);
$view_storage = $this->entityManager
->getStorage('view');
$options = [];
foreach ($displays as $data) {
list($view_id, $display_id) = $data;
$view = $view_storage
->load($view_id);
if (in_array($view
->get('base_table'), [
$entity_type
->getBaseTable(),
$entity_type
->getDataTable(),
])) {
$display = $view
->get('display');
$options[$view_id . ':' . $display_id] = $view_id . ' - ' . $display[$display_id]['display_title'];
}
}
$form['business_rules_view']['#element_validate'] = [
[
get_called_class(),
'settingsFormValidate',
],
];
if ($options) {
$form['business_rules_view']['help']['#markup'] = t('This plugin do not works for autocomplete form widget. Make sure you have selected "Select list" or "Check boxes/radio buttons" at "Manage form display" tab.');
$default = !empty($view_settings['view_name']) ? $view_settings['view_name'] . ':' . $view_settings['display_name'] : NULL;
$form['business_rules_view']['view_and_display'] = [
'#type' => 'select',
'#title' => $this
->t('View used to select the entities'),
'#required' => TRUE,
'#options' => $options,
'#default_value' => $default,
'#description' => '<p>' . $this
->t('Choose the view and display that select the entities that can be referenced.<br />Only views with a display of type "Entity Reference" are eligible.') . '</p>',
];
$field_config = $this->util->request
->get('field_config');
$entity_type = $field_config
->getTargetEntityTypeId();
$bundle = $field_config
->getTargetBundle();
$fields = $this->util
->getBundleEditableFields($entity_type, $bundle);
$fields_options = [];
if (count($fields)) {
foreach ($fields as $key => $name) {
if ($key !== 'title' && $key !== $field_config
->getName()) {
$fields_options[$key] = $name;
}
}
}
$default = !empty($view_settings['parent_field']) ? $view_settings['parent_field'] : NULL;
$form['business_rules_view']['parent_field'] = [
'#type' => 'select',
'#title' => t('Parent field'),
'#options' => $fields_options,
'#required' => TRUE,
'#description' => t('The field which this field depends. When the parent field value is changed, the available options for this field will be updated using the parent field value as the first argument followed by any particular other argument imputed in the "Views arguments".'),
'#default_value' => $default,
];
$default = !empty($view_settings['reference_parent_by_uuid']) ? $view_settings['reference_parent_by_uuid'] : FALSE;
$form['business_rules_view']['reference_parent_by_uuid'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Reference parent by UUID instead of entity ID?'),
'#default_value' => $default,
'#description' => $this
->t('Required if the parent argument in your view (selected above) accepts UUIDs instead of entity IDs (to ensure configuration portability between sites).'),
];
$default = !empty($view_settings['arguments']) ? implode(', ', $view_settings['arguments']) : '';
$form['business_rules_view']['arguments'] = [
'#type' => 'textfield',
'#title' => $this
->t('View arguments'),
'#default_value' => $default,
'#required' => FALSE,
'#description' => $this
->t('Provide a comma separated list of arguments to pass to the view.'),
];
}
else {
if ($this->currentUser
->hasPermission('administer views') && $this->moduleHandler
->moduleExists('views_ui')) {
$form['business_rules_view']['no_view_help'] = [
'#markup' => '<p>' . $this
->t('No eligible views were found. <a href=":create">Create a view</a> with an <em>Entity Reference</em> display, or add such a display to an <a href=":existing">existing view</a>.', [
':create' => Url::fromRoute('views_ui.add')
->toString(),
':existing' => Url::fromRoute('entity.view.collection')
->toString(),
]) . '</p>',
];
}
else {
$form['business_rules_view']['no_view_help']['#markup'] = '<p>' . $this
->t('No eligible views were found.') . '</p>';
}
}
return $form;
}
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
}
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
}
protected function initializeView($match = NULL, $match_operator = 'CONTAINS', $limit = 0, $ids = NULL) {
$handler_settings = $this
->getHandlerSettings();
$view_name = $handler_settings['business_rules_view']['view_name'];
$display_name = $handler_settings['business_rules_view']['display_name'];
$this->view = Views::getView($view_name);
if (!$this->view || !$this->view
->access($display_name)) {
drupal_set_message(t('The reference view %view_name cannot be found.', [
'%view_name' => $view_name,
]), 'warning');
return FALSE;
}
$this->view
->setDisplay($display_name);
$entity_reference_options = [
'match' => $match,
'match_operator' => $match_operator,
'limit' => $limit,
'ids' => $ids,
];
$this->view->displayHandlers
->get($display_name)
->setOption('entity_reference_options', $entity_reference_options);
return TRUE;
}
public function getReferenceableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) {
$handler_settings = $this
->getHandlerSettings();
$display_name = $handler_settings['business_rules_view']['display_name'];
$arguments = $handler_settings['business_rules_view']['arguments'];
$parent_field_value = $this
->getParentFieldValue($this->configuration['entity']);
if (is_array($parent_field_value) && !empty($parent_field_value['target_id']) && preg_match('/\\((\\d+)\\)$/', $parent_field_value['target_id'], $matches)) {
$parent_field_value = $matches[1];
}
if (is_array($parent_field_value)) {
$parent_field_value = implode(",", $parent_field_value);
}
$arguments = !empty($parent_field_value) ? [
$parent_field_value,
] + $arguments : $arguments;
$result = [];
if ($this
->initializeView($match, $match_operator, $limit)) {
$result = $this->view
->executeDisplay($display_name, $arguments);
}
$return = [];
if ($result) {
foreach ($this->view->result as $row) {
$entity = $row->_entity;
$return[$entity
->bundle()][$entity
->id()] = $entity
->label();
}
}
return $return;
}
public function countReferenceableEntities($match = NULL, $match_operator = 'CONTAINS') {
$this
->getReferenceableEntities($match, $match_operator);
return $this->view->pager
->getTotalItems();
}
public function validateReferenceableEntities(array $ids) {
$handler_settings = $this
->getHandlerSettings();
$display_name = $handler_settings['business_rules_view']['display_name'];
$arguments = $handler_settings['business_rules_view']['arguments'];
$parent_field_value = $this
->getParentFieldValue();
if (is_array($parent_field_value)) {
$parent_field_value = implode(",", $parent_field_value);
}
$arguments = !empty($parent_field_value) ? [
$parent_field_value,
] + $arguments : $arguments;
$result = [];
$ids = $this
->getValidIds($parent_field_value);
if ($this
->initializeView(NULL, 'CONTAINS', 0, $ids)) {
$entities = $this->view
->executeDisplay($display_name, $arguments);
$result = is_array($entities) ? array_keys($entities) : [];
}
return $result;
}
private function getValidIds($parent_field_value) {
$handler_settings = $this
->getHandlerSettings();
$display_name = $handler_settings['business_rules_view']['display_name'];
$arguments = $handler_settings['business_rules_view']['arguments'];
$arguments = !empty($parent_field_value) ? [
$parent_field_value,
] + $arguments : $arguments;
$result = [];
if ($this
->initializeView(NULL, 'CONTAINS', 0)) {
$result = $this->view
->executeDisplay($display_name, $arguments);
}
$return = [];
if ($result) {
foreach ($this->view->result as $row) {
$entity = $row->_entity;
$return[] = $entity
->id();
}
}
return $return;
}
public function entityQueryAlter(SelectInterface $query) {
}
protected function getParentFieldValue(EntityInterface $entity = NULL) {
$handler_settings = $this
->getHandlerSettings();
$field = $handler_settings['business_rules_view']['parent_field'];
$value = $this->util->request
->get($field);
if (!$value && $entity && $entity
->get($field)) {
$value = $entity
->get($field)
->getString();
}
if (is_array($value) && !empty($value[0]['target_id']) && preg_match('/\\((\\d+)\\)$/', $value[0]['target_id'], $matches)) {
$value = $matches[1];
}
return $value;
}
protected function getHandlerSettings() {
if (isset($this->configuration['handler_settings'])) {
return $this->configuration['handler_settings'];
}
return $this->configuration;
}
}