
| Current Path : /var/www/html/rocksensor/web/core/lib/Drupal/Core/Recipe/ |
Linux ift1.ift-informatik.de 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64 |
| Current File : /var/www/html/rocksensor/web/core/lib/Drupal/Core/Recipe/InputConfigurator.php |
<?php
declare(strict_types=1);
namespace Drupal\Core\Recipe;
use Drupal\Core\TypedData\DataDefinition;
use Drupal\Core\TypedData\TypedDataInterface;
use Drupal\Core\TypedData\TypedDataManagerInterface;
use Symfony\Component\Validator\Exception\ValidationFailedException;
/**
* Collects and validates input values for a recipe.
*
* @internal
* This API is experimental.
*/
final class InputConfigurator {
/**
* The input data.
*
* @var \Drupal\Core\TypedData\TypedDataInterface[]
*/
private array $data = [];
/**
* The collected input values, or NULL if none have been collected yet.
*
* @var mixed[]|null
*/
private ?array $values = NULL;
/**
* @param array<string, array<string, mixed>> $definitions
* The recipe's input definitions, keyed by name. This is an array of arrays
* where each sub-array has, at minimum:
* - `description`: A short, human-readable description of the input (e.g.,
* what the recipe uses it for).
* - `data_type`: A primitive data type known to the typed data system.
* - `constraints`: An optional array of validation constraints to apply
* to the value. This should be an associative array of arrays, keyed by
* constraint name, where each sub-array is a set of options for that
* constraint (identical to the way validation constraints are defined in
* config schema).
* - `default`: A default value for the input, if it cannot be collected
* the user. See ::getDefaultValue() for more information.
* @param \Drupal\Core\Recipe\RecipeConfigurator $dependencies
* The recipes that this recipe depends on.
* @param string $prefix
* A prefix for each input definition, to give each one a unique name
* when collecting input for multiple recipes. Usually this is the unique
* name of the recipe.
* @param \Drupal\Core\TypedData\TypedDataManagerInterface $typedDataManager
* The typed data manager service.
*/
public function __construct(
array $definitions,
private readonly RecipeConfigurator $dependencies,
private readonly string $prefix,
TypedDataManagerInterface $typedDataManager,
) {
// Convert the input definitions to typed data definitions.
foreach ($definitions as $name => $definition) {
$data_definition = DataDefinition::create($definition['data_type'])
->setDescription($definition['description'])
->setConstraints($definition['constraints'] ?? []);
unset(
$definition['data_type'],
$definition['description'],
$definition['constraints'],
);
$data_definition->setSettings($definition);
$this->data[$name] = $typedDataManager->create($data_definition);
}
}
/**
* Returns the typed data definitions for the inputs defined by this recipe.
*
* This does NOT return the data definitions for inputs defined by this
* recipe's dependencies.
*
* @return \Drupal\Core\TypedData\DataDefinitionInterface[]
* The typed data definitions, keyed by input name.
*/
public function getDataDefinitions(): array {
return array_map(fn (TypedDataInterface $data) => $data->getDataDefinition(), $this->data);
}
/**
* Returns the collected input values, keyed by name.
*
* @return mixed[]
* The collected input values, keyed by name.
*/
public function getValues(): array {
return $this->values ?? [];
}
/**
* Returns the description for all inputs of this recipe and its dependencies.
*
* @return string[]
* The descriptions of every input defined by the recipe and its
* dependencies, keyed by the input's fully qualified name (i.e., prefixed
* by the name of the recipe that defines it).
*/
public function describeAll(): array {
$descriptions = [];
foreach ($this->dependencies->recipes as $dependency) {
$descriptions = array_merge($descriptions, $dependency->input->describeAll());
}
foreach ($this->getDataDefinitions() as $key => $definition) {
$name = $this->prefix . '.' . $key;
$descriptions[$name] = $definition->getDescription();
}
return $descriptions;
}
/**
* Collects input values for this recipe and its dependencies.
*
* @param \Drupal\Core\Recipe\InputCollectorInterface $collector
* The input collector to use.
* @param string[] $processed
* The names of the recipes for which input has already been collected.
* Internal use only, should not be passed in by calling code.
*
* @throws \Symfony\Component\Validator\Exception\ValidationFailedException
* Thrown if any of the collected values violate their validation
* constraints.
*/
public function collectAll(InputCollectorInterface $collector, array &$processed = []): void {
// Don't bother collecting values for a recipe we've already seen.
if (in_array($this->prefix, $processed, TRUE)) {
return;
}
if (is_array($this->values)) {
throw new \LogicException('Input values cannot be changed once they have been set.');
}
// First, collect values for the recipe's dependencies.
/** @var \Drupal\Core\Recipe\Recipe $dependency */
foreach ($this->dependencies->recipes as $dependency) {
$dependency->input->collectAll($collector, $processed);
}
$this->values = [];
foreach ($this->data as $key => $data) {
$definition = $data->getDataDefinition();
$value = $collector->collectValue(
$this->prefix . '.' . $key,
$definition,
$this->getDefaultValue($definition),
);
$data->setValue($value, FALSE);
$violations = $data->validate();
if (count($violations) > 0) {
throw new ValidationFailedException($value, $violations);
}
$this->values[$key] = $data->getCastedValue();
}
$processed[] = $this->prefix;
}
/**
* Returns the default value for an input definition.
*
* @param array $definition
* An input definition. Must contain a `source` element, which can be either
* 'config' or 'value'. If `source` is 'config', then there must also be a
* `config` element, which is a two-element indexed array containing
* (in order) the name of an extant config object, and a property path
* within that object. If `source` is 'value', then there must be a `value`
* element, which will be returned as-is.
*
* @return mixed
* The default value.
*/
private function getDefaultValue(DataDefinition $definition): mixed {
$settings = $definition->getSetting('default');
if ($settings['source'] === 'config') {
[$name, $key] = $settings['config'];
$config = \Drupal::config($name);
if ($config->isNew()) {
throw new \RuntimeException("The '$name' config object does not exist.");
}
return $config->get($key);
}
return $settings['value'];
}
}