Drupal 8.0.0 beta 12. More info: https://www.drupal.org/node/2514176

This commit is contained in:
Pantheon Automation 2015-08-17 17:00:26 -07:00 committed by Greg Anderson
commit 9921556621
13277 changed files with 1459781 additions and 0 deletions

View file

@ -0,0 +1,51 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\CategorizingPluginManagerInterface.
*/
namespace Drupal\Component\Plugin;
/**
* Defines an interface for plugin managers that categorize plugin definitions.
*/
interface CategorizingPluginManagerInterface extends PluginManagerInterface {
/**
* Gets the names of all categories.
*
* @return string[]
* An array of translated categories, sorted alphabetically.
*/
public function getCategories();
/**
* Gets sorted plugin definitions.
*
* @param array[]|null $definitions
* (optional) The plugin definitions to sort. If omitted, all plugin
* definitions are used.
*
* @return array[]
* An array of plugin definitions, sorted by category and label.
*/
public function getSortedDefinitions(array $definitions = NULL);
/**
* Gets sorted plugin definitions grouped by category.
*
* In addition to grouping, both categories and its entries are sorted,
* whereas plugin definitions are sorted by label.
*
* @param array[]|null $definitions
* (optional) The plugin definitions to group. If omitted, all plugin
* definitions are used.
*
* @return array[]
* Keys are category names, and values are arrays of which the keys are
* plugin IDs and the values are plugin definitions.
*/
public function getGroupedDefinitions(array $definitions = NULL);
}

View file

@ -0,0 +1,41 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\ConfigurablePluginInterface.
*/
namespace Drupal\Component\Plugin;
/**
* Provides an interface for a configurable plugin.
*
* @ingroup plugin_api
*/
interface ConfigurablePluginInterface extends DependentPluginInterface {
/**
* Gets this plugin's configuration.
*
* @return array
* An array of this plugin's configuration.
*/
public function getConfiguration();
/**
* Sets the configuration for this plugin instance.
*
* @param array $configuration
* An associative array containing the plugin's configuration.
*/
public function setConfiguration(array $configuration);
/**
* Gets default configuration for this plugin.
*
* @return array
* An associative array with the default configuration.
*/
public function defaultConfiguration();
}

View file

@ -0,0 +1,103 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\Context\Context.
*/
namespace Drupal\Component\Plugin\Context;
use Drupal\Component\Plugin\Exception\ContextException;
use Symfony\Component\Validator\Constraints\Type;
use Symfony\Component\Validator\Validation;
/**
* A generic context class for wrapping data a plugin needs to operate.
*/
class Context implements ContextInterface {
/**
* The value of the context.
*
* @var mixed
*/
protected $contextValue;
/**
* The definition to which a context must conform.
*
* @var \Drupal\Component\Plugin\Context\ContextDefinitionInterface
*/
protected $contextDefinition;
/**
* Sets the contextDefinition for us without needing to call the setter.
*
* @param \Drupal\Component\Plugin\Context\ContextDefinitionInterface $context_definition
* The context definition.
*/
public function __construct(ContextDefinitionInterface $context_definition) {
$this->contextDefinition = $context_definition;
}
/**
* Implements \Drupal\Component\Plugin\Context\ContextInterface::setContextValue().
*/
public function setContextValue($value) {
$this->contextValue = $value;
}
/**
* Implements \Drupal\Component\Plugin\Context\ContextInterface::getContextValue().
*/
public function getContextValue() {
// Support optional contexts.
if (!isset($this->contextValue)) {
$definition = $this->getContextDefinition();
$default_value = $definition->getDefaultValue();
if (!isset($default_value) && $definition->isRequired()) {
$type = $definition->getDataType();
throw new ContextException(sprintf("The %s context is required and not present.", $type));
}
// Keep the default value here so that subsequent calls don't have to look
// it up again.
$this->contextValue = $default_value;
}
return $this->contextValue;
}
/**
* {@inheritdoc}
*/
public function setContextDefinition(ContextDefinitionInterface $context_definition) {
$this->contextDefinition = $context_definition;
}
/**
* Implements \Drupal\Component\Plugin\Context\ContextInterface::getContextDefinition().
*/
public function getContextDefinition() {
return $this->contextDefinition;
}
/**
* Implements \Drupal\Component\Plugin\Context\ContextInterface::getConstraints().
*/
public function getConstraints() {
if (empty($this->contextDefinition['class'])) {
throw new ContextException("An error was encountered while trying to validate the context.");
}
return array(new Type($this->contextDefinition['class']));
}
/**
* Implements \Drupal\Component\Plugin\Context\ContextInterface::validate().
*/
public function validate() {
$validator = Validation::createValidatorBuilder()
->getValidator();
return $validator->validateValue($this->getContextValue(), $this->getConstraints());
}
}

View file

@ -0,0 +1,179 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\Context\ContextDefinitionInterface.
*/
namespace Drupal\Component\Plugin\Context;
/**
* Interface for context definitions.
*
* @todo WARNING: This interface is going to receive some additions as part of
* https://www.drupal.org/node/2346999.
*/
interface ContextDefinitionInterface {
/**
* Gets a human readable label.
*
* @return string
* The label.
*/
public function getLabel();
/**
* Sets the human readable label.
*
* @param string $label
* The label to set.
*
* @return $this
*/
public function setLabel($label);
/**
* Gets a human readable description.
*
* @return string|null
* The description, or NULL if no description is available.
*/
public function getDescription();
/**
* Sets the human readable description.
*
* @param string|null $description
* The description to set.
*
* @return $this
*/
public function setDescription($description);
/**
* Gets the data type needed by the context.
*
* If the context is multiple-valued, this represents the type of each value.
*
* @return string
* The data type.
*/
public function getDataType();
/**
* Sets the data type needed by the context.
*
* @param string $data_type
* The data type to set.
*
* @return $this
*/
public function setDataType($data_type);
/**
* Determines whether the data is multi-valued, i.e. a list of data items.
*
* @return bool
* Whether the data is multi-valued; i.e. a list of data items.
*/
public function isMultiple();
/**
* Sets whether the data is multi-valued.
*
* @param bool $multiple
* (optional) Whether the data is multi-valued. Defaults to TRUE.
*
* @return $this
*/
public function setMultiple($multiple = TRUE);
/**
* Determines whether the context is required.
*
* For required data a non-NULL value is mandatory.
*
* @return bool
* Whether a data value is required.
*/
public function isRequired();
/**
* Sets whether the data is required.
*
* @param bool $required
* (optional) Whether the data is multi-valued. Defaults to TRUE.
*
* @return $this
*/
public function setRequired($required = TRUE);
/**
* Gets the default value for this context definition.
*
* @return mixed
* The default value or NULL if no default value is set.
*/
public function getDefaultValue();
/**
* Sets the default data value.
*
* @param mixed $default_value
* The default value to be set or NULL to remove any default value.
*
* @return $this
*/
public function setDefaultValue($default_value);
/**
* Gets an array of validation constraints.
*
* @return array
* An array of validation constraint definitions, keyed by constraint name.
* Each constraint definition can be used for instantiating
* \Symfony\Component\Validator\Constraint objects.
*/
public function getConstraints();
/**
* Sets the array of validation constraints.
*
* NOTE: This will override any previously set constraints. In most cases
* ContextDefinitionInterface::addConstraint() should be used instead.
*
* @param array $constraints
* The array of constraints.
*
* @return $this
*
* @see self::addConstraint()
*/
public function setConstraints(array $constraints);
/**
* Adds a validation constraint.
*
* @param string $constraint_name
* The name of the constraint to add, i.e. its plugin id.
* @param array|null $options
* The constraint options as required by the constraint plugin, or NULL.
*
* @return $this
*/
public function addConstraint($constraint_name, $options = NULL);
/**
* Gets a validation constraint.
*
* @param string $constraint_name
* The name of the constraint, i.e. its plugin id.
*
* @return array
* A validation constraint definition which can be used for instantiating a
* \Symfony\Component\Validator\Constraint object.
*/
public function getConstraint($constraint_name);
}

