View source
<?php
namespace Drupal\entity_field_condition\Plugin\Condition;
use Drupal\Core\Render\Element;
use Drupal\Core\Form\SubformState;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Condition\ConditionPluginBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Field\FieldTypePluginManagerInterface;
use Drupal\entity_field_condition\Contracts\EntityFieldCompareTypeInterface;
use Drupal\entity_field_condition\Contracts\EntityFieldCompareTypeManagerInterface;
class EntityField extends ConditionPluginBase implements ContainerFactoryPluginInterface {
protected $entityTypeManager;
protected $entityFieldManager;
protected $fieldTypePluginManager;
protected $entityTypeBundleInfo;
protected $entityFieldCompareTypeManager;
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info, FieldTypePluginManagerInterface $field_type_plugin_manager, EntityFieldCompareTypeManagerInterface $entity_field_compare_type_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->entityTypeManager = $entity_type_manager;
$this->entityFieldManager = $entity_field_manager;
$this->entityTypeBundleInfo = $entity_type_bundle_info;
$this->fieldTypePluginManager = $field_type_plugin_manager;
$this->entityFieldCompareTypeManager = $entity_field_compare_type_manager;
}
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container
->get('entity_type.manager'), $container
->get('entity_field.manager'), $container
->get('entity_type.bundle.info'), $container
->get('plugin.manager.field.field_type'), $container
->get('plugin.manager.entity_field_condition.compare_type'));
}
public function defaultConfiguration() : array {
return [
'entity' => [
'bundle' => NULL,
'field' => NULL,
'compare_type' => NULL,
'compare_configuration' => [],
],
] + parent::defaultConfiguration();
}
public function buildConfigurationForm(array $form, FormStateInterface $form_state) : array {
$parents = $form['#parents'] ?? $this
->resolveFormParents($form_state);
$wrapper_id = $this
->buildWrapperId();
$form['entity'] = [
'#tree' => TRUE,
'#type' => 'container',
'#prefix' => "<div id='{$wrapper_id}'>",
'#suffix' => '</div>',
];
$entity_bundle = $this
->getFormStateValue(array_merge($parents, [
'entity',
'bundle',
]), $form_state, $this
->getEntityBundleType());
$form['entity']['bundle'] = [
'#type' => 'select',
'#title' => $this
->t('Entity Type'),
'#options' => $this
->getEntityContextDataEntityBundleOptions(),
'#empty_option' => $this
->t('- None -'),
'#default_value' => $entity_bundle,
'#ajax' => [
'event' => 'change',
'method' => 'replace',
'callback' => [
$this,
'ajaxCallback',
],
'wrapper' => $wrapper_id,
'progress' => [
'type' => 'throbber',
'message' => $this
->t('Loading fields...'),
],
],
];
if (isset($entity_bundle) && !empty($entity_bundle)) {
$form['entity']['field'] = [
'#type' => 'select',
'#title' => $this
->t('Field'),
'#required' => TRUE,
'#options' => $this
->getEntityBundleFieldOptions($entity_bundle),
'#default_value' => $this
->getEntityFieldName(),
];
$compare_type_id = $this
->getFormStateValue(array_merge($parents, [
'entity',
'compare_type',
]), $form_state, $this
->getConfigurationEntity()['compare_type']);
$compare_type_options = $this->entityFieldCompareTypeManager
->getDefinitionOptions();
$form['entity']['compare_type'] = [
'#type' => 'select',
'#title' => $this
->t('Compare Type'),
'#required' => TRUE,
'#options' => $compare_type_options,
'#empty_option' => $this
->t('- None -'),
'#default_value' => $compare_type_id,
'#ajax' => [
'event' => 'change',
'method' => 'replace',
'callback' => [
$this,
'ajaxCallback',
],
'wrapper' => $wrapper_id,
'progress' => [
'type' => 'throbber',
'message' => $this
->t('Loading compare type...'),
],
],
];
if (isset($compare_type_id, $compare_type_options[$compare_type_id])) {
$form['entity']['compare_configuration'] = [
'#type' => 'fieldset',
'#title' => $this
->t('Compare Configuration'),
'#tree' => TRUE,
];
try {
$instance = $this->entityFieldCompareTypeManager
->createInstance($compare_type_id, $this
->getCompareTypeConfigurations());
if ($instance instanceof EntityFieldCompareTypeInterface) {
$subform = [
'#parents' => array_merge($parents, [
'entity',
'compare_configuration',
]),
];
$form['entity']['compare_configuration'] += $instance
->buildConfigurationForm($subform, SubformState::createForSubform($subform, $form, $form_state));
}
} catch (\RuntimeException $exception) {
watchdog_exception('entity_field_condition', $exception);
}
if (count(Element::children($form['entity']['compare_configuration'])) === 0) {
unset($form['entity']['compare_configuration']);
}
}
}
return parent::buildConfigurationForm($form, $form_state);
}
protected function buildWrapperId() : string {
return Html::getId(implode('-', [
'entity-field-condition',
$this
->getPluginId(),
]));
}
protected function getEntityContextDataEntityBundleOptions() : array {
$options = [];
foreach ($this
->getEntityContextDataEntityBundleTypes() as $type => $info) {
if (!isset($info['label'])) {
continue;
}
$options[$type] = $info['label'];
}
return $options;
}
protected function getEntityBundleFieldOptions(string $bundle) : array {
if (empty($bundle)) {
return [];
}
$options = [];
$field_types = $this->fieldTypePluginManager
->getDefinitions();
foreach ($this
->getEntityContextDataEntityFieldDefinitions($bundle) as $definition) {
$type = $definition
->getType();
if (!isset($field_types[$type])) {
continue;
}
$category = $field_types[$type]['label'];
$options[$category
->render()][$definition
->getName()] = $definition
->getLabel();
}
return $options;
}
public function ajaxCallback(array $form, FormStateInterface $form_state) : array {
$button = $form_state
->getTriggeringElement();
return NestedArray::getValue($form, array_splice($button['#array_parents'], 0, -1));
}
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) : void {
if ($compare_type_id = $form_state
->getValue([
'entity',
'compare_type',
])) {
try {
$instance = $this->entityFieldCompareTypeManager
->createInstance($compare_type_id, $this
->getCompareTypeConfigurations());
$parents = $form['#parents'] ?? [];
if ($instance instanceof EntityFieldCompareTypeInterface) {
$subform = [
'#parents' => array_merge($parents, [
'entity',
'compare_configuration',
]),
];
$instance
->validateConfigurationForm($subform, SubformState::createForSubform($subform, $form, $form_state));
}
} catch (\RuntimeException $exception) {
watchdog_exception('entity_field_condition', $exception);
}
}
}
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) : void {
parent::submitConfigurationForm($form, $form_state);
$values = $form_state
->cleanValues()
->getValues();
if (!isset($values['entity']['bundle']) || empty($values['entity']['bundle'])) {
$values = [];
}
if ($compare_type_id = $form_state
->getValue([
'entity',
'compare_type',
])) {
try {
$instance = $this->entityFieldCompareTypeManager
->createInstance($compare_type_id, $this
->getCompareTypeConfigurations());
$parents = $form['#parents'] ?? [];
if ($instance instanceof EntityFieldCompareTypeInterface) {
$subform_parents = [
'entity',
'compare_configuration',
];
$subform = [
'#parents' => array_merge($parents, $subform_parents),
];
$instance
->submitConfigurationForm($subform, SubformState::createForSubform($subform, $form, $form_state));
NestedArray::setValue($values, $subform_parents, $instance
->getConfiguration());
}
} catch (\RuntimeException $exception) {
watchdog_exception('entity_field_condition', $exception);
}
}
$this
->setConfiguration($values);
}
public function evaluate() : bool {
$verdict = FALSE;
$field_name = $this
->getEntityFieldName();
$compare_type = $this
->getEntityFieldCompareType();
if (isset($field_name, $compare_type) && $this
->hasEntityContext()) {
$verdict = $compare_type
->evaluate($this
->getContextValue('entity'), $field_name);
}
return $this
->isNegated() ? !$verdict : $verdict;
}
public function summary() : ?TranslatableMarkup {
$entity_field = $this
->getEntityFieldName();
$entity_bundle = $this
->getEntityBundleType();
if (isset($entity_field, $entity_bundle)) {
$entity_definition = $this
->getEntityContextDataEntityDefinition();
return $this
->t('The @entity_type with bundle of @entity_bundle has a condition for @field.', [
'@entity_type' => $entity_definition
->getLabel(),
'@entity_bundle' => $entity_bundle,
'@field' => $entity_field,
]);
}
return NULL;
}
protected function getFormStateValue($key, FormStateInterface $form_state, $default = NULL, bool $checkEmpty = FALSE) {
$key = !is_array($key) ? [
$key,
] : $key;
$inputs = [
$form_state
->getValues(),
$form_state
->getUserInput(),
];
foreach ($inputs as $input) {
$key_exist = FALSE;
$value = NestedArray::getValue($input, $key, $key_exist);
if ($key_exist) {
if ($checkEmpty === TRUE && empty($value)) {
continue;
}
return $value;
}
}
return $default;
}
protected function hasEntityContext() : bool {
return $this
->getContextValue('entity') instanceof ContentEntityInterface;
}
protected function getConfigurationEntity() : array {
return $this
->getConfiguration()['entity'] ?? [];
}
protected function getEntityFieldName() : ?string {
return $this
->getConfigurationEntity()['field'] ?? NULL;
}
protected function getEntityBundleType() : ?string {
return $this
->getConfigurationEntity()['bundle'] ?? NULL;
}
protected function getCompareTypeConfigurations() : array {
return $this
->getConfigurationEntity()['compare_configuration'] ?? [];
}
protected function resolveFormParents(FormStateInterface $form_state) : array {
$parents = [];
if ($form_object = $form_state
->getFormObject()) {
switch (get_class($form_object)) {
case 'Drupal\\block\\BlockForm':
$parents = [
'visibility',
$this
->getPluginId(),
];
break;
case 'Drupal\\block_visibility_groups\\Form\\ConditionAddForm':
$parents = [
'condition',
];
break;
}
}
return $parents;
}
protected function getEntityFieldCompareType() : ?EntityFieldCompareTypeInterface {
$compare_type_id = $this
->getConfigurationEntity()['compare_type'] ?? NULL;
if (!isset($compare_type_id)) {
return NULL;
}
return $this->entityFieldCompareTypeManager
->createInstance($compare_type_id, $this
->getCompareTypeConfigurations());
}
protected function getEntityContextDataEntityTypeId() : ?string {
$context_definition = $this
->getContextDefinition('entity');
if (!isset($context_definition)) {
return NULL;
}
$data_definition = $context_definition
->getDataDefinition();
return $data_definition
->getEntityTypeId();
}
protected function getEntityContextDataEntityDefinition() : EntityTypeInterface {
return $this->entityTypeManager
->getDefinition($this
->getEntityContextDataEntityTypeId());
}
protected function getEntityContextDataEntityFieldDefinitions(string $bundle) : array {
return $this->entityFieldManager
->getFieldDefinitions($this
->getEntityContextDataEntityTypeId(), $bundle);
}
protected function getEntityContextDataEntityBundleTypes() : array {
return $this->entityTypeBundleInfo
->getBundleInfo($this
->getEntityContextDataEntityTypeId());
}
}