Move into nested docroot

This commit is contained in:
Rob Davies 2017-02-13 15:31:17 +00:00
parent 83a0d3a149
commit c8b70abde9
13405 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,46 @@
<?php
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,36 @@
<?php
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,94 @@
<?php
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;
/**
* Create a context object.
*
* @param \Drupal\Component\Plugin\Context\ContextDefinitionInterface $context_definition
* The context definition.
* @param mixed|null $context_value
* The value of the context.
*/
public function __construct(ContextDefinitionInterface $context_definition, $context_value = NULL) {
$this->contextDefinition = $context_definition;
$this->contextValue = $context_value;
}
/**
* {@inheritdoc}
*/
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 hasContextValue() {
return (bool) $this->contextValue || (bool) $this->getContextDefinition()->getDefaultValue();
}
/**
* {@inheritdoc}
*/
public function getContextDefinition() {
return $this->contextDefinition;
}
/**
* {@inheritdoc}
*/
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']));
}
/**
* {@inheritdoc}
*/
public function validate() {
$validator = Validation::createValidatorBuilder()
->getValidator();
return $validator->validateValue($this->getContextValue(), $this->getConstraints());
}
}

View file

@ -0,0 +1,174 @@
<?php
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,52 @@
<?php
namespace Drupal\Component\Plugin\Context;
/**
* A generic context interface for wrapping data a plugin needs to operate.
*/
interface ContextInterface {
/**
* Gets the context value.
*
* @return mixed
* The currently set context value, or NULL if it is not set.
*/
public function getContextValue();
/**
* Returns whether the context has a value.
*
* @return bool
* TRUE if the context has a value, FALSE otherwise.
*/
public function hasContextValue();
/**
* 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,153 @@
<?php
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_configuration = isset($configuration['context']) ? $configuration['context'] : [];
unset($configuration['context']);
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->contexts = $this->createContextFromConfiguration($context_configuration);
}
/**
* Creates context objects from any context mappings in configuration.
*
* @param array $context_configuration
* An associative array of context names and values.
*
* @return \Drupal\Component\Plugin\Context\ContextInterface[]
* An array of context objects.
*/
protected function createContextFromConfiguration(array $context_configuration) {
$contexts = [];
foreach ($context_configuration as $key => $value) {
$context_definition = $this->getContextDefinition($key);
$contexts[$key] = new Context($context_definition, $value);
}
return $contexts;
}
/**
* {@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->context[$name] = new Context($this->getContextDefinition($name), $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,147 @@
<?php
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.
*
* @return \Drupal\Component\Plugin\Context\ContextDefinitionInterface.
* The definition against which the context value must validate.
*
* @throws \Drupal\Component\Plugin\Exception\PluginException
* If the requested context is not defined.
*/
public function getContextDefinition($name);
/**
* Gets the defined contexts.
*
* @return array
* The set context objects.
*
* @throws \Drupal\Component\Plugin\Exception\PluginException
* If contexts are defined but not set.
*/
public function getContexts();
/**
* Gets a defined context.
*
* @param string $name
* The name of the context in the plugin definition.
*
* @return \Drupal\Component\Plugin\Context\ContextInterface
* The context object.
*
* @throws \Drupal\Component\Plugin\Exception\PluginException
* If the requested context is not set.
*/
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.
*
* @return mixed
* The currently set context value.
*
* @throws \Drupal\Component\Plugin\Exception\PluginException
* If the requested context is not set.
*/
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.
*
* @return \Drupal\Component\Plugin\ContextAwarePluginInterface.
* A context aware plugin object for chaining.
*
* @throws \Drupal\Component\Plugin\Exception\PluginException
* If the value does not pass validation.
*/
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,35 @@
<?php
namespace Drupal\Component\Plugin\Definition;
/**
* Defines a plugin definition.
*
* Object-based plugin definitions MUST implement this interface.
*
* @ingroup Plugin
*/
interface PluginDefinitionInterface {
/**
* Sets the class.
*
* @param string $class
* A fully qualified class name.
*
* @return static
*
* @throws \InvalidArgumentException
* If the class is invalid.
*/
public function setClass($class);
/**
* Gets the class.
*
* @return string
* A fully qualified class name.
*/
public function getClass();
}

View file

@ -0,0 +1,37 @@
<?php
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,35 @@
<?php
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,42 @@
<?php
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,26 @@
<?php
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,32 @@
<?php
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,244 @@
<?php
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,28 @@
<?php
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,50 @@
<?php
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,62 @@
<?php
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
* If TRUE, an invalid plugin ID will cause an exception to be thrown; if
* FALSE, NULL will be returned.
*
* @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,37 @@
<?php
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;
/**
* {@inheritdoc}
*/
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,67 @@
<?php
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);
}
/**
* {@inheritdoc}
*/
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,8 @@
<?php
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,8 @@
<?php
namespace Drupal\Component\Plugin\Exception;
/**
* Exception interface for all exceptions thrown by the Plugin component.
*/
interface ExceptionInterface { }

