Commit a2f9a607 authored by alexpott's avatar alexpott

Issue #2033383 by tim.plunkett: Provide a default plugin bag.

parent 1d4d6ed2
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\ConfigurablePluginInterface.
*/
namespace Drupal\Component\Plugin;
/**
* Provides an interface for a configurable plugin.
*/
interface ConfigurablePluginInterface {
/**
* Returns 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);
}
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\DefaultPluginBag.
*/
namespace Drupal\Component\Plugin;
use Drupal\Component\Plugin\Exception\PluginException;
use Drupal\Component\Utility\MapArray;
use Drupal\Component\Utility\String;
/**
* Provides a default plugin bag for a plugin type.
*
* A plugin bag is used to contain plugins that will be lazily instantiated. The
* configurations of each potential plugin are passed in, and the configuration
* key containing the plugin ID is specified by self::$pluginKey.
*/
class DefaultPluginBag extends PluginBag {
/**
* The manager used to instantiate the plugins.
*
* @var \Drupal\Component\Plugin\PluginManagerInterface
*/
protected $manager;
/**
* The initial configuration for each plugin in the bag.
*
* @var array
* An associative array containing the initial configuration for each plugin
* in the bag, keyed by plugin instance ID.
*/
protected $configurations = array();
/**
* The key within the plugin configuration that contains the plugin ID.
*
* @var string
*/
protected $pluginKey = 'id';
/**
* Constructs a new DefaultPluginBag object.
*
* @param \Drupal\Component\Plugin\PluginManagerInterface $manager
* The manager to be used for instantiating plugins.
* @param array $configurations
* (optional) An associative array containing the initial configuration for
* each plugin in the bag, keyed by plugin instance ID.
*/
public function __construct(PluginManagerInterface $manager, array $configurations = array()) {
$this->manager = $manager;
$this->configurations = $configurations;
if (!empty($configurations)) {
$this->instanceIDs = MapArray::copyValuesToKeys(array_keys($configurations));
}
}
/**
* {@inheritdoc}
*/
protected function initializePlugin($instance_id) {
$configuration = $this->configurations[$instance_id];
if (!isset($configuration[$this->pluginKey])) {
throw new PluginException(String::format("Unknown plugin ID '@instance'.", array('@instance' => $instance_id)));
}
$this->pluginInstances[$instance_id] = $this->manager->createInstance($configuration[$this->pluginKey], $configuration);
$this->addInstanceID($instance_id);
}
/**
* Sorts all plugin instances in this bag.
*
* @return self
* Returns the plugin bag.
*/
public function sort() {
uasort($this->instanceIDs, array($this, 'sortHelper'));
return $this;
}
/**
* Provides uasort() callback to sort plugins.
*/
public function sortHelper($aID, $bID) {
$a = $this->get($aID);
$b = $this->get($bID);
return strnatcasecmp($a->getPluginId(), $b->getPluginId());
}
/**
* Returns the current configuration of all plugins in this bag.
*
* @return array
* An associative array keyed by instance ID, whose values are up-to-date
* plugin configurations.
*/
public function getConfiguration() {
$instances = array();
$this->rewind();
foreach ($this as $instance_id => $instance) {
if ($instance instanceof ConfigurablePluginInterface) {
$instances[$instance_id] = $instance->getConfiguration();
}
else {
$instances[$instance_id] = $this->configurations[$instance_id];
}
}
return $instances;
}
/**
* Updates the configuration for a plugin instance.
*
* If there is no plugin instance yet, a new will be instantiated. Otherwise,
* the existing instance is updated with the new configuration.
*
* @param string $instance_id
* The ID of a plugin to set the configuration for.
* @param array $configuration
* The plugin configuration to set.
*/
public function setConfiguration($instance_id, array $configuration) {
$this->configurations[$instance_id] = $configuration;
$instance = $this->get($instance_id);
if ($instance instanceof ConfigurablePluginInterface) {
$instance->setConfiguration($configuration);
}
}
}
<?php
/**
* @file
* Contains \Drupal\Component\Plugin\DefaultSinglePluginBag.
*/
namespace Drupal\Component\Plugin;
use Drupal\Component\Utility\MapArray;
/**
* Provides a default plugin bag for a plugin type.
*
* A plugin bag usually stores multiple plugins, and is used to lazily
* instantiate them. When only one plugin is needed, it is still best practice
* to encapsulate all of the instantiation logic in a plugin bag. This class can
* be used directly, or subclassed to add further exception handling in
* self::initializePlugin().
*/
class DefaultSinglePluginBag extends PluginBag {
/**
* The manager used to instantiate the plugins.
*
* @var \Drupal\Component\Plugin\PluginManagerInterface
*/
protected $manager;
/**
* An array of configuration to instantiate the plugin with.
*
* @var array
*/
protected $configuration;
/**
* Constructs a new DefaultSinglePluginBag object.
*
* @param \Drupal\Component\Plugin\PluginManagerInterface $manager
* The manager to be used for instantiating plugins.
* @param array $instance_ids
* The IDs of the plugin instances with which we are dealing.
* @param array $configuration
* An array of configuration.
*/
public function __construct(PluginManagerInterface $manager, array $instance_ids, array $configuration) {
$this->manager = $manager;
$this->instanceIDs = MapArray::copyValuesToKeys($instance_ids);
$this->configuration = $configuration;
}
/**
* {@inheritdoc}
*/
protected function initializePlugin($instance_id) {
$this->pluginInstances[$instance_id] = $this->manager->createInstance($instance_id, $this->configuration);
}
}
...@@ -7,46 +7,20 @@ ...@@ -7,46 +7,20 @@
namespace Drupal\Core\Action; namespace Drupal\Core\Action;
use Drupal\Component\Plugin\PluginBag; use Drupal\Component\Plugin\DefaultSinglePluginBag;
use Drupal\Component\Plugin\PluginManagerInterface;
/** /**
* Provides a container for lazily loading Action plugins. * Provides a container for lazily loading Action plugins.
*/ */
class ActionBag extends PluginBag { class ActionBag extends DefaultSinglePluginBag {
/**
* The manager used to instantiate the plugins.
*
* @var \Drupal\Component\Plugin\PluginManagerInterface
*/
protected $manager;
/**
* Constructs a new ActionBag object.
*
* @param \Drupal\Component\Plugin\PluginManagerInterface $manager
* The manager to be used for instantiating plugins.
* @param array $instance_ids
* The ids of the plugin instances with which we are dealing.
* @param array $configuration
* An array of configuration.
*/
public function __construct(PluginManagerInterface $manager, array $instance_ids, array $configuration) {
$this->manager = $manager;
$this->instanceIDs = drupal_map_assoc($instance_ids);
$this->configuration = $configuration;
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @return \Drupal\Core\Action\ActionInterface
*/ */
protected function initializePlugin($instance_id) { public function &get($instance_id) {
if (isset($this->pluginInstances[$instance_id])) { return parent::get($instance_id);
return;
}
$this->pluginInstances[$instance_id] = $this->manager->createInstance($instance_id, $this->configuration);
} }
} }
...@@ -7,13 +7,14 @@ ...@@ -7,13 +7,14 @@
namespace Drupal\Core\Action; namespace Drupal\Core\Action;
use Drupal\Core\Action\ConfigurableActionInterface; use Drupal\Component\Plugin\ConfigurablePluginInterface;
use Drupal\Core\Action\ActionBase; use Drupal\Core\Action\ActionBase;
use Drupal\Core\Plugin\PluginFormInterface;
/** /**
* Provides a base implementation for a configurable Action plugin. * Provides a base implementation for a configurable Action plugin.
*/ */
abstract class ConfigurableActionBase extends ActionBase implements ConfigurableActionInterface { abstract class ConfigurableActionBase extends ActionBase implements ConfigurablePluginInterface, PluginFormInterface {
/** /**
* {@inheritdoc} * {@inheritdoc}
...@@ -43,7 +44,14 @@ public function getConfiguration() { ...@@ -43,7 +44,14 @@ public function getConfiguration() {
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function validate(array &$form, array &$form_state) { public function setConfiguration(array $configuration) {
$this->configuration = $configuration;
}
/**
* {@inheritdoc}
*/
public function validateConfigurationForm(array &$form, array &$form_state) {
} }
} }
...@@ -23,7 +23,7 @@ class AlterDecorator implements DiscoveryInterface { ...@@ -23,7 +23,7 @@ class AlterDecorator implements DiscoveryInterface {
/** /**
* The Discovery object being decorated. * The Discovery object being decorated.
* *
* @var Drupal\Component\Plugin\Discovery\DiscoveryInterface * @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface
*/ */
protected $decorated; protected $decorated;
...@@ -32,7 +32,7 @@ class AlterDecorator implements DiscoveryInterface { ...@@ -32,7 +32,7 @@ class AlterDecorator implements DiscoveryInterface {
* *
* It uses the DiscoveryInterface object it should decorate. * It uses the DiscoveryInterface object it should decorate.
* *
* @param Drupal\Component\Plugin\Discovery\DiscoveryInterface $decorated * @param \Drupal\Component\Plugin\Discovery\DiscoveryInterface $decorated
* The object implementing DiscoveryInterface that is being decorated. * The object implementing DiscoveryInterface that is being decorated.
* @param string $hook * @param string $hook
* The name of the alter hook that will be used by this discovery instance. * The name of the alter hook that will be used by this discovery instance.
...@@ -56,7 +56,7 @@ public function getDefinition($plugin_id) { ...@@ -56,7 +56,7 @@ public function getDefinition($plugin_id) {
*/ */
public function getDefinitions() { public function getDefinitions() {
$definitions = $this->decorated->getDefinitions(); $definitions = $this->decorated->getDefinitions();
drupal_alter($this->hook, $definitions); \Drupal::moduleHandler()->alter($this->hook, $definitions);
return $definitions; return $definitions;
} }
......
...@@ -2,28 +2,15 @@ ...@@ -2,28 +2,15 @@
/** /**
* @file * @file
* Contains \Drupal\Core\Action\ConfigurableActionInterface. * Contains \Drupal\Core\Plugin\PluginFormInterface.
*/ */
namespace Drupal\Core\Action; namespace Drupal\Core\Plugin;
use Drupal\Core\Action\ActionInterface;
/** /**
* Provides an interface for an Action plugin. * Provides an interface for a plugin that contains a form.
*
* @see \Drupal\Core\Annotation\Operation
* @see \Drupal\Core\Action\OperationManager
*/ */
interface ConfigurableActionInterface extends ActionInterface { interface PluginFormInterface {
/**
* Returns this plugin's configuration.
*
* @return array
* An array of this action plugin's configuration.
*/
public function getConfiguration();
/** /**
* Form constructor. * Form constructor.
...@@ -36,7 +23,7 @@ public function getConfiguration(); ...@@ -36,7 +23,7 @@ public function getConfiguration();
* @return array * @return array
* The form structure. * The form structure.
*/ */
public function form(array $form, array &$form_state); public function buildConfigurationForm(array $form, array &$form_state);
/** /**
* Form validation handler. * Form validation handler.
...@@ -46,16 +33,21 @@ public function form(array $form, array &$form_state); ...@@ -46,16 +33,21 @@ public function form(array $form, array &$form_state);
* @param array $form_state * @param array $form_state
* An associative array containing the current state of the form. * An associative array containing the current state of the form.
*/ */
public function validate(array &$form, array &$form_state); public function validateConfigurationForm(array &$form, array &$form_state);
/** /**
* Form submission handler. * Form submission handler.
* *
* To properly store submitted form values store them in $this->configuration.
* @code
* $this->configuration['some_value'] = $form_state['values']['some_value'];
* @endcode
*
* @param array $form * @param array $form
* An associative array containing the structure of the form. * An associative array containing the structure of the form.
* @param array $form_state * @param array $form_state
* An associative array containing the current state of the form. * An associative array containing the current state of the form.
*/ */
public function submit(array &$form, array &$form_state); public function submitConfigurationForm(array &$form, array &$form_state);
} }
...@@ -10,8 +10,8 @@ ...@@ -10,8 +10,8 @@
use Drupal\Core\Entity\EntityControllerInterface; use Drupal\Core\Entity\EntityControllerInterface;
use Drupal\Core\Entity\EntityFormController; use Drupal\Core\Entity\EntityFormController;
use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Action\ConfigurableActionInterface;
use Drupal\Core\Entity\EntityStorageControllerInterface; use Drupal\Core\Entity\EntityStorageControllerInterface;
use Drupal\Core\Plugin\PluginFormInterface;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
/** /**
...@@ -97,8 +97,8 @@ public function form(array $form, array &$form_state) { ...@@ -97,8 +97,8 @@ public function form(array $form, array &$form_state) {
'#value' => $this->entity->getType(), '#value' => $this->entity->getType(),
); );
if ($this->plugin instanceof ConfigurableActionInterface) { if ($this->plugin instanceof PluginFormInterface) {
$form += $this->plugin->form($form, $form_state); $form += $this->plugin->buildConfigurationForm($form, $form_state);
} }
return parent::form($form, $form_state); return parent::form($form, $form_state);
...@@ -133,8 +133,8 @@ protected function actions(array $form, array &$form_state) { ...@@ -133,8 +133,8 @@ protected function actions(array $form, array &$form_state) {
public function validate(array $form, array &$form_state) { public function validate(array $form, array &$form_state) {
parent::validate($form, $form_state); parent::validate($form, $form_state);
if ($this->plugin instanceof ConfigurableActionInterface) { if ($this->plugin instanceof PluginFormInterface) {
$this->plugin->validate($form, $form_state); $this->plugin->validateConfigurationForm($form, $form_state);
} }
} }
...@@ -144,8 +144,8 @@ public function validate(array $form, array &$form_state) { ...@@ -144,8 +144,8 @@ public function validate(array $form, array &$form_state) {
public function submit(array $form, array &$form_state) { public function submit(array $form, array &$form_state) {
parent::submit($form, $form_state); parent::submit($form, $form_state);
if ($this->plugin instanceof ConfigurableActionInterface) { if ($this->plugin instanceof PluginFormInterface) {
$this->plugin->submit($form, $form_state); $this->plugin->submitConfigurationForm($form, $form_state);
} }
return $this->entity; return $this->entity;
} }
......
...@@ -57,7 +57,7 @@ public function getFormID() { ...@@ -57,7 +57,7 @@ public function getFormID() {
public function buildForm(array $form, array &$form_state) { public function buildForm(array $form, array &$form_state) {
$actions = array(); $actions = array();
foreach ($this->manager->getDefinitions() as $id => $definition) { foreach ($this->manager->getDefinitions() as $id => $definition) {
if (is_subclass_of($definition['class'], '\Drupal\Core\Action\ConfigurableActionInterface')) { if (is_subclass_of($definition['class'], '\Drupal\Core\Plugin\PluginFormInterface')) {
$key = Crypt::hashBase64($id); $key = Crypt::hashBase64($id);
$actions[$key] = $definition['label'] . '...'; $actions[$key] = $definition['label'] . '...';
} }
......
...@@ -116,7 +116,7 @@ protected function getDefaultConfiguration() { ...@@ -116,7 +116,7 @@ protected function getDefaultConfiguration() {
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function form(array $form, array &$form_state) { public function buildConfigurationForm(array $form, array &$form_state) {
$form['recipient'] = array( $form['recipient'] = array(
'#type' => 'textfield', '#type' => 'textfield',
'#title' => t('Recipient'), '#title' => t('Recipient'),
...@@ -145,7 +145,7 @@ public function form(array $form, array &$form_state) { ...@@ -145,7 +145,7 @@ public function form(array $form, array &$form_state) {
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function validate(array &$form, array &$form_state) { public function validateConfigurationForm(array &$form, array &$form_state) {
if (!valid_email_address($form_state['values']['recipient']) && strpos($form_state['values']['recipient'], ':mail') === FALSE) { if (!valid_email_address($form_state['values']['recipient']) && strpos($form_state['values']['recipient'], ':mail') === FALSE) {
// We want the literal %author placeholder to be emphasized in the error message. // We want the literal %author placeholder to be emphasized in the error message.
form_set_error('recipient', t('Enter a valid email address or use a token e-mail address such as %author.', array('%author' => '[node:author:mail]'))); form_set_error('recipient', t('Enter a valid email address or use a token e-mail address such as %author.', array('%author' => '[node:author:mail]')));
...@@ -155,7 +155,7 @@ public function validate(array &$form, array &$form_state) { ...@@ -155,7 +155,7 @@ public function validate(array &$form, array &$form_state) {
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function submit(array &$form, array &$form_state) { public function submitConfigurationForm(array &$form, array &$form_state) {
$this->configuration['recipient'] = $form_state['values']['recipient']; $this->configuration['recipient'] = $form_state['values']['recipient'];
$this->configuration['subject'] = $form_state['values']['subject']; $this->configuration['subject'] = $form_state['values']['subject'];
$this->configuration['message'] = $form_state['values']['message']; $this->configuration['message'] = $form_state['values']['message'];
......
...@@ -96,7 +96,7 @@ protected function getDefaultConfiguration() { ...@@ -96,7 +96,7 @@ protected function getDefaultConfiguration() {
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function form(array $form, array &$form_state) { public function buildConfigurationForm(array $form, array &$form_state) {
$form['url'] = array( $form['url'] = array(
'#type' => 'textfield', '#type' => 'textfield',
'#title' => t('URL'), '#title' => t('URL'),
...@@ -110,7 +110,7 @@ public function form(array $form, array &$form_state) { ...@@ -110,7 +110,7 @@ public function form(array $form, array &$form_state) {
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function submit(array &$form, array &$form_state) { public function submitConfigurationForm(array &$form, array &$form_state) {
$this->configuration['url'] = $form_state['values']['url']; $this->configuration['url'] = $form_state['values']['url'];
} }
......
...@@ -70,7 +70,7 @@ protected function getDefaultConfiguration() { ...@@ -70,7 +70,7 @@ protected function getDefaultConfiguration() {
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function form(array $form, array &$form_state) { public function buildConfigurationForm(array $form, array &$form_state) {
$form['message'] = array( $form['message'] = array(
'#type' => 'textarea', '#type' => 'textarea',
'#title' => t('Message'), '#title' => t('Message'),
...@@ -85,7 +85,7 @@ public function form(array $form, array &$form_state) { ...@@ -85,7 +85,7 @@ public function form(array $form, array &$form_state) {
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function submit(array &$form, array &$form_state) { public function submitConfigurationForm(array &$form, array &$form_state) {
$this->configuration['message'] = $form_state['values']['message']; $this->configuration['message'] = $form_state['values']['message'];
unset($this->configuration['node']); unset($this->configuration['node']);
} }
......
...@@ -50,50 +50,28 @@ public function settings() { ...@@ -50,50 +50,28 @@ public function settings() {
} }
/** /**
* Returns the configuration data for the block plugin. * {@inheritdoc}
*