View file

@ -0,0 +1,68 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\Context\ContextInterface.
*/
namespace Drupal\Component\Plugin\Context;
/**
* A generic context interface for wrapping data a plugin needs to operate.
*/
interface ContextInterface {
/**
* Sets the context value.
*
* @param mixed $value
* The value of this context, matching the context definition.
*
* @see \Drupal\Component\Plugin\Context\ContextInterface::setContextDefinition().
*/
public function setContextValue($value);
/**
* Gets the context value.
*
* @return mixed
* The currently set context value, or NULL if it is not set.
*/
public function getContextValue();
/**
* Sets the definition that the context must conform to.
*
* @param \Drupal\Component\Plugin\Context\ContextDefinitionInterface $context_definition
* A defining characteristic representation of the context against which
* that context can be validated.
*/
public function setContextDefinition(ContextDefinitionInterface $context_definition);
/**
* Gets the provided definition that the context must conform to.
*
* @return \Drupal\Component\Plugin\Context\ContextDefinitionInterface
* The defining characteristic representation of the context.
*/
public function getContextDefinition();
/**
* Gets a list of validation constraints.
*
* @return array
* Array of constraints, each being an instance of
* \Symfony\Component\Validator\Constraint.
*/
public function getConstraints();
/**
* Validates the set context value.
*
* @return \Symfony\Component\Validator\ConstraintViolationListInterface
* A list of constraint violations. If the list is empty, validation
* succeeded.
*/
public function validate();
}

View file

@ -0,0 +1,145 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\ContextAwarePluginBase.
*/
namespace Drupal\Component\Plugin;
use Drupal\Component\Plugin\Context\ContextInterface;
use Drupal\Component\Plugin\Exception\ContextException;
use Drupal\Component\Plugin\Context\Context;
use Symfony\Component\Validator\ConstraintViolationList;
/**
* Base class for plugins that are context aware.
*/
abstract class ContextAwarePluginBase extends PluginBase implements ContextAwarePluginInterface {
/**
* The data objects representing the context of this plugin.
*
* @var \Drupal\Component\Plugin\Context\ContextInterface[]
*/
protected $context;
/**
* Overrides \Drupal\Component\Plugin\PluginBase::__construct().
*
* Overrides the construction of context aware plugins to allow for
* unvalidated constructor based injection of contexts.
*
* @param array $configuration
* The plugin configuration, i.e. an array with configuration values keyed
* by configuration option name. The special key 'context' may be used to
* initialize the defined contexts by setting it to an array of context
* values keyed by context names.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition) {
$context = array();
if (isset($configuration['context'])) {
$context = $configuration['context'];
unset($configuration['context']);
}
parent::__construct($configuration, $plugin_id, $plugin_definition);
foreach ($context as $key => $value) {
$context_definition = $this->getContextDefinition($key);
$this->context[$key] = new Context($context_definition);
$this->context[$key]->setContextValue($value);
}
}
/**
* {@inheritdoc}
*/
public function getContextDefinitions() {
$definition = $this->getPluginDefinition();
return !empty($definition['context']) ? $definition['context'] : array();
}
/**
* {@inheritdoc}
*/
public function getContextDefinition($name) {
$definition = $this->getPluginDefinition();
if (empty($definition['context'][$name])) {
throw new ContextException(sprintf("The %s context is not a valid context.", $name));
}
return $definition['context'][$name];
}
/**
* {@inheritdoc}
*/
public function getContexts() {
// Make sure all context objects are initialized.
foreach ($this->getContextDefinitions() as $name => $definition) {
$this->getContext($name);
}
return $this->context;
}
/**
* {@inheritdoc}
*/
public function getContext($name) {
// Check for a valid context value.
if (!isset($this->context[$name])) {
$this->context[$name] = new Context($this->getContextDefinition($name));
}
return $this->context[$name];
}
/**
* {@inheritdoc}
*/
public function setContext($name, ContextInterface $context) {
$this->context[$name] = $context;
}
/**
* {@inheritdoc}
*/
public function getContextValues() {
$values = array();
foreach ($this->getContextDefinitions() as $name => $definition) {
$values[$name] = isset($this->context[$name]) ? $this->context[$name]->getContextValue() : NULL;
}
return $values;
}
/**
* {@inheritdoc}
*/
public function getContextValue($name) {
return $this->getContext($name)->getContextValue();
}
/**
* {@inheritdoc}
*/
public function setContextValue($name, $value) {
$this->getContext($name)->setContextValue($value);
return $this;
}
/**
* {@inheritdoc}
*/
public function validateContexts() {
$violations = new ConstraintViolationList();
// @todo: Implement symfony validator API to let the validator traverse
// and set property paths accordingly.
foreach ($this->getContexts() as $context) {
$violations->addAll($context->validate());
}
return $violations;
}
}

View file