View file

@ -0,0 +1,11 @@
<?php
namespace Drupal\Component\Plugin\Exception;
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,8 @@
<?php
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,42 @@
<?php
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.
*
* For the remaining parameters see \Exception.
*
* @param string $plugin_id
* The plugin ID of the mapper.
*
* @see \Exception
*/
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,11 @@
<?php
namespace Drupal\Component\Plugin\Exception;
/**
* Base exception interface for grouping mapper exceptions.
*
* Extended interface for exceptions thrown specifically by the Mapper subsystem
* within the Plugin component.
*/
interface MapperExceptionInterface extends ExceptionInterface { }

View file

@ -0,0 +1,9 @@
<?php
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,27 @@
<?php
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.
*
* For the remaining parameters see \Exception.
*
* @param string $plugin_id
* The plugin ID that was not found.
*
* @see \Exception
*/
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,107 @@
<?php
namespace Drupal\Component\Plugin\Factory;
use Drupal\Component\Plugin\Definition\PluginDefinitionInterface;
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;
}
/**
* {@inheritdoc}
*/
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 \Drupal\Component\Plugin\Definition\PluginDefinitionInterface|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) {
$missing_class_message = sprintf('The plugin (%s) did not specify an instance class.', $plugin_id);
if (is_array($plugin_definition)) {
if (empty($plugin_definition['class'])) {
throw new PluginException($missing_class_message);
}
$class = $plugin_definition['class'];
}
elseif ($plugin_definition instanceof PluginDefinitionInterface) {
if (!$plugin_definition->getClass()) {
throw new PluginException($missing_class_message);
}
$class = $plugin_definition->getClass();
}
else {
$plugin_definition_type = is_object($plugin_definition) ? get_class($plugin_definition) : gettype($plugin_definition);
throw new PluginException(sprintf('%s can only handle plugin definitions that are arrays or that implement %s, but %s given.', __CLASS__, PluginDefinitionInterface::class, $plugin_definition_type));
}
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($class, $required_interface)) {
throw new PluginException(sprintf('Plugin "%s" (%s) must implement interface %s.', $plugin_id, $class, $required_interface));
}
return $class;
}
}

View file

@ -0,0 +1,26 @@
<?php
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,80 @@
<?php
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 {
/**
* {@inheritdoc}
*/
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 with 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,23 @@
<?php
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,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View file

@ -0,0 +1,160 @@
<?php
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,30 @@
<?php
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,18 @@
<?php
namespace Drupal\Component\Plugin;
/**
* Provides an interface for objects that depend on a plugin.
*/
interface PluginAwareInterface {
/**
* Sets the plugin for this object.
*
* @param \Drupal\Component\Plugin\PluginInspectionInterface $plugin
* The plugin.
*/
public function setPlugin(PluginInspectionInterface $plugin);
}

View file

@ -0,0 +1,96 @@
<?php
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,32 @@
<?php
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,95 @@
<?php
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,29 @@
<?php
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,12 @@
The Drupal Plugin Component
Thanks for using this Drupal component.
You can participate in its development on Drupal.org, through our issue system:
https://www.drupal.org/project/issues/drupal
You can get the full Drupal repo here:
https://www.drupal.org/project/drupal/git-instructions
You can browse the full Drupal repo here:
http://cgit.drupalcode.org/drupal

View file

@ -0,0 +1,18 @@
HOW-TO: Test this Drupal component
In order to test this component, you'll need to get the entire Drupal repo and
run the tests there.
You'll find the tests under core/tests/Drupal/Tests/Component.
You can get the full Drupal repo here:
https://www.drupal.org/project/drupal/git-instructions
You can find more information about running PHPUnit tests with Drupal here:
https://www.drupal.org/node/2116263
Each component in the Drupal\Component namespace has its own annotated test
group. You can use this group to run only the tests for this component. Like
this:
$ ./vendor/bin/phpunit -c core --group Plugin

View file

@ -0,0 +1,19 @@
{
"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.5.9",
"symfony/validator": "~2.7"
},
"autoload": {
"psr-4": {
"Drupal\\Component\\Plugin\\": ""
}
},
"suggest": {
"symfony/validator": "Leveraged in the use of context aware plugins."
}
}