eca-1.0.x-dev/modules/content/src/Plugin/ECA/Condition/EntityFieldValue.php
modules/content/src/Plugin/ECA/Condition/EntityFieldValue.php
<?php
namespace Drupal\eca_content\Plugin\ECA\Condition;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\Context\ContextDefinition;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\TypedData\ComplexDataInterface;
use Drupal\Core\TypedData\Plugin\DataType\BooleanData;
use Drupal\Core\TypedData\PrimitiveInterface;
use Drupal\Core\TypedData\TraversableTypedDataInterface;
use Drupal\eca\Attribute\EcaCondition;
use Drupal\eca\Plugin\ECA\Condition\ConditionInterface;
use Drupal\eca\Plugin\ECA\Condition\StringComparisonBase;
use Drupal\eca\TypedData\PropertyPathTrait;
/**
* Plugin implementation of the ECA condition for an entity field value.
*/
#[EcaCondition(
id: 'eca_entity_field_value',
label: new TranslatableMarkup('Entity: compare field value'),
context_definitions: [
'entity' => new ContextDefinition(
data_type: 'entity',
label: new TranslatableMarkup('Entity'),
),
],
description: new TranslatableMarkup('Compares a field value with an expected custom value.'),
version_introduced: '1.0.0',
)]
class EntityFieldValue extends StringComparisonBase {
use PropertyPathTrait;
/**
* {@inheritdoc}
*
* This class takes care of Token replacements on its own.
*/
protected static bool $replaceTokens = FALSE;
/**
* The configured and tokenized field name.
*
* @var string|null
*/
protected ?string $fieldName;
/**
* The configured value as expected field value.
*
* @var string|null
*/
protected ?string $expectedValue;
/**
* The target field value to evaluate the expected value against.
*
* @var string|null
*/
protected ?string $targetValue;
/**
* {@inheritdoc}
*/
public function reset(): ConditionInterface {
$this->fieldName = NULL;
$this->expectedValue = NULL;
$this->targetValue = NULL;
return parent::reset();
}
/**
* {@inheritdoc}
*/
protected function getLeftValue(): string {
$target_value = $this->targetValue ?? $this->getTargetValue();
if (NULL === $target_value && $this->getRightValue() === '') {
// Since the StringComparisonBase always compares string values, we want
// to make sure, that the evaluation will return FALSE for the very rare
// situation, that an empty string is expected to be contained.
return '_ENTITY_FIELD_VALUE_IS_NULL_';
}
return $target_value ?? '';
}
/**
* {@inheritdoc}
*/
protected function getRightValue(): string {
return $this->getExpectedValue();
}
/**
* Get the configured and tokenized field name.
*
* @return string
* The tokenized field name.
*/
protected function getFieldName(): string {
if (!isset($this->fieldName)) {
$this->fieldName = trim((string) $this->tokenService->replaceClear($this->configuration['field_name'] ?? ''));
}
return $this->fieldName;
}
/**
* Get the configured and tokenized value as expected field value.
*
* @return string
* The expected value.
*/
protected function getExpectedValue(): string {
if (!isset($this->expectedValue)) {
$this->expectedValue = trim((string) $this->tokenService->replaceClear($this->configuration['expected_value'] ?? ''));
}
return $this->expectedValue;
}
/**
* Get the target field value to evaluate against.
*
* @return string|null
* The target field value as string or NULL if no value is present.
*/
protected function getTargetValue(): ?string {
$field_values = $this->getFieldValues();
$num_items = count($field_values);
switch ($num_items) {
case 0:
$target_value = NULL;
break;
case 1:
$target_value = reset($field_values);
break;
default:
// When the field contains multiple values, we evaluate against
// every single item and stick with the first match found.
$target_value = NULL;
$negated = $this->isNegated();
$this->configuration['negate'] = FALSE;
foreach ($field_values as $field_value) {
$this->targetValue = $field_value;
if ($this->evaluate()) {
$target_value = $field_value;
break;
}
}
$this->targetValue = NULL;
$this->configuration['negate'] = $negated;
}
return $target_value;
}
/**
* Get a list of field values to evaluate against.
*
* @return string[]
* The list of field values.
*/
protected function getFieldValues(): array {
$field_name = $this->getFieldName();
$entity = $this->getEntity();
$values = [];
$options = [
'auto_append' => FALSE,
'auto_item' => FALSE,
'access' => FALSE,
];
if ($entity && ($list = $this->getTypedProperty($entity->getTypedData(), $field_name, $options))) {
if (!($list instanceof TraversableTypedDataInterface)) {
$list = [$list];
}
/**
* @var \Drupal\Core\TypedData\TypedDataInterface $property
*/
foreach ($list as $property) {
if ($property instanceof ComplexDataInterface) {
$main_property = $property->getDataDefinition()->getMainPropertyName();
if ($main_property !== NULL) {
$property = $property->get($main_property);
}
}
if ($property instanceof BooleanData) {
$values[] = (string) (int) $property->getValue();
}
elseif ($property instanceof PrimitiveInterface) {
$values[] = (string) $property->getValue();
}
}
}
return $values;
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration(): array {
return [
'expected_value' => '',
'field_name' => '',
] + parent::defaultConfiguration();
}
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state): array {
$form['field_name'] = [
'#type' => 'textfield',
'#title' => $this->t('Field name'),
'#default_value' => $this->configuration['field_name'] ?? '',
'#description' => $this->t('The name of the field whose value to compare.'),
'#weight' => -90,
];
$form['expected_value'] = [
'#type' => 'textfield',
'#title' => $this->t('Expected field value'),
'#description' => $this->t('The expected value.'),
'#default_value' => $this->configuration['expected_value'] ?? '',
'#weight' => -70,
];
return parent::buildConfigurationForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state): void {
$this->configuration['field_name'] = $form_state->getValue('field_name');
$this->configuration['expected_value'] = $form_state->getValue('expected_value');
parent::submitConfigurationForm($form, $form_state);
}
/**
* Get the entity to act upon.
*
* @return \Drupal\Core\Entity\EntityInterface|null
* The entity, or NULL if not found.
*/
public function getEntity(): ?EntityInterface {
return $this->getValueFromContext('entity');
}
}