@ -0,0 +1,152 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\ContextAwarePluginInterface.
*/
namespace Drupal\Component\Plugin;
use \Drupal\Component\Plugin\Context\ContextInterface;
/**
* Interface for defining context aware plugins.
*
* Context aware plugins can specify an array of context definitions keyed by
* context name at the plugin definition under the "context" key.
*
* @ingroup plugin_api
*/
interface ContextAwarePluginInterface extends PluginInspectionInterface {
/**
* Gets the context definitions of the plugin.
*
* @return \Drupal\Component\Plugin\Context\ContextDefinitionInterface[]
* The array of context definitions, keyed by context name.
*/
public function getContextDefinitions();
/**
* Gets a specific context definition of the plugin.
*
* @param string $name
* The name of the context in the plugin definition.
*
* @throws \Drupal\Component\Plugin\Exception\PluginException
* If the requested context is not defined.
*
* @return \Drupal\Component\Plugin\Context\ContextDefinitionInterface.
* The definition against which the context value must validate.
*/
public function getContextDefinition($name);
/**
* Gets the defined contexts.
*
* @throws \Drupal\Component\Plugin\Exception\PluginException
* If contexts are defined but not set.
*
* @return array
* The set context objects.
*/
public function getContexts();
/**
* Gets a defined context.
*
* @param string $name
* The name of the context in the plugin definition.
*
* @throws \Drupal\Component\Plugin\Exception\PluginException
* If the requested context is not set.
*
* @return \Drupal\Component\Plugin\Context\ContextInterface
* The context object.
*/
public function getContext($name);
/**
* Gets the values for all defined contexts.
*
* @return array
* An array of set context values, keyed by context name. If a context is
* unset its value is returned as NULL.
*/
public function getContextValues();
/**
* Gets the value for a defined context.
*
* @param string $name
* The name of the context in the plugin configuration.
*
* @throws \Drupal\Component\Plugin\Exception\PluginException
* If the requested context is not set.
*
* @return mixed
* The currently set context value.
*/
public function getContextValue($name);
/**
* Set a context on this plugin.
*
* @param string $name
* The name of the context in the plugin configuration.
* @param \Drupal\Component\Plugin\Context\ContextInterface $context
* The context object to set.
*/
public function setContext($name, ContextInterface $context);
/**
* Sets the value for a defined context.
*
* @param string $name
* The name of the context in the plugin definition.
* @param mixed $value
* The value to set the context to. The value has to validate against the
* provided context definition.
*
* @throws \Drupal\Component\Plugin\Exception\PluginException
* If the value does not pass validation.
*
* @return \Drupal\Component\Plugin\ContextAwarePluginInterface.
* A context aware plugin object for chaining.
*/
public function setContextValue($name, $value);
/**
* Validates the set values for the defined contexts.
*
* @return \Symfony\Component\Validator\ConstraintViolationListInterface
* A list of constraint violations. If the list is empty, validation
* succeeded.
*/
public function validateContexts();
/**
* Gets a mapping of the expected assignment names to their context names.
*
* @return array
* A mapping of the expected assignment names to their context names. For
* example, if one of the $contexts is named 'user.current_user', but the
* plugin expects a context named 'user', then this map would contain
* 'user' => 'user.current_user'.
*/
public function getContextMapping();
/**
* Sets a mapping of the expected assignment names to their context names.
*
* @param array $context_mapping
* A mapping of the expected assignment names to their context names. For
* example, if one of the $contexts is named 'user.current_user', but the
* plugin expects a context named 'user', then this map would contain
* 'user' => 'user.current_user'.
*
* @return $this
*/
public function setContextMapping(array $context_mapping);
}

View file

@ -0,0 +1,42 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\DependentPluginInterface.
*/
namespace Drupal\Component\Plugin;
/**
* Provides an interface for a plugin that has dependencies.
*
* @ingroup plugin_api
*/
interface DependentPluginInterface {
/**
* Calculates dependencies for the configured plugin.
*
* Dependencies are saved in the plugin's configuration entity and are used to
* determine configuration synchronization order. For example, if the plugin
* integrates with specific user roles, this method should return an array of
* dependencies listing the specified roles.
*
* @return array
* An array of dependencies grouped by type (config, content, module,
* theme). For example:
* @code
* array(
* 'config' => array('user.role.anonymous', 'user.role.authenticated'),
* 'content' => array('node:article:f0a189e6-55fb-47fb-8005-5bef81c44d6d'),
* 'module' => array('node', 'user'),
* 'theme' => array('seven'),
* );
* @endcode
*
* @see \Drupal\Core\Config\Entity\ConfigDependencyManager
* @see \Drupal\Core\Entity\EntityInterface::getConfigDependencyName()
*/
public function calculateDependencies();
}

View file

@ -0,0 +1,39 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\Derivative\DeriverBase.
*/
namespace Drupal\Component\Plugin\Derivative;
/**
* Provides a basic deriver.
*/
abstract class DeriverBase implements DeriverInterface {
/**
* List of derivative definitions.
*
* @var array
*/
protected $derivatives = array();
/**
* {@inheritdoc}
*/
public function getDerivativeDefinition($derivative_id, $base_plugin_definition) {
if (!empty($this->derivatives) && !empty($this->derivatives[$derivative_id])) {
return $this->derivatives[$derivative_id];
}
$this->getDerivativeDefinitions($base_plugin_definition);
return $this->derivatives[$derivative_id];
}
/**
* {@inheritdoc}
*/
public function getDerivativeDefinitions($base_plugin_definition) {
return $this->derivatives;
}
}

View file

@ -0,0 +1,47 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\Derivative\DeriverInterface.
*/
namespace Drupal\Component\Plugin\Derivative;
/**
* Provides additional plugin definitions based on an existing definition.
*
* @ingroup plugin_api
*/
interface DeriverInterface {
/**
* Gets the definition of a derivative plugin.
*
* @param string $derivative_id
* The derivative id. The id must uniquely identify the derivative within a
* given base plugin, but derivative ids can be reused across base plugins.
* @param mixed $base_plugin_definition
* The definition of the base plugin from which the derivative plugin
* is derived. It is maybe an entire object or just some array, depending
* on the discovery mechanism.
*
* @return array
* The full definition array of the derivative plugin, typically a merge of
* $base_plugin_definition with extra derivative-specific information. NULL
* if the derivative doesn't exist.
*/
public function getDerivativeDefinition($derivative_id, $base_plugin_definition);
/**
* Gets the definition of all derivatives of a base plugin.
*
* @param array $base_plugin_definition
* The definition array of the base plugin.
* @return array
* An array of full derivative definitions keyed on derivative id.
*
* @see getDerivativeDefinition()
*/
public function getDerivativeDefinitions($base_plugin_definition);
}

View file

@ -0,0 +1,31 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\DerivativeInspectionInterface.
*/
namespace Drupal\Component\Plugin;
/**
* Provides a plugin interface for providing derivative metadata inspection.
*/
interface DerivativeInspectionInterface {
/**
* Gets the base_plugin_id of the plugin instance.
*
* @return string
* The base_plugin_id of the plugin instance.
*/
public function getBaseId();
/**
* Gets the derivative_id of the plugin instance.
*
* @return string|null
* The derivative_id of the plugin instance NULL otherwise.
*/
public function getDerivativeId();
}

View file

@ -0,0 +1,37 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface.
*/
namespace Drupal\Component\Plugin\Discovery;
/**
* Interface for discovery components holding a cache of plugin definitions.
*/
interface CachedDiscoveryInterface extends DiscoveryInterface {
/**
* Clears static and persistent plugin definition caches.
*
* Don't resort to calling \Drupal::cache()->delete() and friends to make
* Drupal detect new or updated plugin definitions. Always use this method on
* the appropriate plugin type's plugin manager!
*/
public function clearCachedDefinitions();
/**
* Disable the use of caches.
*
* Can be used to ensure that uncached plugin definitions are returned,
* without invalidating all cached information.
*
* This will also remove all local/static caches.
*
* @param bool $use_caches
* FALSE to not use any caches.
*/
public function useCaches($use_caches = FALSE);
}

View file

