diff --git a/core/lib/Drupal/Component/Plugin/ContextAwarePluginBase.php b/core/lib/Drupal/Component/Plugin/ContextAwarePluginBase.php index 7f61c504e07b85f4f81ffaebc3dd7d1338a20c44..533b026236ab8876082887ccf65b3c90aadf20a6 100644 --- a/core/lib/Drupal/Component/Plugin/ContextAwarePluginBase.php +++ b/core/lib/Drupal/Component/Plugin/ContextAwarePluginBase.php @@ -42,6 +42,9 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition parent::__construct($configuration, $plugin_id, $plugin_definition); + if ($context_configuration) { + @trigger_error('Passing context values to plugins via configuration is deprecated in drupal:9.1.0 and will be removed before drupal:10.0.0. Instead, call ::setContextValue() on the plugin itself. See https://www.drupal.org/node/3120980', E_USER_DEPRECATED); + } $this->context = $this->createContextFromConfiguration($context_configuration); } diff --git a/core/lib/Drupal/Core/Block/BlockBase.php b/core/lib/Drupal/Core/Block/BlockBase.php index 7076da42af71c6b76732b37d45c6361d32cb5ec5..ab6948f8ca9209d9474fd6c21952671c73635a1b 100644 --- a/core/lib/Drupal/Core/Block/BlockBase.php +++ b/core/lib/Drupal/Core/Block/BlockBase.php @@ -3,7 +3,9 @@ namespace Drupal\Core\Block; use Drupal\Core\Plugin\ContextAwarePluginAssignmentTrait; -use Drupal\Core\Plugin\ContextAwarePluginBase; +use Drupal\Core\Plugin\ContextAwarePluginInterface; +use Drupal\Core\Plugin\ContextAwarePluginTrait; +use Drupal\Core\Plugin\PluginBase; use Drupal\Core\Plugin\PluginWithFormsInterface; use Drupal\Core\Render\PreviewFallbackInterface; @@ -16,9 +18,10 @@ * * @ingroup block_api */ -abstract class BlockBase extends ContextAwarePluginBase implements BlockPluginInterface, PluginWithFormsInterface, PreviewFallbackInterface { +abstract class BlockBase extends PluginBase implements BlockPluginInterface, PluginWithFormsInterface, PreviewFallbackInterface, ContextAwarePluginInterface { use BlockPluginTrait; + use ContextAwarePluginTrait; use ContextAwarePluginAssignmentTrait; } diff --git a/core/lib/Drupal/Core/Condition/ConditionManager.php b/core/lib/Drupal/Core/Condition/ConditionManager.php index 2bacf2a0e93328922ff25622f34f2c28240c9082..be4a4b5f89a6919c1a6c856a8021ba5fd6acebb6 100644 --- a/core/lib/Drupal/Core/Condition/ConditionManager.php +++ b/core/lib/Drupal/Core/Condition/ConditionManager.php @@ -60,6 +60,7 @@ public function createInstance($plugin_id, array $configuration = []) { // If we receive any context values via config set it into the plugin. if (!empty($configuration['context'])) { + @trigger_error('Passing context values to plugins via configuration is deprecated in drupal:9.1.0 and will be removed before drupal:10.0.0. Instead, call ::setContextValue() on the plugin itself. See https://www.drupal.org/node/3120980', E_USER_DEPRECATED); foreach ($configuration['context'] as $name => $context) { $plugin->setContextValue($name, $context); } diff --git a/core/lib/Drupal/Core/Executable/ExecutablePluginBase.php b/core/lib/Drupal/Core/Executable/ExecutablePluginBase.php index 088bd3735bf0e87874196132d81df339a755b70d..c9632a1d5c3d4829ded3b07e932060fce63893b8 100644 --- a/core/lib/Drupal/Core/Executable/ExecutablePluginBase.php +++ b/core/lib/Drupal/Core/Executable/ExecutablePluginBase.php @@ -2,13 +2,18 @@ namespace Drupal\Core\Executable; -use Drupal\Core\Plugin\ContextAwarePluginBase; use Drupal\Component\Plugin\Exception\PluginException; +use Drupal\Core\Cache\CacheableDependencyInterface; +use Drupal\Core\Plugin\ContextAwarePluginInterface; +use Drupal\Core\Plugin\ContextAwarePluginTrait; +use Drupal\Core\Plugin\PluginBase; /** * Provides the basic architecture for executable plugins. */ -abstract class ExecutablePluginBase extends ContextAwarePluginBase implements ExecutableInterface { +abstract class ExecutablePluginBase extends PluginBase implements ExecutableInterface, CacheableDependencyInterface, ContextAwarePluginInterface { + + use ContextAwarePluginTrait; /** * Gets an array of definitions of available configuration options. diff --git a/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php b/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php index c40c02783f58146d00bcaf54bda3f2b9b3043580..1be0e353a51b30e18fdea3783262121d179b1c73 100644 --- a/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php +++ b/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php @@ -3,21 +3,20 @@ namespace Drupal\Core\Plugin; use Drupal\Component\Plugin\ContextAwarePluginBase as ComponentContextAwarePluginBase; -use Drupal\Component\Plugin\Exception\ContextException; -use Drupal\Component\Plugin\PluginHelper; -use Drupal\Core\Cache\Cache; use Drupal\Core\Cache\CacheableDependencyInterface; use Drupal\Core\DependencyInjection\DependencySerializationTrait; use Drupal\Core\Plugin\Context\Context; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\Core\TypedData\TypedDataTrait; -use Drupal\Component\Plugin\Context\ContextInterface as ComponentContextInterface; -use Drupal\Core\Plugin\Context\ContextInterface; + +@trigger_error(__NAMESPACE__ . '\ContextAwarePluginBase is deprecated in drupal:9.1.0 and will be removed before drupal:10.0.0. Instead, use \Drupal\Core\Plugin\ContextAwarePluginTrait. See https://www.drupal.org/node/3120980', E_USER_DEPRECATED); /** * Base class for plugins that are context aware. */ abstract class ContextAwarePluginBase extends ComponentContextAwarePluginBase implements ContextAwarePluginInterface, CacheableDependencyInterface { + + use ContextAwarePluginTrait; use TypedDataTrait; use StringTranslationTrait; use DependencySerializationTrait; @@ -38,139 +37,4 @@ protected function createContextFromConfiguration(array $context_configuration) return $contexts; } - /** - * {@inheritdoc} - * - * This code is identical to the Component in order to pick up a different - * Context class. - * - * @return \Drupal\Core\Plugin\Context\ContextInterface - * The context object. - */ - 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, ComponentContextInterface $context) { - // Check that the context passed is an instance of our extended interface. - if (!$context instanceof ContextInterface) { - throw new ContextException("Passed $name context must be an instance of \\Drupal\\Core\\Plugin\\Context\\ContextInterface"); - } - parent::setContext($name, $context); - } - - /** - * {@inheritdoc} - */ - public function setContextValue($name, $value) { - $this->setContext($name, Context::createFromContext($this->getContext($name), $value)); - return $this; - } - - /** - * {@inheritdoc} - */ - public function getContextMapping() { - $configuration = PluginHelper::isConfigurable($this) ? $this->getConfiguration() : $this->configuration; - return isset($configuration['context_mapping']) ? $configuration['context_mapping'] : []; - } - - /** - * {@inheritdoc} - */ - public function setContextMapping(array $context_mapping) { - if (PluginHelper::isConfigurable($this)) { - $configuration = $this->getConfiguration(); - $configuration['context_mapping'] = array_filter($context_mapping); - $this->setConfiguration($configuration); - } - else { - $this->configuration['context_mapping'] = $context_mapping; - } - return $this; - } - - /** - * {@inheritdoc} - * - * @return \Drupal\Core\Plugin\Context\ContextDefinitionInterface[] - */ - public function getContextDefinitions() { - return parent::getContextDefinitions(); - } - - /** - * {@inheritdoc} - * - * @return \Drupal\Core\Plugin\Context\ContextDefinitionInterface - */ - public function getContextDefinition($name) { - return parent::getContextDefinition($name); - } - - /** - * Wraps the context handler. - * - * @return \Drupal\Core\Plugin\Context\ContextHandlerInterface - */ - protected function contextHandler() { - return \Drupal::service('context.handler'); - } - - /** - * {@inheritdoc} - */ - public function getCacheContexts() { - $cache_contexts = []; - // Applied contexts can affect the cache contexts when this plugin is - // involved in caching, collect and return them. - foreach ($this->getContexts() as $context) { - /** @var $context \Drupal\Core\Cache\CacheableDependencyInterface */ - if ($context instanceof CacheableDependencyInterface) { - $cache_contexts = Cache::mergeContexts($cache_contexts, $context->getCacheContexts()); - } - } - return $cache_contexts; - } - - /** - * {@inheritdoc} - */ - public function getCacheTags() { - $tags = []; - // Applied contexts can affect the cache tags when this plugin is - // involved in caching, collect and return them. - foreach ($this->getContexts() as $context) { - /** @var $context \Drupal\Core\Cache\CacheableDependencyInterface */ - if ($context instanceof CacheableDependencyInterface) { - $tags = Cache::mergeTags($tags, $context->getCacheTags()); - } - } - return $tags; - } - - /** - * {@inheritdoc} - */ - public function getCacheMaxAge() { - $max_age = Cache::PERMANENT; - - // Applied contexts can affect the cache max age when this plugin is - // involved in caching, collect and return them. - foreach ($this->getContexts() as $context) { - /** @var $context \Drupal\Core\Cache\CacheableDependencyInterface */ - if ($context instanceof CacheableDependencyInterface) { - $max_age = Cache::mergeMaxAges($max_age, $context->getCacheMaxAge()); - } - } - return $max_age; - } - } diff --git a/core/lib/Drupal/Core/Plugin/ContextAwarePluginInterface.php b/core/lib/Drupal/Core/Plugin/ContextAwarePluginInterface.php index 67f53b69704f3b3a61556e2fa10b52e9e9c3865d..7b48f99347b18a83b29822e5ec3294a7c1644d27 100644 --- a/core/lib/Drupal/Core/Plugin/ContextAwarePluginInterface.php +++ b/core/lib/Drupal/Core/Plugin/ContextAwarePluginInterface.php @@ -8,6 +8,7 @@ * An override of ContextAwarePluginInterface for documentation purposes. * * @see \Drupal\Component\Plugin\ContextAwarePluginInterface + * @see \Drupal\Core\Plugin\ContextAwarePluginTrait * * @ingroup plugin_api */ diff --git a/core/lib/Drupal/Core/Plugin/ContextAwarePluginTrait.php b/core/lib/Drupal/Core/Plugin/ContextAwarePluginTrait.php new file mode 100644 index 0000000000000000000000000000000000000000..5d3445618af85c68688f1e2a311712e20e61a5b4 --- /dev/null +++ b/core/lib/Drupal/Core/Plugin/ContextAwarePluginTrait.php @@ -0,0 +1,251 @@ +<?php + +namespace Drupal\Core\Plugin; + +use Drupal\Component\Plugin\ConfigurableInterface; +use Drupal\Component\Plugin\Context\ContextInterface as ComponentContextInterface; +use Drupal\Component\Plugin\Definition\ContextAwarePluginDefinitionInterface; +use Drupal\Component\Plugin\Exception\ContextException; +use Drupal\Core\Cache\Cache; +use Drupal\Core\Cache\CacheableDependencyInterface; +use Drupal\Core\Plugin\Context\Context; +use Drupal\Core\Plugin\Context\ContextInterface; +use Symfony\Component\Validator\ConstraintViolationList; + +/** + * Provides a trait to add context-aware functionality to plugins. + * + * @see \Drupal\Core\Plugin\ContextAwarePluginInterface + * + * @ingroup plugin_api + */ +trait ContextAwarePluginTrait { + + /** + * The data objects representing the context of this plugin. + * + * @var \Drupal\Core\Plugin\Context\ContextInterface[] + */ + protected $context = []; + + /** + * Tracks whether the context has been initialized from configuration. + * + * @var bool + * + * @todo Remove this in Drupal 10.0.x. + * See https://www.drupal.org/project/drupal/issues/3153956. + * + * @internal + */ + protected $initializedContextConfig = FALSE; + + /** + * {@inheritdoc} + */ + public function getContexts() { + // Make sure all context objects are initialized. + foreach ($this->getContextDefinitions() as $name => $definition) { + $this->getContext($name); + } + return $this->context; + } + + /** + * {@inheritdoc} + * + * @return \Drupal\Core\Plugin\Context\ContextInterface + * The context object. + */ + public function getContext($name) { + // @todo Remove this entire block in Drupal 10.0.x. + // See https://www.drupal.org/project/drupal/issues/3153956. + if (!$this->initializedContextConfig) { + $this->initializedContextConfig = TRUE; + if ($this instanceof ConfigurableInterface) { + $configuration = $this->getConfiguration(); + } + else { + $reflection = new \ReflectionProperty($this, 'configuration'); + $reflection->setAccessible(TRUE); + $configuration = $reflection->getValue($this); + } + + if (isset($configuration['context'])) { + @trigger_error('Passing context values to plugins via configuration is deprecated in drupal:9.1.0 and will be removed before drupal:10.0.0. Instead, call ::setContextValue() on the plugin itself. See https://www.drupal.org/node/3120980', E_USER_DEPRECATED); + foreach ($configuration['context'] as $key => $value) { + $context_definition = $this->getContextDefinition($key); + $this->context[$key] = new Context($context_definition, $value); + } + } + } + + // 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, ComponentContextInterface $context) { + // Check that the context passed is an instance of our extended interface. + if (!$context instanceof ContextInterface) { + throw new ContextException("Passed $name context must be an instance of \\Drupal\\Core\\Plugin\\Context\\ContextInterface"); + } + $this->context[$name] = $context; + } + + /** + * {@inheritdoc} + */ + public function getContextValues() { + $values = []; + 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->setContext($name, Context::createFromContext($this->getContext($name), $value)); + return $this; + } + + /** + * {@inheritdoc} + */ + public function getContextMapping() { + $configuration = $this instanceof ConfigurableInterface ? $this->getConfiguration() : $this->configuration; + return isset($configuration['context_mapping']) ? $configuration['context_mapping'] : []; + } + + /** + * {@inheritdoc} + */ + public function setContextMapping(array $context_mapping) { + if ($this instanceof ConfigurableInterface) { + $configuration = $this->getConfiguration(); + $configuration['context_mapping'] = array_filter($context_mapping); + $this->setConfiguration($configuration); + } + else { + $this->configuration['context_mapping'] = $context_mapping; + } + return $this; + } + + /** + * {@inheritdoc} + */ + abstract protected function getPluginDefinition(); + + /** + * {@inheritdoc} + * + * @return \Drupal\Core\Plugin\Context\ContextDefinitionInterface[] + */ + public function getContextDefinitions() { + $definition = $this->getPluginDefinition(); + if ($definition instanceof ContextAwarePluginDefinitionInterface) { + return $definition->getContextDefinitions(); + } + + return !empty($definition['context_definitions']) ? $definition['context_definitions'] : []; + } + + /** + * {@inheritdoc} + * + * @return \Drupal\Core\Plugin\Context\ContextDefinitionInterface + */ + public function getContextDefinition($name) { + $definition = $this->getPluginDefinition(); + if ($definition instanceof ContextAwarePluginDefinitionInterface) { + if ($definition->hasContextDefinition($name)) { + return $definition->getContextDefinition($name); + } + } + elseif (!empty($definition['context_definitions'][$name])) { + return $definition['context_definitions'][$name]; + } + throw new ContextException(sprintf("The %s context is not a valid context.", $name)); + } + + /** + * {@inheritdoc} + */ + public function validateContexts() { + $violations = new ConstraintViolationList(); + + // @todo Implement the Symfony Validator component to let the validator + // traverse and set property paths accordingly. + // See https://www.drupal.org/project/drupal/issues/3153847. + foreach ($this->getContexts() as $context) { + $violations->addAll($context->validate()); + } + return $violations; + } + + /** + * {@inheritdoc} + */ + public function getCacheContexts() { + $cache_contexts = []; + // Applied contexts can affect the cache contexts when this plugin is + // involved in caching, collect and return them. + foreach ($this->getContexts() as $context) { + /** @var $context \Drupal\Core\Cache\CacheableDependencyInterface */ + if ($context instanceof CacheableDependencyInterface) { + $cache_contexts = Cache::mergeContexts($cache_contexts, $context->getCacheContexts()); + } + } + return $cache_contexts; + } + + /** + * {@inheritdoc} + */ + public function getCacheTags() { + $tags = []; + // Applied contexts can affect the cache tags when this plugin is + // involved in caching, collect and return them. + foreach ($this->getContexts() as $context) { + /** @var $context \Drupal\Core\Cache\CacheableDependencyInterface */ + if ($context instanceof CacheableDependencyInterface) { + $tags = Cache::mergeTags($tags, $context->getCacheTags()); + } + } + return $tags; + } + + /** + * {@inheritdoc} + */ + public function getCacheMaxAge() { + $max_age = Cache::PERMANENT; + + // Applied contexts can affect the cache max age when this plugin is + // involved in caching, collect and return them. + foreach ($this->getContexts() as $context) { + /** @var $context \Drupal\Core\Cache\CacheableDependencyInterface */ + if ($context instanceof CacheableDependencyInterface) { + $max_age = Cache::mergeMaxAges($max_age, $context->getCacheMaxAge()); + } + } + return $max_age; + } + +} diff --git a/core/modules/layout_builder/src/Plugin/SectionStorage/SectionStorageBase.php b/core/modules/layout_builder/src/Plugin/SectionStorage/SectionStorageBase.php index 415fed907ef5aa0cacea7c36f7d560261617c19e..41e63d148124df9c3804271162bba024c63ae035 100644 --- a/core/modules/layout_builder/src/Plugin/SectionStorage/SectionStorageBase.php +++ b/core/modules/layout_builder/src/Plugin/SectionStorage/SectionStorageBase.php @@ -2,9 +2,11 @@ namespace Drupal\layout_builder\Plugin\SectionStorage; +use Drupal\Core\Cache\CacheableDependencyInterface; use Drupal\Core\Plugin\Context\Context; use Drupal\Core\Plugin\Context\ContextDefinition; -use Drupal\Core\Plugin\ContextAwarePluginBase; +use Drupal\Core\Plugin\ContextAwarePluginTrait; +use Drupal\Core\Plugin\PluginBase; use Drupal\layout_builder\Routing\LayoutBuilderRoutesTrait; use Drupal\layout_builder\Section; use Drupal\layout_builder\SectionStorageInterface; @@ -13,8 +15,9 @@ /** * Provides a base class for Section Storage types. */ -abstract class SectionStorageBase extends ContextAwarePluginBase implements SectionStorageInterface, TempStoreIdentifierInterface { +abstract class SectionStorageBase extends PluginBase implements SectionStorageInterface, TempStoreIdentifierInterface, CacheableDependencyInterface { + use ContextAwarePluginTrait; use LayoutBuilderRoutesTrait; /** diff --git a/core/modules/layout_builder/tests/modules/layout_builder_test/src/Plugin/SectionStorage/SimpleConfigSectionStorage.php b/core/modules/layout_builder/tests/modules/layout_builder_test/src/Plugin/SectionStorage/SimpleConfigSectionStorage.php index a17ededaea7169e4bf73ee23f1a43649f181f707..f7316ec105178fada28e998c158a1038a2c75a1e 100644 --- a/core/modules/layout_builder/tests/modules/layout_builder_test/src/Plugin/SectionStorage/SimpleConfigSectionStorage.php +++ b/core/modules/layout_builder/tests/modules/layout_builder_test/src/Plugin/SectionStorage/SimpleConfigSectionStorage.php @@ -8,7 +8,8 @@ use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\Plugin\Context\Context; use Drupal\Core\Plugin\Context\ContextDefinition; -use Drupal\Core\Plugin\ContextAwarePluginBase; +use Drupal\Core\Plugin\ContextAwarePluginTrait; +use Drupal\Core\Plugin\PluginBase; use Drupal\Core\Session\AccountInterface; use Drupal\Core\Url; use Drupal\layout_builder\Plugin\SectionStorage\SectionStorageLocalTaskProviderInterface; @@ -29,8 +30,9 @@ * } * ) */ -class SimpleConfigSectionStorage extends ContextAwarePluginBase implements SectionStorageInterface, SectionStorageLocalTaskProviderInterface, ContainerFactoryPluginInterface { +class SimpleConfigSectionStorage extends PluginBase implements SectionStorageInterface, SectionStorageLocalTaskProviderInterface, ContainerFactoryPluginInterface { + use ContextAwarePluginTrait; use LayoutBuilderRoutesTrait; use SectionStorageTrait; diff --git a/core/modules/node/tests/src/Kernel/NodeConditionTest.php b/core/modules/node/tests/src/Kernel/NodeConditionTest.php index 0a9c6f7e201e5e66e42e8459f838deaa8e01d0c9..a52c0f3f42338b0322c57a0f04e2ddadc680a969 100644 --- a/core/modules/node/tests/src/Kernel/NodeConditionTest.php +++ b/core/modules/node/tests/src/Kernel/NodeConditionTest.php @@ -74,6 +74,16 @@ public function testConditions() { // Check a greater than 2 bundles summary scenario. $condition->setConfig('bundles', ['page' => 'page', 'article' => 'article', 'test' => 'test']); $this->assertEqual('The node bundle is page, article or test', $condition->summary()); + } + + /** + * @group legacy + */ + public function testLegacy() { + $this->expectDeprecation('Passing context values to plugins via configuration is deprecated in drupal:9.1.0 and will be removed before drupal:10.0.0. Instead, call ::setContextValue() on the plugin itself. See https://www.drupal.org/node/3120980'); + $manager = $this->container->get('plugin.manager.condition'); + $article = Node::create(['type' => 'article', 'title' => $this->randomMachineName(), 'uid' => 1]); + $article->save(); // Test Constructor injection. $condition = $manager->createInstance('node_type', ['bundles' => ['article' => 'article'], 'context' => ['node' => $article]]); diff --git a/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/mock_block/MockComplexContextBlock.php b/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/mock_block/MockComplexContextBlock.php index e044e27e32204ffff8f50eb3c6897d0ba87cc661..f791811302fe3a42aeca8ed92dbc634dfdb9e573 100644 --- a/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/mock_block/MockComplexContextBlock.php +++ b/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/mock_block/MockComplexContextBlock.php @@ -2,14 +2,18 @@ namespace Drupal\plugin_test\Plugin\plugin_test\mock_block; -use Drupal\Core\Plugin\ContextAwarePluginBase; +use Drupal\Core\Plugin\ContextAwarePluginInterface; +use Drupal\Core\Plugin\ContextAwarePluginTrait; +use Drupal\Core\Plugin\PluginBase; /** * Implementation of a complex context plugin used by Plugin API context tests. * * @see \Drupal\plugin_test\Plugin\MockBlockManager */ -class MockComplexContextBlock extends ContextAwarePluginBase { +class MockComplexContextBlock extends PluginBase implements ContextAwarePluginInterface { + + use ContextAwarePluginTrait; public function getTitle() { $user = $this->getContextValue('user'); diff --git a/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/mock_block/MockUserNameBlock.php b/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/mock_block/MockUserNameBlock.php index 6b4688d8acde250c2ab39785ca8f445e412b4efe..8ea56ede0eb5abcd89b203244c9e87700af0836c 100644 --- a/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/mock_block/MockUserNameBlock.php +++ b/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/mock_block/MockUserNameBlock.php @@ -2,14 +2,18 @@ namespace Drupal\plugin_test\Plugin\plugin_test\mock_block; -use Drupal\Core\Plugin\ContextAwarePluginBase; +use Drupal\Core\Plugin\ContextAwarePluginInterface; +use Drupal\Core\Plugin\ContextAwarePluginTrait; +use Drupal\Core\Plugin\PluginBase; /** * Implementation of a user name block plugin used by Plugin API context test. * * @see \Drupal\plugin_test\Plugin\MockBlockManager */ -class MockUserNameBlock extends ContextAwarePluginBase { +class MockUserNameBlock extends PluginBase implements ContextAwarePluginInterface { + + use ContextAwarePluginTrait; public function getTitle() { $user = $this->getContextValue('user'); diff --git a/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/mock_block/TypedDataStringBlock.php b/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/mock_block/TypedDataStringBlock.php index b47d46b4fca76d80c55949385aa2f41ceb21b5e5..5658cbf4240a00dce3ff08aa03ddad399cb764c0 100644 --- a/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/mock_block/TypedDataStringBlock.php +++ b/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/mock_block/TypedDataStringBlock.php @@ -2,7 +2,9 @@ namespace Drupal\plugin_test\Plugin\plugin_test\mock_block; -use Drupal\Core\Plugin\ContextAwarePluginBase; +use Drupal\Core\Plugin\ContextAwarePluginInterface; +use Drupal\Core\Plugin\ContextAwarePluginTrait; +use Drupal\Core\Plugin\PluginBase; /** * Implementation of a String TypedData contextual block plugin used by Plugin @@ -10,7 +12,9 @@ * * @see \Drupal\plugin_test\Plugin\MockBlockManager */ -class TypedDataStringBlock extends ContextAwarePluginBase { +class TypedDataStringBlock extends PluginBase implements ContextAwarePluginInterface { + + use ContextAwarePluginTrait; public function getTitle() { return $this->getContextValue('string'); diff --git a/core/modules/user/tests/src/Kernel/Condition/UserRoleConditionTest.php b/core/modules/user/tests/src/Kernel/Condition/UserRoleConditionTest.php index 73fa0546ead49188b130a1d8e94b5dc957f749c3..4bfb0588ef06b9b273722e2fc4a548937718e76b 100644 --- a/core/modules/user/tests/src/Kernel/Condition/UserRoleConditionTest.php +++ b/core/modules/user/tests/src/Kernel/Condition/UserRoleConditionTest.php @@ -135,10 +135,6 @@ public function testConditions() { $condition->setConfig('roles', [RoleInterface::AUTHENTICATED_ID => RoleInterface::AUTHENTICATED_ID]); $this->assertTrue($condition->execute(), 'Authenticated users pass role checks for authenticated.'); - // Test Constructor injection. - $condition = $this->manager->createInstance('user_role', ['roles' => [RoleInterface::AUTHENTICATED_ID => RoleInterface::AUTHENTICATED_ID], 'context' => ['user' => $this->authenticated]]); - $this->assertTrue($condition->execute(), 'Constructor injection of context and configuration working as anticipated.'); - // Check the negated summary. $condition->setConfig('negate', TRUE); $this->assertEqual($condition->summary(), 'The user is not a member of Authenticated user'); @@ -154,4 +150,14 @@ public function testConditions() { $this->assertEqual($condition->summary(), new FormattableMarkup('The user is a member of @roles', ['@roles' => $this->role->label()])); } + /** + * @group legacy + */ + public function testLegacy() { + $this->expectDeprecation('Passing context values to plugins via configuration is deprecated in drupal:9.1.0 and will be removed before drupal:10.0.0. Instead, call ::setContextValue() on the plugin itself. See https://www.drupal.org/node/3120980'); + // Test Constructor injection. + $condition = $this->manager->createInstance('user_role', ['roles' => [RoleInterface::AUTHENTICATED_ID => RoleInterface::AUTHENTICATED_ID], 'context' => ['user' => $this->authenticated]]); + $this->assertTrue($condition->execute(), 'Constructor injection of context and configuration working as anticipated.'); + } + } diff --git a/core/tests/Drupal/KernelTests/Core/Plugin/Context/ContextAwarePluginBaseTest.php b/core/tests/Drupal/KernelTests/Core/Plugin/Context/ContextAwarePluginBaseTest.php index fa25970de03ad84a2b2320be34a9e68233d1f1f2..2205e7c0715ecc42643adac66500406fcd397d07 100644 --- a/core/tests/Drupal/KernelTests/Core/Plugin/Context/ContextAwarePluginBaseTest.php +++ b/core/tests/Drupal/KernelTests/Core/Plugin/Context/ContextAwarePluginBaseTest.php @@ -2,7 +2,6 @@ namespace Drupal\KernelTests\Core\Plugin\Context; -use Drupal\Component\Plugin\Context\ContextInterface as ComponentContextInterface; use Drupal\Component\Plugin\Definition\ContextAwarePluginDefinitionInterface; use Drupal\Component\Plugin\Definition\ContextAwarePluginDefinitionTrait; use Drupal\Component\Plugin\Definition\PluginDefinition; @@ -19,6 +18,7 @@ * @coversDefaultClass \Drupal\Core\Plugin\ContextAwarePluginBase * * @group Plugin + * @group legacy */ class ContextAwarePluginBaseTest extends KernelTestBase { @@ -41,7 +41,10 @@ public function setUp(): void { ]; $plugin_definition = new TestPluginDefinition(); $plugin_definition->addContextDefinition('nato_letter', ContextDefinition::create('string')); - $this->plugin = new TestContextAwarePlugin($configuration, 'the_sisko', $plugin_definition); + $this->plugin = $this->getMockBuilder(ContextAwarePluginBase::class) + ->setConstructorArgs([$configuration, 'the_sisko', $plugin_definition]) + ->setMethods(['setContext']) + ->getMockForAbstractClass(); } /** @@ -81,9 +84,8 @@ public function testSetContextValue() { $this->plugin->getPluginDefinition()->addContextDefinition('foo', new ContextDefinition('string')); - $this->assertFalse($this->plugin->setContextCalled); + $this->plugin->expects($this->exactly(1))->method('setContext'); $this->plugin->setContextValue('foo', new StringData(new DataDefinition(), 'bar')); - $this->assertTrue($this->plugin->setContextCalled); } } @@ -93,22 +95,3 @@ class TestPluginDefinition extends PluginDefinition implements ContextAwarePlugi use ContextAwarePluginDefinitionTrait; } - -class TestContextAwarePlugin extends ContextAwarePluginBase { - - /** - * Indicates if ::setContext() has been called or not. - * - * @var bool - */ - public $setContextCalled = FALSE; - - /** - * {@inheritdoc} - */ - public function setContext($name, ComponentContextInterface $context) { - parent::setContext($name, $context); - $this->setContextCalled = TRUE; - } - -} diff --git a/core/tests/Drupal/KernelTests/Core/Plugin/Context/ContextAwarePluginTraitTest.php b/core/tests/Drupal/KernelTests/Core/Plugin/Context/ContextAwarePluginTraitTest.php new file mode 100644 index 0000000000000000000000000000000000000000..b5a7aeb2e7ffbce0aa558d051ba55e6e1b7ed20a --- /dev/null +++ b/core/tests/Drupal/KernelTests/Core/Plugin/Context/ContextAwarePluginTraitTest.php @@ -0,0 +1,184 @@ +<?php + +namespace Drupal\KernelTests\Core\Plugin\Context; + +use Drupal\Component\Plugin\ConfigurableInterface; +use Drupal\Component\Plugin\Context\ContextInterface as ComponentContextInterface; +use Drupal\Component\Plugin\Definition\ContextAwarePluginDefinitionInterface; +use Drupal\Component\Plugin\Definition\ContextAwarePluginDefinitionTrait; +use Drupal\Component\Plugin\Definition\PluginDefinition; +use Drupal\Component\Plugin\Exception\ContextException; +use Drupal\Core\DependencyInjection\ContainerBuilder; +use Drupal\Core\Plugin\Context\ContextDefinition; +use Drupal\Core\Plugin\ContextAwarePluginInterface; +use Drupal\Core\Plugin\ContextAwarePluginTrait; +use Drupal\Core\Plugin\PluginBase; +use Drupal\Core\TypedData\DataDefinition; +use Drupal\Core\TypedData\Plugin\DataType\StringData; +use Drupal\Core\TypedData\TypedDataManagerInterface; +use Drupal\KernelTests\KernelTestBase; +use Drupal\Tests\Traits\ExpectDeprecationTrait; + +/** + * @coversDefaultClass \Drupal\Core\Plugin\ContextAwarePluginTrait + * + * @group Plugin + */ +class ContextAwarePluginTraitTest extends KernelTestBase { + + use ExpectDeprecationTrait; + + /** + * The plugin instance under test. + * + * @var \Drupal\Core\Plugin\ContextAwarePluginTrait + */ + private $plugin; + + /** + * The configurable plugin instance under test. + * + * @var \Drupal\Core\Plugin\ContextAwarePluginTrait + */ + private $configurablePlugin; + + /** + * {@inheritdoc} + */ + public function setUp(): void { + parent::setUp(); + $plugin_definition = new TestContextAwarePluginDefinition(); + $plugin_definition->addContextDefinition('nato_letter', ContextDefinition::create('string')); + $this->plugin = new TestContextAwarePlugin([], 'the_sisko', $plugin_definition); + $this->configurablePlugin = new TestConfigurableContextAwarePlugin([], 'the_sisko', $plugin_definition); + } + + /** + * @covers ::getContextDefinitions + */ + public function testGetContextDefinitions() { + $this->assertIsArray($this->plugin->getContextDefinitions()); + } + + /** + * @covers ::getContextDefinition + */ + public function testGetContextDefinition() { + // The context is not defined, so an exception will be thrown. + $this->expectException(ContextException::class); + $this->expectExceptionMessage('The person context is not a valid context.'); + $this->plugin->getContextDefinition('person'); + } + + /** + * @covers ::getContextValue + */ + public function testGetContextValue() { + $this->plugin->setContextValue('nato_letter', 'Alpha'); + $this->assertSame('Alpha', $this->plugin->getContextValue('nato_letter')); + } + + /** + * @covers ::getContextValue + * @group legacy + */ + public function testGetContextValueFromConfiguration() { + $this->expectDeprecation('Passing context values to plugins via configuration is deprecated in drupal:9.1.0 and will be removed before drupal:10.0.0. Instead, call ::setContextValue() on the plugin itself. See https://www.drupal.org/node/3120980'); + $configuration = [ + 'context' => [ + 'nato_letter' => 'Alpha', + ], + ]; + $this->plugin = new TestContextAwarePlugin($configuration, 'the_sisko', $this->plugin->getPluginDefinition()); + // Assert that the context value passed in the plugin configuration is + // available. + $this->assertSame('Alpha', $this->plugin->getContextValue('nato_letter')); + } + + /** + * @covers ::getContextValue + * @group legacy + */ + public function testConfigurableGetContextValueFromConfiguration() { + $this->expectDeprecation('Passing context values to plugins via configuration is deprecated in drupal:9.1.0 and will be removed before drupal:10.0.0. Instead, call ::setContextValue() on the plugin itself. See https://www.drupal.org/node/3120980'); + // Assert that the context value passed in the plugin configuration is + // available. + $this->assertSame('Alpha', $this->configurablePlugin->getContextValue('nato_letter')); + } + + /** + * @covers ::setContextValue + */ + public function testSetContextValue() { + $typed_data_manager = $this->prophesize(TypedDataManagerInterface::class); + $container = new ContainerBuilder(); + $container->set('typed_data_manager', $typed_data_manager->reveal()); + \Drupal::setContainer($container); + + $this->plugin->getPluginDefinition()->addContextDefinition('foo', new ContextDefinition('string')); + + $this->assertFalse($this->plugin->setContextCalled); + $this->plugin->setContextValue('foo', new StringData(new DataDefinition(), 'bar')); + $this->assertTrue($this->plugin->setContextCalled); + } + +} + +class TestContextAwarePluginDefinition extends PluginDefinition implements ContextAwarePluginDefinitionInterface { + + use ContextAwarePluginDefinitionTrait; + +} + +class TestContextAwarePlugin extends PluginBase implements ContextAwarePluginInterface { + + use ContextAwarePluginTrait { + setContext as setContextTrait; + } + + /** + * Indicates if ::setContext() has been called or not. + * + * @var bool + */ + public $setContextCalled = FALSE; + + /** + * {@inheritdoc} + */ + public function setContext($name, ComponentContextInterface $context) { + $this->setContextTrait($name, $context); + $this->setContextCalled = TRUE; + } + +} + +class TestConfigurableContextAwarePlugin extends PluginBase implements ConfigurableInterface, ContextAwarePluginInterface { + + use ContextAwarePluginTrait; + + /** + * {@inheritdoc} + */ + public function defaultConfiguration() { + return []; + } + + /** + * {@inheritdoc} + */ + public function getConfiguration() { + return [ + 'context' => [ + 'nato_letter' => 'Alpha', + ], + ]; + } + + /** + * {@inheritdoc} + */ + public function setConfiguration(array $configuration) { + } + +} diff --git a/core/tests/Drupal/KernelTests/Core/Plugin/ContextHandlerTest.php b/core/tests/Drupal/KernelTests/Core/Plugin/ContextHandlerTest.php index a3a43d871c185e70269df03fe21d4a5b40b4fa0c..089731ea052bfa6c2a28994e64aebc490a998b07 100644 --- a/core/tests/Drupal/KernelTests/Core/Plugin/ContextHandlerTest.php +++ b/core/tests/Drupal/KernelTests/Core/Plugin/ContextHandlerTest.php @@ -5,7 +5,9 @@ use Drupal\Core\Plugin\Context\ContextHandler; use Drupal\Core\Plugin\Context\EntityContext; use Drupal\Core\Plugin\Context\EntityContextDefinition; -use Drupal\Core\Plugin\ContextAwarePluginBase; +use Drupal\Core\Plugin\ContextAwarePluginInterface; +use Drupal\Core\Plugin\ContextAwarePluginTrait; +use Drupal\Core\Plugin\PluginBase; use Drupal\entity_test\Entity\EntityTest; use Drupal\KernelTests\KernelTestBase; @@ -66,6 +68,8 @@ public function testApplyContextMappingAlreadyApplied() { /** * Provides a test implementation of a context-aware plugin. */ -class TestContextAwarePlugin extends ContextAwarePluginBase { +class TestContextAwarePlugin extends PluginBase implements ContextAwarePluginInterface { + + use ContextAwarePluginTrait; }