Skip to content
Snippets Groups Projects

Draft: Resolve #3443882 "Plugin option attribute"

Closed godotislate requested to merge issue/drupal-3443882:3443882-plugin-option-attribute into 11.x
Files
16
<?php
declare(strict_types=1);
namespace Drupal\Component\Plugin\Attribute;
use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
use Drupal\Component\Utility\NestedArray;
/**
* Attribute class for adding optional property values to plugin definitions.
*/
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)]
class PluginProperty extends AttributeBase implements PluginPropertyInterface {
/**
* Constructs a plugin property object.
*
* @param int|string|array{int,string} $key
* The property key to set in the plugin in the definition. If the key is an
* array, it will be treated as a nested key, with the outermost keys coming
* first.
* @param mixed $value
* The value to set the property to.
* @param class-string[] $allowedPluginClasses
* List of plugin attribute class names that this property attribute can set
* properties on. If list is empty, property can be applied to any plugin.
* @param bool $allowOverride
* Whether the plugin can override property value already defined and set.
* @param string|null $provider
* The provider of the attribute class.
* @param mixed $addToDefinitionCallback
* Callable that adds the property to the plugin definition. If NULL and the
* plugin definition is an array, the property will be set by nested key on
* the array. Callback function parameters are this plugin property
* attribute object and the plugin definition:
* @code
* function exampleAddToDefinitionCallback(PluginProperty $attribute, array|object $definition): array|object {}
* @endcode
*/
public function __construct(
public readonly int|string|array $key,
public readonly mixed $value,
public readonly array $allowedPluginClasses = [],
public readonly bool $allowOverride = FALSE,
public ?string $provider = 'core',
public mixed $addToDefinitionCallback = NULL,
) {
if ($key === []) {
throw new \InvalidArgumentException('Key can not be an empty array.');
}
// Can not serialize closures, so prevent their use.
if ($this->addToDefinitionCallback instanceof \Closure) {
throw new \InvalidArgumentException('Add to definition callback can not be a closure.');
}
}
/**
* {@inheritdoc}
*/
public function getKey(): int|string|array {
return $this->key;
}
/**
* {@inheritdoc}
*/
public function getValue(): mixed {
return $this->value;
}
/**
* {@inheritdoc}
*/
public function isValidPluginClass(string $plugin_class): bool {
if (empty($this->allowedPluginClasses)) {
return TRUE;
}
foreach ($this->allowedPluginClasses as $allowed_class) {
if (is_a($plugin_class, $allowed_class, TRUE)) {
return TRUE;
}
}
return FALSE;
}
/**
* {@inheritdoc}
*/
public function allowsExistingPropertyOverride(): bool {
return $this->allowOverride;
}
/**
* {@inheritdoc}
*/
public function addToDefinition(array|object $definition): array|object {
if (isset($this->addToDefinitionCallback)) {
if (is_callable($this->addToDefinitionCallback)) {
return ($this->addToDefinitionCallback)($this, $definition);
}
throw new InvalidPluginDefinitionException($definition['id'], 'Can not add property to plugin definition because specified callback is invalid.');
}
// Plugin property classes that work with plugin attributes that return an
// object from Plugin::get() will need to override this method.
if (is_array($definition)) {
$key = is_array($this->key) ? $this->key : [$this->key];
if (!$this->allowOverride && NestedArray::keyExists($definition, $key)) {
throw new InvalidPluginDefinitionException($definition['id'], sprintf('Can not override %s plugin definition property at key: [%s].', $definition['class'], implode(', ', $key)));
}
NestedArray::setValue($definition, $key, $this->value);
}
return $definition;
}
}
Loading