@ -0,0 +1,248 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator.
*/
namespace Drupal\Component\Plugin\Discovery;
use Drupal\Component\Plugin\Exception\InvalidDeriverException;
/**
* Base class providing the tools for a plugin discovery to be derivative aware.
*
* Provides a decorator that allows the use of plugin derivatives for normal
* implementations DiscoveryInterface.
*/
class DerivativeDiscoveryDecorator implements DiscoveryInterface {
use DiscoveryTrait;
/**
* Plugin derivers.
*
* @var \Drupal\Component\Plugin\Derivative\DeriverInterface[]
* Keys are base plugin IDs.
*/
protected $derivers = array();
/**
* The decorated plugin discovery.
*
* @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface
*/
protected $decorated;
/**
* Creates a new instance.
*
* @param \Drupal\Component\Plugin\Discovery\DiscoveryInterface $decorated
* The parent object implementing DiscoveryInterface that is being
* decorated.
*/
public function __construct(DiscoveryInterface $decorated) {
$this->decorated = $decorated;
}
/**
* {@inheritdoc}
*
* @throws \Drupal\Component\Plugin\Exception\InvalidDeriverException
* Thrown if the 'deriver' class specified in the plugin definition
* does not implement \Drupal\Component\Plugin\Derivative\DeriverInterface.
*/
public function getDefinition($plugin_id, $exception_on_invalid = TRUE) {
// This check is only for derivative plugins that have explicitly provided
// an ID. This is not common, and can be expected to fail. Therefore, opt
// out of the thrown exception, which will be handled when checking the
// $base_plugin_id.
$plugin_definition = $this->decorated->getDefinition($plugin_id, FALSE);
list($base_plugin_id, $derivative_id) = $this->decodePluginId($plugin_id);
$base_plugin_definition = $this->decorated->getDefinition($base_plugin_id, $exception_on_invalid);
if ($base_plugin_definition) {
$deriver = $this->getDeriver($base_plugin_id, $base_plugin_definition);
if ($deriver) {
$derivative_plugin_definition = $deriver->getDerivativeDefinition($derivative_id, $base_plugin_definition);
// If a plugin defined itself as a derivative, merge in possible
// defaults from the derivative.
if ($derivative_id && isset($plugin_definition)) {
$plugin_definition = $this->mergeDerivativeDefinition($plugin_definition, $derivative_plugin_definition);
}
else {
$plugin_definition = $derivative_plugin_definition;
}
}
}
return $plugin_definition;
}
/**
* {@inheritdoc}
*
* @throws \Drupal\Component\Plugin\Exception\InvalidDeriverException
* Thrown if the 'deriver' class specified in the plugin definition
* does not implement \Drupal\Component\Plugin\Derivative\DeriverInterface.
*/
public function getDefinitions() {
$plugin_definitions = $this->decorated->getDefinitions();
return $this->getDerivatives($plugin_definitions);
}
/**
* Adds derivatives to a list of plugin definitions.
*
* This should be called by the class extending this in
* DiscoveryInterface::getDefinitions().
*/
protected function getDerivatives(array $base_plugin_definitions) {
$plugin_definitions = array();
foreach ($base_plugin_definitions as $base_plugin_id => $plugin_definition) {
$deriver = $this->getDeriver($base_plugin_id, $plugin_definition);
if ($deriver) {
$derivative_definitions = $deriver->getDerivativeDefinitions($plugin_definition);
foreach ($derivative_definitions as $derivative_id => $derivative_definition) {
$plugin_id = $this->encodePluginId($base_plugin_id, $derivative_id);
// Use this definition as defaults if a plugin already defined
// itself as this derivative.
if ($derivative_id && isset($base_plugin_definitions[$plugin_id])) {
$derivative_definition = $this->mergeDerivativeDefinition($base_plugin_definitions[$plugin_id], $derivative_definition);
}
$plugin_definitions[$plugin_id] = $derivative_definition;
}
}
// If a plugin already defined itself as a derivative it might already
// be merged into the definitions.
elseif (!isset($plugin_definitions[$base_plugin_id])) {
$plugin_definitions[$base_plugin_id] = $plugin_definition;
}
}
return $plugin_definitions;
}
/**
* Decodes derivative id and plugin id from a string.
*
* @param string $plugin_id
* Plugin identifier that may point to a derivative plugin.
*
* @return array
* An array with the base plugin id as the first index and the derivative id
* as the second. If there is no derivative id it will be null.
*/
protected function decodePluginId($plugin_id) {
// Try and split the passed plugin definition into a plugin and a
// derivative id. We don't need to check for !== FALSE because a leading
// colon would break the derivative system and doesn't makes sense.
if (strpos($plugin_id, ':')) {
return explode(':', $plugin_id, 2);
}
return array($plugin_id, NULL);
}
/**
* Encodes plugin and derivative id's into a string.
*
* @param string $base_plugin_id
* The base plugin identifier.
* @param string $derivative_id
* The derivative identifier.
*
* @return string
* A uniquely encoded combination of the $base_plugin_id and $derivative_id.
*/
protected function encodePluginId($base_plugin_id, $derivative_id) {
if ($derivative_id) {
return "$base_plugin_id:$derivative_id";
}
// By returning the unmerged plugin_id, we are able to support derivative
// plugins that support fetching the base definitions.
return $base_plugin_id;
}
/**
* Gets a deriver for a base plugin.
*
* @param string $base_plugin_id
* The base plugin id of the plugin.
* @param mixed $base_definition
* The base plugin definition to build derivatives.
*
* @return \Drupal\Component\Plugin\Derivative\DeriverInterface|null
* A DerivativeInterface or NULL if none exists for the plugin.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidDeriverException
* Thrown if the 'deriver' class specified in the plugin definition
* does not implement \Drupal\Component\Plugin\Derivative\DeriverInterface.
*/
protected function getDeriver($base_plugin_id, $base_definition) {
if (!isset($this->derivers[$base_plugin_id])) {
$this->derivers[$base_plugin_id] = FALSE;
$class = $this->getDeriverClass($base_definition);
if ($class) {
$this->derivers[$base_plugin_id] = new $class($base_plugin_id);
}
}
return $this->derivers[$base_plugin_id] ?: NULL;
}
/**
* Gets the deriver class name from the base plugin definition.
*
* @param array $base_definition
* The base plugin definition to build derivatives.
*
* @return string|null
* The name of a class implementing
* \Drupal\Component\Plugin\Derivative\DeriverInterface.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidDeriverException
* Thrown if the 'deriver' class specified in the plugin definition
* does not implement
* \Drupal\Component\Plugin\Derivative\DerivativeInterface.
*/
protected function getDeriverClass($base_definition) {
$class = NULL;
if ((is_array($base_definition) || ($base_definition = (array) $base_definition)) && (isset($base_definition['deriver']) && $class = $base_definition['deriver'])) {
if (!class_exists($class)) {
throw new InvalidDeriverException(sprintf('Plugin (%s) deriver "%s" does not exist.', $base_definition['id'], $class));
}
if (!is_subclass_of($class, '\Drupal\Component\Plugin\Derivative\DeriverInterface')) {
throw new InvalidDeriverException(sprintf('Plugin (%s) deriver "%s" must implement \Drupal\Component\Plugin\Derivative\DeriverInterface.', $base_definition['id'], $class));
}
}
return $class;
}
/**
* Merges a base and derivative definition, taking into account empty values.
*
* @param array $base_plugin_definition
* The base plugin definition.
* @param array $derivative_definition
* The derivative plugin definition.
*
* @return array
* The merged definition.
*/
protected function mergeDerivativeDefinition($base_plugin_definition, $derivative_definition) {
// Use this definition as defaults if a plugin already defined itself as
// this derivative, but filter out empty values first.
$filtered_base = array_filter($base_plugin_definition);
$derivative_definition = $filtered_base + ($derivative_definition ?: array());
// Add back any empty keys that the derivative didn't have.
return $derivative_definition + $base_plugin_definition;
}
/**
* Passes through all unknown calls onto the decorated object.
*/
public function __call($method, $args) {
return call_user_func_array(array($this->decorated, $method), $args);
}
}

