Commit 109dfd58 authored by alexpott's avatar alexpott

Issue #2852463 by mikelutz, tim.plunkett, heddn, xjm, MegaChriz, joachim,...

Issue #2852463 by mikelutz, tim.plunkett, heddn, xjm, MegaChriz, joachim, phenaproxima, dawehner, benjifisher: Create a trait to implement \Drupal\Component\Plugin\ConfigurableInterface
parent 58146e48
<?php
namespace Drupal\Component\Plugin;
use Drupal\Component\Utility\NestedArray;
/**
* Implements \Drupal\Component\Plugin\ConfigurableInterface.
*
* In order for configurable plugins to maintain their configuration, the
* default configuration must be merged into any explicitly defined
* configuration. This trait provides the appropriate getters and setters to
* handle this logic, removing the need for excess boilerplate.
*
* @ingroup Plugin
*
* @todo Add protected $configuration property when PHP 5 is no longer
* supported. See https://www.drupal.org/project/drupal/issues/3029004.
*/
trait ConfigurableTrait {
/**
* Gets this plugin's configuration.
*
* @return array
* An array of this plugin's configuration.
*
* @see \Drupal\Component\Plugin\ConfigurableInterface::getConfiguration()
*/
public function getConfiguration() {
return $this->configuration;
}
/**
* Sets the configuration for this plugin instance.
*
* @param array $configuration
* An associative array containing the plugin's configuration.
*
* @return $this
*
* @see \Drupal\Component\Plugin\ConfigurableInterface::setConfiguration()
*/
public function setConfiguration(array $configuration) {
$this->configuration = NestedArray::mergeDeepArray([$this->defaultConfiguration(), $configuration], TRUE);
return $this;
}
/**
* Gets default configuration for this plugin.
*
* @return array
* An associative array with the default configuration.
*
* @see \Drupal\Component\Plugin\ConfigurableInterface::defaultConfiguration()
*/
public function defaultConfiguration() {
return [];
}
}
......@@ -51,9 +51,20 @@ abstract class PluginBase implements PluginInspectionInterface, DerivativeInspec
* The plugin implementation definition.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition) {
$this->configuration = $configuration;
$this->pluginId = $plugin_id;
$this->pluginDefinition = $plugin_definition;
if ($this->isConfigurable()) {
// @todo Some plugins use getConfiguration() and setConfiguration() to
// manipulate external configuration storage but still expect
// $this->configuration to be set. Deprecate this in
// https://www.drupal.org/project/drupal/issues/3029077.
$this->configuration = $configuration;
$this->setConfiguration($configuration);
}
else {
$this->configuration = $configuration;
}
if ($this instanceof ConfigurablePluginInterface && !$this instanceof ConfigurableInterface) {
@trigger_error('Drupal\Component\Plugin\ConfigurablePluginInterface is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. You should implement ConfigurableInterface and/or DependentPluginInterface directly as needed. If you implement ConfigurableInterface you may choose to implement ConfigurablePluginInterface in Drupal 8 as well for maximum compatibility, however this must be removed prior to Drupal 9. See https://www.drupal.org/node/2946161', E_USER_DEPRECATED);
......
......@@ -6,6 +6,7 @@
use Drupal\Component\Plugin\ConfigurablePluginInterface;
use Drupal\Component\Plugin\DependentPluginInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Component\Plugin\ConfigurableTrait;
use Drupal\Core\Plugin\PluginFormInterface;
/**
......@@ -13,35 +14,7 @@
*/
abstract class ConfigurableActionBase extends ActionBase implements ConfigurableInterface, DependentPluginInterface, ConfigurablePluginInterface, PluginFormInterface {
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->setConfiguration($configuration);
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
return [];
}
/**
* {@inheritdoc}
*/
public function getConfiguration() {
return $this->configuration;
}
/**
* {@inheritdoc}
*/
public function setConfiguration(array $configuration) {
$this->configuration = $configuration + $this->defaultConfiguration();
}
use ConfigurableTrait;
/**
* {@inheritdoc}
......
......@@ -5,6 +5,7 @@
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerTrait;
use Drupal\Component\Plugin\ConfigurableTrait;
use Drupal\Core\Plugin\ContextAwarePluginAssignmentTrait;
use Drupal\Core\Plugin\ContextAwarePluginBase;
use Drupal\Component\Utility\NestedArray;
......@@ -26,6 +27,7 @@
*/
abstract class BlockBase extends ContextAwarePluginBase implements BlockPluginInterface, PluginWithFormsInterface, PreviewFallbackInterface {
use ConfigurableTrait;
use ContextAwarePluginAssignmentTrait;
use MessengerTrait;
use PluginWithFormsTrait;
......@@ -51,21 +53,6 @@ public function label() {
return (string) $definition['admin_label'];
}
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->setConfiguration($configuration);
}
/**
* {@inheritdoc}
*/
public function getConfiguration() {
return $this->configuration;
}
/**
* {@inheritdoc}
*/
......@@ -92,13 +79,6 @@ protected function baseConfigurationDefaults() {
];
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
return [];
}
/**
* {@inheritdoc}
*/
......
......@@ -6,6 +6,7 @@
use Drupal\Core\Executable\ExecutablePluginBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Form\SubformStateInterface;
use Drupal\Component\Plugin\ConfigurableTrait;
use Drupal\Core\Plugin\ContextAwarePluginAssignmentTrait;
/**
......@@ -19,6 +20,7 @@
*/
abstract class ConditionPluginBase extends ExecutablePluginBase implements ConditionInterface {
use ConfigurableTrait;
use ContextAwarePluginAssignmentTrait;
/**
......@@ -28,15 +30,6 @@ abstract class ConditionPluginBase extends ExecutablePluginBase implements Condi
*/
protected $executableManager;
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->setConfiguration($configuration);
}
/**
* {@inheritdoc}
*/
......@@ -93,14 +86,6 @@ public function getConfiguration() {
] + $this->configuration;
}
/**
* {@inheritdoc}
*/
public function setConfiguration(array $configuration) {
$this->configuration = $configuration + $this->defaultConfiguration();
return $this;
}
/**
* {@inheritdoc}
*/
......
......@@ -2,6 +2,7 @@
namespace Drupal\Core\Display;
use Drupal\Component\Plugin\ConfigurableTrait;
use Drupal\Core\Cache\RefinableCacheableDependencyTrait;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\PluginBase;
......@@ -18,18 +19,10 @@
*/
abstract class VariantBase extends PluginBase implements VariantInterface {
use ConfigurableTrait;
use PluginDependencyTrait;
use RefinableCacheableDependencyTrait;
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->setConfiguration($configuration);
}
/**
* {@inheritdoc}
*/
......@@ -74,14 +67,6 @@ public function getConfiguration() {
] + $this->configuration;
}
/**
* {@inheritdoc}
*/
public function setConfiguration(array $configuration) {
$this->configuration = $configuration + $this->defaultConfiguration();
return $this;
}
/**
* {@inheritdoc}
*/
......
......@@ -2,7 +2,7 @@
namespace Drupal\Core\Layout;
use Drupal\Component\Utility\NestedArray;
use Drupal\Component\Plugin\ConfigurableTrait;
use Drupal\Core\Plugin\PluginBase;
/**
......@@ -10,6 +10,8 @@
*/
class LayoutDefault extends PluginBase implements LayoutInterface {
use ConfigurableTrait;
/**
* The layout definition.
*
......@@ -17,14 +19,6 @@ class LayoutDefault extends PluginBase implements LayoutInterface {
*/
protected $pluginDefinition;
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->setConfiguration($configuration);
}
/**
* {@inheritdoc}
*/
......@@ -45,27 +39,6 @@ public function build(array $regions) {
return $build;
}
/**
* {@inheritdoc}
*/
public function getConfiguration() {
return $this->configuration;
}
/**
* {@inheritdoc}
*/
public function setConfiguration(array $configuration) {
$this->configuration = NestedArray::mergeDeep($this->defaultConfiguration(), $configuration);
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
return [];
}
/**
* {@inheritdoc}
*/
......
......@@ -101,8 +101,8 @@ public function testBlockMigration() {
$visibility = [
'request_path' => [
'id' => 'request_path',
'negate' => TRUE,
'pages' => "<front>\n/node/1\n/blog/*",
'negate' => TRUE,
],
];
$settings = [
......@@ -131,10 +131,10 @@ public function testBlockMigration() {
'roles' => [
'authenticated' => 'authenticated',
],
'negate' => FALSE,
'context_mapping' => [
'user' => '@user.current_user_context:current_user',
],
'negate' => FALSE,
],
];
$settings = [
......@@ -152,10 +152,10 @@ public function testBlockMigration() {
'roles' => [
'migrate_test_role_1' => 'migrate_test_role_1',
],
'negate' => FALSE,
'context_mapping' => [
'user' => '@user.current_user_context:current_user',
],
'negate' => FALSE,
],
];
$settings = [
......@@ -171,8 +171,8 @@ public function testBlockMigration() {
$visibility = [
'request_path' => [
'id' => 'request_path',
'negate' => TRUE,
'pages' => '/node/1',
'negate' => TRUE,
],
];
$settings = [
......@@ -254,8 +254,8 @@ public function testBlockMigration() {
$visibility = [
'request_path' => [
'id' => 'request_path',
'negate' => FALSE,
'pages' => '<front>',
'negate' => FALSE,
],
];
$settings = [
......@@ -272,8 +272,8 @@ public function testBlockMigration() {
$visibility = [
'request_path' => [
'id' => 'request_path',
'negate' => FALSE,
'pages' => '/node',
'negate' => FALSE,
],
];
$settings = [
......
......@@ -2,6 +2,7 @@
namespace Drupal\image;
use Drupal\Component\Plugin\ConfigurableTrait;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Plugin\PluginBase;
use Psr\Log\LoggerInterface;
......@@ -19,6 +20,8 @@
*/
abstract class ImageEffectBase extends PluginBase implements ImageEffectInterface, ContainerFactoryPluginInterface {
use ConfigurableTrait;
/**
* The image effect ID.
*
......@@ -46,7 +49,6 @@ abstract class ImageEffectBase extends PluginBase implements ImageEffectInterfac
public function __construct(array $configuration, $plugin_id, $plugin_definition, LoggerInterface $logger) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->setConfiguration($configuration);
$this->logger = $logger;
}
......@@ -151,13 +153,6 @@ public function setConfiguration(array $configuration) {
return $this;
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
return [];
}
/**
* {@inheritdoc}
*/
......
......@@ -2,7 +2,7 @@
namespace Drupal\search\Plugin;
use Drupal\Component\Utility\NestedArray;
use Drupal\Component\Plugin\ConfigurableTrait;
use Drupal\Core\Form\FormStateInterface;
/**
......@@ -10,6 +10,8 @@
*/
abstract class ConfigurableSearchPluginBase extends SearchPluginBase implements ConfigurableSearchPluginInterface {
use ConfigurableTrait;
/**
* The unique ID for the search page using this plugin.
*
......@@ -17,36 +19,6 @@ abstract class ConfigurableSearchPluginBase extends SearchPluginBase implements
*/
protected $searchPageId;
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->setConfiguration($configuration);
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
return [];
}
/**
* {@inheritdoc}
*/
public function getConfiguration() {
return $this->configuration;
}
/**
* {@inheritdoc}
*/
public function setConfiguration(array $configuration) {
$this->configuration = NestedArray::mergeDeep($this->defaultConfiguration(), $configuration);
}
/**
* {@inheritdoc}
*/
......
......@@ -3,6 +3,7 @@
namespace Drupal\workflows\Plugin;
use Drupal\Component\Plugin\PluginBase;
use Drupal\Component\Plugin\ConfigurableTrait;
use Drupal\Core\Plugin\PluginWithFormsTrait;
use Drupal\workflows\State;
use Drupal\workflows\StateInterface;
......@@ -18,6 +19,7 @@
*/
abstract class WorkflowTypeBase extends PluginBase implements WorkflowTypeInterface {
use ConfigurableTrait;
use PluginWithFormsTrait;
/**
......@@ -25,14 +27,6 @@ abstract class WorkflowTypeBase extends PluginBase implements WorkflowTypeInterf
*/
const VALID_ID_REGEX = '/[^a-z0-9_]+/';
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->setConfiguration($configuration);
}
/**
* {@inheritdoc}
*/
......@@ -57,13 +51,6 @@ public function workflowStateHasData(WorkflowInterface $workflow, StateInterface
return FALSE;
}
/**
* {@inheritdoc}
*/
public function getConfiguration() {
return $this->configuration;
}
/**
* {@inheritdoc}
*/
......
<?php
namespace Drupal\Tests\Component\Plugin;
use Drupal\Component\Plugin\ConfigurableInterface;
use Drupal\Component\Plugin\ConfigurableTrait;
use Drupal\Component\Plugin\PluginBase;
use PHPUnit\Framework\TestCase;
/**
* Tests for ConfigurableTrait.
*
* @coversDefaultClass \Drupal\Component\Plugin\ConfigurableTrait
*
* @group Plugin
*/
class ConfigurableTraitTest extends TestCase {
/**
* Tests ConfigurableTrait::defaultConfiguration.
*
* @covers ::defaultConfiguration
*/
public function testDefaultConfiguration() {
/** @var \Drupal\Component\Plugin\ConfigurableInterface $configurable_plugin */
$configurable_plugin = $this->getMockForTrait(ConfigurableTrait::class);
$this->assertSame([], $configurable_plugin->defaultConfiguration());
}
/**
* Tests ConfigurableTrait::getConfiguration.
*
* @covers ::getConfiguration
*/
public function testGetConfiguration() {
$test_configuration = [
'config_key_1' => 'config_value_1',
'config_key_2' => [
'nested_key_1' => 'nested_value_1',
'nested_key_2' => 'nested_value_2',
],
];
$configurable_plugin = new ConfigurableTestClass($test_configuration);
$this->assertSame($test_configuration, $configurable_plugin->getConfiguration());
}
/**
* Tests configurableTrait::setConfiguration.
*
* Specifically test the way default and provided configurations are merged.
*
* @param array $default_configuration
* The default configuration to use for the trait.
* @param array $test_configuration
* The configuration to test.
* @param array $final_configuration
* The expected final plugin configuration.
*
* @covers ::setConfiguration
*
* @dataProvider setConfigurationDataProvider
*/
public function testSetConfiguration(array $default_configuration, array $test_configuration, array $final_configuration) {
$test_object = new ConfigurableTestClass($default_configuration);
$test_object->setConfiguration($test_configuration);
$this->assertSame($final_configuration, $test_object->getConfiguration());
}
/**
* Provides data for testSetConfiguration.
*
* @return array
* The data.
*/
public function setConfigurationDataProvider() {
return [
'Direct Override' => [
'default_configuration' => [
'default_key_1' => 'default_value_1',
'default_key_2' => [
'default_nested_key_1' => 'default_nested_value_1',
'default_nested_key_2' => 'default_nested_value_2',
],
],
'test_configuration' => [
'default_key_1' => 'override_value_1',
'default_key_2' => [
'default_nested_key_1' => 'override_nested_value_1',
'default_nested_key_2' => 'override_nested_value_2',
],
],
'final_configuration' => [
'default_key_1' => 'override_value_1',
'default_key_2' => [
'default_nested_key_1' => 'override_nested_value_1',
'default_nested_key_2' => 'override_nested_value_2',
],
],
],
'Mixed Override' => [
'default_configuration' => [
'default_key_1' => 'default_value_1',
'default_key_2' => [
'default_nested_key_1' => 'default_nested_value_1',
'default_nested_key_2' => 'default_nested_value_2',
],
],
'test_configuration' => [
'override_key_1' => 'config_value_1',
'default_key_2' => [
'default_nested_key_1' => 'override_value_1',
'override_nested_key' => 'override_value',
],
],
'final_configuration' => [
'default_key_1' => 'default_value_1',
'default_key_2' => [
'default_nested_key_1' => 'override_value_1',
'default_nested_key_2' => 'default_nested_value_2',
'override_nested_key' => 'override_value',
],
'override_key_1' => 'config_value_1',
],
],
'indexed_override' => [
'default_configuration' => [
'config_value_1',
'config_value_2',
'config_value_3',
],
'test_configuration' => [
'override_value_1',
'override_value_2',
],
'final_configuration' => [
'override_value_1',
'override_value_2',
'config_value_3',
],
],
'indexed_override_complex' => [
'default_configuration' => [
'config_value_1',
'config_value_2',
'config_value_3',
],
'test_configuration' => [
0 => 'override_value_1',
2 => 'override_value_3',
],
'final_configuration' => [
'override_value_1',
'config_value_2',
'override_value_3',
],
],
];
}
}
/**
* A test class using ConfigurablePluginTrait.
*/
class ConfigurableTestClass extends PluginBase implements ConfigurableInterface {
use ConfigurableTrait;
/**
* A default configuration for the test class to return.
*
* @var array
*/
protected $defaultConfiguration;
/**
* Constructs a ConfigurablePluginTestClass object.
*
* @param array $default_configuration
* The default configuration to return.
*/
public function __construct(array $default_configuration) {
$this->defaultConfiguration = $default_configuration;
parent::__construct([], '', []);
}
/**
* Returns the provided test defaults.
*
* @return array
* The default configuration.
*/
public function defaultConfiguration() {
return $this->defaultConfiguration;
}
}
......@@ -4,6 +4,7 @@
use Drupal\Component\Plugin\ConfigurableInterface;
use Drupal\Component\Plugin\PluginBase;
use Drupal\Component\Plugin\ConfigurableTrait;
use Drupal\Core\Plugin\DefaultSingleLazyPluginCollection;
/**
...