eca-1.0.x-dev/modules/form/src/Token/CurrentFormDataProvider.php
modules/form/src/Token/CurrentFormDataProvider.php
<?php
namespace Drupal\eca_form\Token;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Entity\ContentEntityFormInterface;
use Drupal\Core\Entity\EntityFormInterface;
use Drupal\Core\Form\BaseFormIdInterface;
use Drupal\eca\Attribute\Token;
use Drupal\eca\Event\FormEventInterface;
use Drupal\eca\EventSubscriber\EcaExecutionFormSubscriber;
use Drupal\eca\Plugin\DataType\DataTransferObject;
use Drupal\eca\Token\DataProviderInterface;
/**
* Provides data of the current form.
*/
class CurrentFormDataProvider implements DataProviderInterface {
/**
* The ECA form event subscriber.
*
* @var \Drupal\eca\EventSubscriber\EcaExecutionFormSubscriber|null
*/
protected ?EcaExecutionFormSubscriber $subscriber = NULL;
/**
* In-memory cache of instantiated data.
*
* @var array
*/
protected static array $cached = [];
/**
* {@inheritdoc}
*/
#[Token(
name: 'form',
description: 'The current form.',
classes: [FormEventInterface::class],
properties: [
new Token(name: 'id', description: 'The form ID.'),
new Token(name: 'base_id', description: 'The form base ID.'),
new Token(name: 'operation', description: 'The form operation.'),
new Token(name: 'mode', description: 'The form mode.'),
new Token(name: 'triggered', description: 'The form field name that triggered the form event.'),
new Token(name: 'values', description: '', properties: [
new Token(name: 'FIELD_NAME', description: 'The field value for each of the named fields.'),
]),
new Token(name: 'num_errors', description: 'The number of form errors.'),
],
aliases: ['current_form'],
)]
public function getData(string $key): mixed {
if (!($events = $this->subscriber()->getStackedFormEvents())) {
return NULL;
}
$form_state = reset($events)->getFormState();
switch ($key) {
case 'form':
case 'current_form':
$form_object = $form_state->getFormObject();
$dto_values = [
'id' => $form_object->getFormId(),
'base_id' => $form_object instanceof BaseFormIdInterface ? $form_object->getBaseFormId() : NULL,
'operation' => $form_object instanceof EntityFormInterface ? $form_object->getOperation() : NULL,
'mode' => $form_object instanceof ContentEntityFormInterface ? $form_object->getFormDisplay($form_state)->id() : NULL,
'dangerous_raw_values' => array_merge($form_state->getUserInput(), $form_state->getValues()),
'triggered' => NULL,
];
if ($triggering_element = $form_state->getTriggeringElement()) {
if ($triggering_element['#name'] === 'op' && !empty($triggering_element['#array_parents'])) {
$dto_values['triggered'] = end($triggering_element['#array_parents']);
}
else {
$dto_values['triggered'] = $triggering_element['#name'];
}
}
if (isset(static::$cached['form_dto_values'], static::$cached['form_dto']) && (static::$cached['form_dto_values'] === $dto_values)) {
$dto = static::$cached['form_dto'];
}
else {
$dto = DataTransferObject::create([
'id' => $dto_values['id'],
'base_id' => $dto_values['base_id'],
'operation' => $dto_values['operation'],
'mode' => $dto_values['mode'],
'triggered' => $dto_values['triggered'],
]);
if (!empty($dto_values['dangerous_raw_values'])) {
$values_sanitized = $dto_values['dangerous_raw_values'];
array_walk_recursive($values_sanitized, static function (&$value) {
if (!$value) {
return;
}
if (is_scalar($value) || (is_object($value) && method_exists($value, '__toString'))) {
$value = trim(Xss::filter(strip_tags((string) $value)));
}
});
$dto->set('values', $values_sanitized);
}
}
$dto->set('num_errors', count($form_state->getErrors()));
static::$cached['form_dto_values'] = $dto_values;
static::$cached['form_dto'] = $dto;
return $dto;
default:
return NULL;
}
}
/**
* {@inheritdoc}
*/
public function hasData(string $key): bool {
return $this->getData($key) !== NULL;
}
/**
* Get the ECA form event subscriber.
*
* This service can not be obtained through dependency injection, because
* this may lead to a circular reference.
*
* @see https://www.drupal.org/project/eca/issues/3318655
*
* @return \Drupal\eca\EventSubscriber\EcaExecutionFormSubscriber
* The subscriber.
*/
protected function subscriber(): EcaExecutionFormSubscriber {
if (!isset($this->subscriber)) {
$this->subscriber = EcaExecutionFormSubscriber::get();
}
return $this->subscriber;
}
}