View file

@ -0,0 +1,33 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\Discovery\DiscoveryCachedTrait.
*/
namespace Drupal\Component\Plugin\Discovery;
trait DiscoveryCachedTrait {
use DiscoveryTrait;
/**
* Cached definitions array.
*
* @var array
*/
protected $definitions;
/**
* {@inheritdoc}
*/
public function getDefinition($plugin_id, $exception_on_invalid = TRUE) {
// Fetch definitions if they're not loaded yet.
if (!isset($this->definitions)) {
$this->getDefinitions();
}
return $this->doGetDefinition($this->definitions, $plugin_id, $exception_on_invalid);
}
}

View file

@ -0,0 +1,55 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\Discovery\DiscoveryInterface.
*/
namespace Drupal\Component\Plugin\Discovery;
/**
* An interface defining the minimum requirements of building a plugin
* discovery component.
*
* @ingroup plugin_api
*/
interface DiscoveryInterface {
/**
* Gets a specific plugin definition.
*
* @param string $plugin_id
* A plugin id.
* @param bool $exception_on_invalid
* (optional) If TRUE, an invalid plugin ID will throw an exception.
*
* @return mixed
* A plugin definition, or NULL if the plugin ID is invalid and
* $exception_on_invalid is FALSE.
*
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
* Thrown if $plugin_id is invalid and $exception_on_invalid is TRUE.
*/
public function getDefinition($plugin_id, $exception_on_invalid = TRUE);
/**
* Gets the definition of all plugins for this type.
*
* @return mixed[]
* An array of plugin definitions (empty array if no definitions were
* found). Keys are plugin IDs.
*/
public function getDefinitions();
/**
* Indicates if a specific plugin definition exists.
*
* @param string $plugin_id
* A plugin ID.
*
* @return bool
* TRUE if the definition exists, FALSE otherwise.
*/
public function hasDefinition($plugin_id);
}

View file

@ -0,0 +1,67 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\Discovery\DiscoveryTrait.
*/
namespace Drupal\Component\Plugin\Discovery;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
/**
* @see Drupal\Component\Plugin\Discovery\DiscoveryInterface
*/
trait DiscoveryTrait {
/**
* {@inheritdoc}
*/
abstract public function getDefinitions();
/**
* {@inheritdoc}
*/
public function getDefinition($plugin_id, $exception_on_invalid = TRUE) {
$definitions = $this->getDefinitions();
return $this->doGetDefinition($definitions, $plugin_id, $exception_on_invalid);
}
/**
* Gets a specific plugin definition.
*
* @param array $definitions
* An array of the available plugin definitions.
* @param string $plugin_id
* A plugin id.
* @param bool $exception_on_invalid
* (optional) If TRUE, an invalid plugin ID will throw an exception.
* Defaults to FALSE.
*
* @return array|null
* A plugin definition, or NULL if the plugin ID is invalid and
* $exception_on_invalid is TRUE.
*
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
* Thrown if $plugin_id is invalid and $exception_on_invalid is TRUE.
*/
protected function doGetDefinition(array $definitions, $plugin_id, $exception_on_invalid) {
// Avoid using a ternary that would create a copy of the array.
if (isset($definitions[$plugin_id])) {
return $definitions[$plugin_id];
}
elseif (!$exception_on_invalid) {
return NULL;
}
throw new PluginNotFoundException($plugin_id, sprintf('The "%s" plugin does not exist.', $plugin_id));
}
/**
* {@inheritdoc}
*/
public function hasDefinition($plugin_id) {
return (bool) $this->getDefinition($plugin_id, FALSE);
}
}

View file

@ -0,0 +1,41 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\Discovery\StaticDiscovery.
*/
namespace Drupal\Component\Plugin\Discovery;
/**
* A discovery mechanism that allows plugin definitions to be manually
* registered rather than actively discovered.
*/
class StaticDiscovery implements DiscoveryInterface {
use DiscoveryCachedTrait;
/**
* Implements Drupal\Component\Plugin\Discovery\DiscoveryInterface::getDefinitions().
*/
public function getDefinitions() {
if (!$this->definitions) {
$this->definitions = array();
}
return $this->definitions;
}
/**
* Sets a plugin definition.
*/
public function setDefinition($plugin, $definition) {
$this->definitions[$plugin] = $definition;
}
/**
* Deletes a plugin definition.
*/
public function deleteDefinition($plugin) {
unset($this->definitions[$plugin]);
}
}

View file

@ -0,0 +1,71 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\Discovery\StaticDiscoveryDecorator.
*/
namespace Drupal\Component\Plugin\Discovery;
/**
* A decorator that allows manual registration of undiscoverable definitions.
*/
class StaticDiscoveryDecorator extends StaticDiscovery {
/**
* The Discovery object being decorated.
*
* @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface
*/
protected $decorated;
/**
* A callback or closure used for registering additional definitions.
*
* @var \Callable
*/
protected $registerDefinitions;
/**
* Constructs a \Drupal\Component\Plugin\Discovery\StaticDiscoveryDecorator object.
*
* @param \Drupal\Component\Plugin\Discovery\DiscoveryInterface $decorated
* The discovery object that is being decorated.
* @param \Callable $registerDefinitions
* (optional) A callback or closure used for registering additional
* definitions.
*/
public function __construct(DiscoveryInterface $decorated, $registerDefinitions = NULL) {
$this->decorated = $decorated;
$this->registerDefinitions = $registerDefinitions;
}
/**
* {@inheritdoc}
*/
public function getDefinition($base_plugin_id, $exception_on_invalid = TRUE) {
if (isset($this->registerDefinitions)) {
call_user_func($this->registerDefinitions);
}
$this->definitions += $this->decorated->getDefinitions();
return parent::getDefinition($base_plugin_id, $exception_on_invalid);
}
/**
* Implements Drupal\Component\Plugin\Discovery\DiscoveryInterface::getDefinitions().
*/
public function getDefinitions() {
if (isset($this->registerDefinitions)) {
call_user_func($this->registerDefinitions);
}
$this->definitions += $this->decorated->getDefinitions();
return parent::getDefinitions();
}
/**
* Passes through all unknown calls onto the decorated object
*/
public function __call($method, $args) {
return call_user_func_array(array($this->decorated, $method), $args);
}
}

View file

@ -0,0 +1,13 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\Exception\ContextException.
*/
namespace Drupal\Component\Plugin\Exception;
/**
* An exception class to be thrown for context plugin exceptions.
*/
class ContextException extends \Exception implements ExceptionInterface { }

View file

@ -0,0 +1,12 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\Exception\ExceptionInterface.
*/
namespace Drupal\Component\Plugin\Exception;
/**
* Exception interface for all exceptions thrown by the Plugin component.
*/
interface ExceptionInterface { }

View file

@ -0,0 +1,17 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\Exception\InvalidDecoratedMethod.
*/
namespace Drupal\Component\Plugin\Exception;
use Drupal\Component\Plugin\Exception\ExceptionInterface;
use \BadMethodCallException;
/**
* Exception thrown when a decorator's _call() method is triggered, but the
* decorated object does not contain the requested method.
*
*/
class InvalidDecoratedMethod extends BadMethodCallException implements ExceptionInterface { }

View file

@ -0,0 +1,12 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\Exception\InvalidDeriverException.
*/
namespace Drupal\Component\Plugin\Exception;
/**
* Exception to be thrown if a plugin tries to use an invalid deriver.
*/
class InvalidDeriverException extends PluginException { }

View file

@ -0,0 +1,45 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException.
*/
namespace Drupal\Component\Plugin\Exception;
/**
* Defines a class for invalid plugin definition exceptions.
*/
class InvalidPluginDefinitionException extends PluginException {
/**
* The plugin ID of the mapper.
*
* @var string
*/
protected $pluginId;
/**
* Constructs a InvalidPluginDefinitionException.
*
* @param string $plugin_id
* The plugin ID of the mapper.
*
* @see \Exception for the remaining parameters.
*/
public function __construct($plugin_id, $message = '', $code = 0, \Exception $previous = NULL) {
$this->pluginId = $plugin_id;
parent::__construct($message, $code, $previous);
}
/**
* Gets the plugin ID of the mapper that raised the exception.
*
* @return string
* The plugin ID.
*/
public function getPluginId() {
return $this->pluginId;
}
}

View file

@ -0,0 +1,15 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\Exception\MapperExceptionInterface.
*
* Base exception interface for grouping mapper exceptions.
*/
namespace Drupal\Component\Plugin\Exception;
/**
* Extended interface for exceptions thrown specifically by the Mapper subsystem
* within the Plugin component.
*/
interface MapperExceptionInterface extends ExceptionInterface { }

View file

@ -0,0 +1,13 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\Exception\PluginException.
*/
namespace Drupal\Component\Plugin\Exception;
/**
* Generic Plugin exception class to be thrown when no more specific class
* is applicable.
*/
class PluginException extends \Exception implements ExceptionInterface { }

View file

@ -0,0 +1,30 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\Exception\PluginNotFoundException.
*/
namespace Drupal\Component\Plugin\Exception;
/**
* Plugin exception class to be thrown when a plugin ID could not be found.
*/
class PluginNotFoundException extends PluginException {
/**
* Construct an PluginNotFoundException exception.
*
* @param string $plugin_id
* The plugin ID that was not found.
*
* @see \Exception for remaining parameters.
*/
public function __construct($plugin_id, $message = '', $code = 0, \Exception $previous = NULL) {
if (empty($message)) {
$message = sprintf("Plugin ID '%s' was not found.", $plugin_id);
}
parent::__construct($message, $code, $previous);
}
}

View file

@ -0,0 +1,96 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\Factory\DefaultFactory.
*/
namespace Drupal\Component\Plugin\Factory;
use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
use Drupal\Component\Plugin\Exception\PluginException;
/**
* Default plugin factory.
*
* Instantiates plugin instances by passing the full configuration array as a
* single constructor argument. Plugin types wanting to support plugin classes
* with more flexible constructor signatures can do so by using an alternate
* factory such as Drupal\Component\Plugin\Factory\ReflectionFactory.
*/
class DefaultFactory implements FactoryInterface {
/**
* The object that retrieves the definitions of the plugins that this factory instantiates.
*
* The plugin definition includes the plugin class and possibly other
* information necessary for proper instantiation.
*
* @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface
*/
protected $discovery;
/**
* Defines an interface each plugin should implement.
*
* @var string|null
*/
protected $interface;
/**
* Constructs a Drupal\Component\Plugin\Factory\DefaultFactory object.
*
* @param \Drupal\Component\Plugin\Discovery\DiscoveryInterface $discovery
* The plugin discovery.
* @param string|null $plugin_interface
* (optional) The interface each plugin should implement.
*/
public function __construct(DiscoveryInterface $discovery, $plugin_interface = NULL) {
$this->discovery = $discovery;
$this->interface = $plugin_interface;
}
/**
* Implements Drupal\Component\Plugin\Factory\FactoryInterface::createInstance().
*/
public function createInstance($plugin_id, array $configuration = array()) {
$plugin_definition = $this->discovery->getDefinition($plugin_id);
$plugin_class = static::getPluginClass($plugin_id, $plugin_definition, $this->interface);
return new $plugin_class($configuration, $plugin_id, $plugin_definition);
}
/**
* Finds the class relevant for a given plugin.
*
* @param string $plugin_id
* The id of a plugin.
* @param mixed $plugin_definition
* The plugin definition associated with the plugin ID.
* @param string $required_interface
* (optional) THe required plugin interface.
*
* @return string
* The appropriate class name.
*
* @throws \Drupal\Component\Plugin\Exception\PluginException
* Thrown when there is no class specified, the class doesn't exist, or
* the class does not implement the specified required interface.
*
*/
public static function getPluginClass($plugin_id, $plugin_definition = NULL, $required_interface = NULL) {
if (empty($plugin_definition['class'])) {
throw new PluginException(sprintf('The plugin (%s) did not specify an instance class.', $plugin_id));
}
$class = $plugin_definition['class'];
if (!class_exists($class)) {
throw new PluginException(sprintf('Plugin (%s) instance class "%s" does not exist.', $plugin_id, $class));
}
if ($required_interface && !is_subclass_of($plugin_definition['class'], $required_interface)) {
throw new PluginException(sprintf('Plugin "%s" (%s) must implement interface %s.', $plugin_id, $plugin_definition['class'], $required_interface));
}
return $class;
}
}

View file

@ -0,0 +1,30 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\Factory\FactoryInterface.
*/
namespace Drupal\Component\Plugin\Factory;
/**
* Factory interface implemented by all plugin factories.
*/
interface FactoryInterface {
/**
* Creates a pre-configured instance of a plugin.
*
* @param string $plugin_id
* The ID of the plugin being instantiated.
* @param array $configuration
* An array of configuration relevant to the plugin instance.
*
* @return object
* A fully configured plugin instance.
*
* @throws \Drupal\Component\Plugin\Exception\PluginException
* If the instance cannot be created, such as if the ID is invalid.
*/
public function createInstance($plugin_id, array $configuration = array());
}

View file

@ -0,0 +1,83 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\Factory\ReflectionFactory.
*/
namespace Drupal\Component\Plugin\Factory;
/**
* A plugin factory that maps instance configuration to constructor arguments.
*
* Provides logic for any basic plugin type that needs to provide individual
* plugins based upon some basic logic.
*/
class ReflectionFactory extends DefaultFactory {
/**
* Implements Drupal\Component\Plugin\Factory\FactoryInterface::createInstance().
*/
public function createInstance($plugin_id, array $configuration = array()) {
$plugin_definition = $this->discovery->getDefinition($plugin_id);
$plugin_class = static::getPluginClass($plugin_id, $plugin_definition, $this->interface);
// Lets figure out of there's a constructor for this class and pull
// arguments from the $options array if so to populate it.
$reflector = new \ReflectionClass($plugin_class);
if ($reflector->hasMethod('__construct')) {
$arguments = $this->getInstanceArguments($reflector, $plugin_id, $plugin_definition, $configuration);
$instance = $reflector->newInstanceArgs($arguments);
}
else {
$instance = new $plugin_class();
}
return $instance;
}
/**
* Inspects the plugin class and build a list of arguments for the constructor.
*
* This is provided as a helper method so factories extending this class can
* replace this and insert their own reflection logic.
*
* @param \ReflectionClass $reflector
* The reflector object being used to inspect the plugin class.
* @param string $plugin_id
* The identifier of the plugin implementation.
* @param mixed $plugin_definition
* The definition associated to the plugin_id.
* @param array $configuration
* An array of configuration that may be passed to the instance.
*
* @return array
* An array of arguments to be passed to the constructor.
*/
protected function getInstanceArguments(\ReflectionClass $reflector, $plugin_id, $plugin_definition, array $configuration) {
$arguments = array();
foreach ($reflector->getMethod('__construct')->getParameters() as $param) {
$param_name = $param->getName();
if ($param_name == 'plugin_id') {
$arguments[] = $plugin_id;
}
elseif ($param_name == 'plugin_definition') {
$arguments[] = $plugin_definition;
}
elseif ($param_name == 'configuration') {
$arguments[] = $configuration;
}
elseif (isset($configuration[$param_name]) || array_key_exists($param_name, $configuration)) {
$arguments[] = $configuration[$param_name];
}
elseif ($param->isDefaultValueAvailable()) {
$arguments[] = $param->getDefaultValue();
}
else {
$arguments[] = NULL;
}
}
return $arguments;
}
}

View file

@ -0,0 +1,28 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\FallbackPluginManagerInterface.
*/
namespace Drupal\Component\Plugin;
/**
* An interface implemented by plugin managers with fallback plugin behaviors.
*/
interface FallbackPluginManagerInterface {
/**
* Gets a fallback id for a missing plugin.
*
* @param string $plugin_id
* The ID of the missing requested plugin.
* @param array $configuration
* An array of configuration relevant to the plugin instance.
*
* @return string
* The id of an existing plugin to use when the plugin does not exist.
*/
public function getFallbackPluginId($plugin_id, array $configuration = array());
}

View file

@ -0,0 +1,165 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\LazyPluginCollection.
*/
namespace Drupal\Component\Plugin;
/**
* Defines an object which stores multiple plugin instances to lazy load them.
*
* @ingroup plugin_api
*/
abstract class LazyPluginCollection implements \IteratorAggregate, \Countable {
/**
* Stores all instantiated plugins.
*
* @var array
*/
protected $pluginInstances = array();
/**
* Stores the IDs of all potential plugin instances.
*
* @var array
*/
protected $instanceIDs = array();
/**
* Initializes and stores a plugin.
*
* @param string $instance_id
* The ID of the plugin instance to initialize.
*/
abstract protected function initializePlugin($instance_id);
/**
* Gets the current configuration of all plugins in this collection.
*
* @return array
* An array of up-to-date plugin configuration.
*/
abstract public function getConfiguration();
/**
* Sets the configuration for all plugins in this collection.
*
* @param array $configuration
* An array of up-to-date plugin configuration.
*
* @return $this
*/
abstract public function setConfiguration($configuration);
/**
* Clears all instantiated plugins.
*/
public function clear() {
$this->pluginInstances = array();
}
/**
* Determines if a plugin instance exists.
*
* @param string $instance_id
* The ID of the plugin instance to check.
*
* @return bool
* TRUE if the plugin instance exists, FALSE otherwise.
*/
public function has($instance_id) {
return isset($this->pluginInstances[$instance_id]) || isset($this->instanceIDs[$instance_id]);
}
/**
* Gets a plugin instance, initializing it if necessary.
*
* @param string $instance_id
* The ID of the plugin instance being retrieved.
*/
public function &get($instance_id) {
if (!isset($this->pluginInstances[$instance_id])) {
$this->initializePlugin($instance_id);
}
return $this->pluginInstances[$instance_id];
}
/**
* Stores an initialized plugin.
*
* @param string $instance_id
* The ID of the plugin instance being stored.
* @param mixed $value
* An instantiated plugin.
*/
public function set($instance_id, $value) {
$this->pluginInstances[$instance_id] = $value;
$this->addInstanceId($instance_id);
}
/**
* Removes an initialized plugin.
*
* The plugin can still be used; it will be reinitialized.
*
* @param string $instance_id
* The ID of the plugin instance to remove.
*/
public function remove($instance_id) {
unset($this->pluginInstances[$instance_id]);
}
/**
* Adds an instance ID to the available instance IDs.
*
* @param string $id
* The ID of the plugin instance to add.
* @param array|null $configuration
* (optional) The configuration used by this instance. Defaults to NULL.
*/
public function addInstanceId($id, $configuration = NULL) {
if (!isset($this->instanceIDs[$id])) {
$this->instanceIDs[$id] = $id;
}
}
/**
* Gets all instance IDs.
*
* @return array
* An array of all available instance IDs.
*/
public function getInstanceIds() {
return $this->instanceIDs;
}
/**
* Removes an instance ID.
*
* @param string $instance_id
* The ID of the plugin instance to remove.
*/
public function removeInstanceId($instance_id) {
unset($this->instanceIDs[$instance_id]);
$this->remove($instance_id);
}
public function getIterator() {
$instances = [];
foreach ($this->getInstanceIds() as $instance_id) {
$instances[$instance_id] = $this->get($instance_id);
}
return new \ArrayIterator($instances);
}
/**
* {@inheritdoc}
*/
public function count() {
return count($this->instanceIDs);
}
}

View file

@ -0,0 +1,34 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\Mapper\MapperInterface.
*/
namespace Drupal\Component\Plugin\Mapper;
/**
* Plugin mapper interface.
*
* Plugin mappers are responsible for mapping a plugin request to its
* implementation. For example, it might map a cache bin to a memcache bin.
*
* Mapper objects incorporate the best practices of retrieving configurations,
* type information, and factory instantiation.
*/
interface MapperInterface {
/**
* Gets a preconfigured instance of a plugin.
*
* @param array $options
* An array of options that can be used to determine a suitable plugin to
* instantiate and how to configure it.
*
* @return object|false
* A fully configured plugin instance. The interface of the plugin instance
* will depends on the plugin type. If no instance can be retrieved, FALSE
* will be returned.
*/
public function getInstance(array $options);
}

View file

@ -0,0 +1,99 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\PluginBase.
*/
namespace Drupal\Component\Plugin;
/**
* Base class for plugins wishing to support metadata inspection.
*/
abstract class PluginBase implements PluginInspectionInterface, DerivativeInspectionInterface {
/**
* A string which is used to separate base plugin IDs from the derivative ID.
*/
const DERIVATIVE_SEPARATOR = ':';
/**
* The plugin_id.
*
* @var string
*/
protected $pluginId;
/**
* The plugin implementation definition.
*
* @var array
*/
protected $pluginDefinition;
/**
* Configuration information passed into the plugin.
*
* When using an interface like
* \Drupal\Component\Plugin\ConfigurablePluginInterface, this is where the
* configuration should be stored.
*
* Plugin configuration is optional, so plugin implementations must provide
* their own setters and getters.
*
* @var array
*/
protected $configuration;
/**
* Constructs a Drupal\Component\Plugin\PluginBase object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition) {
$this->configuration = $configuration;
$this->pluginId = $plugin_id;
$this->pluginDefinition = $plugin_definition;
}
/**
* {@inheritdoc}
*/
public function getPluginId() {
return $this->pluginId;
}
/**
* {@inheritdoc}
*/
public function getBaseId() {
$plugin_id = $this->getPluginId();
if (strpos($plugin_id, static::DERIVATIVE_SEPARATOR)) {
list($plugin_id) = explode(static::DERIVATIVE_SEPARATOR, $plugin_id, 2);
}
return $plugin_id;
}
/**
* {@inheritdoc}
*/
public function getDerivativeId() {
$plugin_id = $this->getPluginId();
$derivative_id = NULL;
if (strpos($plugin_id, static::DERIVATIVE_SEPARATOR)) {
list(, $derivative_id) = explode(static::DERIVATIVE_SEPARATOR, $plugin_id, 2);
}
return $derivative_id;
}
/**
* {@inheritdoc}
*/
public function getPluginDefinition() {
return $this->pluginDefinition;
}
}

View file

@ -0,0 +1,36 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\PluginInspectionInterface.
*/
namespace Drupal\Component\Plugin;
/**
* Plugin interface for providing some metadata inspection.
*
* This interface provides some simple tools for code receiving a plugin to
* interact with the plugin system.
*
* @ingroup plugin_api
*/
interface PluginInspectionInterface {
/**
* Gets the plugin_id of the plugin instance.
*
* @return string
* The plugin_id of the plugin instance.
*/
public function getPluginId();
/**
* Gets the definition of the plugin implementation.
*
* @return array
* The plugin definition, as returned by the discovery object used by the
* plugin manager.
*/
public function getPluginDefinition();
}

View file

@ -0,0 +1,100 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\PluginManagerBase.
*/
namespace Drupal\Component\Plugin;
use Drupal\Component\Plugin\Discovery\DiscoveryTrait;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
/**
* Base class for plugin managers.
*/
abstract class PluginManagerBase implements PluginManagerInterface {
use DiscoveryTrait;
/**
* The object that discovers plugins managed by this manager.
*
* @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface
*/
protected $discovery;
/**
* The object that instantiates plugins managed by this manager.
*
* @var \Drupal\Component\Plugin\Factory\FactoryInterface
*/
protected $factory;
/**
* The object that returns the preconfigured plugin instance appropriate for a particular runtime condition.
*
* @var \Drupal\Component\Plugin\Mapper\MapperInterface
*/
protected $mapper;
/**
* Gets the plugin discovery.
*
* @return \Drupal\Component\Plugin\Discovery\DiscoveryInterface
*/
protected function getDiscovery() {
return $this->discovery;
}
/**
* Gets the plugin factory.
*
* @return \Drupal\Component\Plugin\Factory\FactoryInterface
*/
protected function getFactory() {
return $this->factory;
}
/**
* {@inheritdoc}
*/
public function getDefinition($plugin_id, $exception_on_invalid = TRUE) {
return $this->getDiscovery()->getDefinition($plugin_id, $exception_on_invalid);
}
/**
* {@inheritdoc}
*/
public function getDefinitions() {
return $this->getDiscovery()->getDefinitions();
}
/**
* {@inheritdoc}
*/
public function createInstance($plugin_id, array $configuration = array()) {
// If this PluginManager has fallback capabilities catch
// PluginNotFoundExceptions.
if ($this instanceof FallbackPluginManagerInterface) {
try {
return $this->getFactory()->createInstance($plugin_id, $configuration);
}
catch (PluginNotFoundException $e) {
$fallback_id = $this->getFallbackPluginId($plugin_id, $configuration);
return $this->getFactory()->createInstance($fallback_id, $configuration);
}
}
else {
return $this->getFactory()->createInstance($plugin_id, $configuration);
}
}
/**
* {@inheritdoc}
*/
public function getInstance(array $options) {
return $this->mapper->getInstance($options);
}
}

View file

@ -0,0 +1,33 @@
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\PluginManagerInterface.
*/
namespace Drupal\Component\Plugin;
use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
use Drupal\Component\Plugin\Factory\FactoryInterface;
use Drupal\Component\Plugin\Mapper\MapperInterface;
/**
* Interface implemented by plugin managers.
*
* There are no explicit methods on the manager interface. Instead plugin
* managers broker the interactions of the different plugin components, and
* therefore, must implement each component interface, which is enforced by
* this interface extending all of the component ones.
*
* While a plugin manager may directly implement these interface methods with
* custom logic, it is expected to be more common for plugin managers to proxy
* the method invocations to the respective components, and directly implement
* only the additional functionality needed by the specific pluggable system.
* To follow this pattern, plugin managers can extend from the PluginManagerBase
* class, which contains the proxying logic.
*
* @see \Drupal\Component\Plugin\PluginManagerBase
*
* @ingroup plugin_api
*/
interface PluginManagerInterface extends DiscoveryInterface, FactoryInterface, MapperInterface {
}

View file

@ -0,0 +1,18 @@
{
"name": "drupal/core-plugin",
"description": "Base building block for a scalable and extensible plug-in system for PHP components and application framework extensions.",
"keywords": ["drupal", "plugin", "plugins"],
"homepage": "https://www.drupal.org/project/drupal",
"license": "GPL-2.0+",
"require": {
"php": ">=5.4.2"
},
"autoload": {
"psr-0": {
"Drupal\\Component\\Plugin\\": ""
}
},
"suggest": {
"symfony/validator": "Leveraged in the use of context aware plugins."
}
}