diff --git a/core/lib/Drupal/Core/Condition/ConditionManager.php b/core/lib/Drupal/Core/Condition/ConditionManager.php index f6f7641..e847411 100644 --- a/core/lib/Drupal/Core/Condition/ConditionManager.php +++ b/core/lib/Drupal/Core/Condition/ConditionManager.php @@ -44,6 +44,14 @@ public function __construct(\Traversable $namespaces, CacheBackendInterface $cac */ public function createInstance($plugin_id, array $configuration = array()) { $plugin = $this->factory->createInstance($plugin_id, $configuration); + + // If we receive any context values via config set it into the plugin. + if (!empty($configuration['context'])) { + foreach ($configuration['context'] as $name => $context) { + $plugin->setContextValue($name, $context); + } + } + return $plugin->setExecutableManager($this); } diff --git a/core/lib/Drupal/Core/Condition/ConditionPluginBase.php b/core/lib/Drupal/Core/Condition/ConditionPluginBase.php index 279ef0f..341feec 100644 --- a/core/lib/Drupal/Core/Condition/ConditionPluginBase.php +++ b/core/lib/Drupal/Core/Condition/ConditionPluginBase.php @@ -17,6 +17,13 @@ /** * {@inheritdoc} */ + public static function contextDefinitions() { + return []; + } + + /** + * {@inheritdoc} + */ public function __construct(array $configuration, $plugin_id, $plugin_definition) { parent::__construct($configuration, $plugin_id, $plugin_definition); diff --git a/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php b/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php index fc851d3..adb474e 100644 --- a/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php +++ b/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php @@ -70,8 +70,6 @@ class ContextDefinition implements ContextDefinitionInterface { /** * Creates a new context definition. * - * @param \Drupal\Core\TypedData\TypedDataManager $typed_data_manager - * The typed data manager. * @param string $data_type * The data type for which to create the context definition. Defaults to * 'any'. @@ -79,9 +77,8 @@ class ContextDefinition implements ContextDefinitionInterface { * @return static * The created context definition object. */ - public static function create(TypedDataManager $typed_data_manager, $data_type = 'any') { + public static function create($data_type = 'any') { return new static( - $typed_data_manager, $data_type ); } @@ -89,19 +86,34 @@ public static function create(TypedDataManager $typed_data_manager, $data_type = /** * Constructs a new context definition object. * - * @param \Drupal\Core\TypedData\TypedDataManager $typed_data_manager - * The typed data manager. * @param string $data_type * The required data type. */ - public function __construct(TypedDataManager $typed_data_manager, $data_type = 'any') { - $this->typedDataManager = $typed_data_manager; + public function __construct($data_type = 'any') { $this->dataType = $data_type; } /** * {@inheritdoc} */ + public function setTypedDataManager(TypedDataManager $typed_data_manager) { + $this->typedDataManager = $typed_data_manager; + } + + /** + * {@inheritdoc} + */ + public function getTypedDataManager() { + if (empty($this->typedDataManager)) { + $this->typedDataManager = \Drupal::typedDataManager(); + } + + return $this->typedDataManager; + } + + /** + * {@inheritdoc} + */ public function getDataType() { return $this->dataType; } @@ -212,10 +224,10 @@ public function addConstraint($constraint_name, $options = NULL) { public function getDataDefinition() { // @todo Setters are missing from the core data definition interfaces. if ($this->isMultiple()) { - $definition = $this->typedDataManager->createListDataDefinition($this->getDataType()); + $definition = $this->getTypedDataManager()->createListDataDefinition($this->getDataType()); } else { - $definition = $this->typedDataManager->createDataDefinition($this->getDataType()); + $definition = $this->getTypedDataManager()->createDataDefinition($this->getDataType()); } $definition->setLabel($this->getLabel()) ->setDescription($this->getDescription()) diff --git a/core/lib/Drupal/Core/Plugin/Context/ContextDefinitionInterface.php b/core/lib/Drupal/Core/Plugin/Context/ContextDefinitionInterface.php index 8871def..4e4a94f 100644 --- a/core/lib/Drupal/Core/Plugin/Context/ContextDefinitionInterface.php +++ b/core/lib/Drupal/Core/Plugin/Context/ContextDefinitionInterface.php @@ -7,12 +7,28 @@ namespace Drupal\Core\Plugin\Context; +use Drupal\Core\TypedData\TypedDataManager; + /** * Interface for context definitions. */ interface ContextDefinitionInterface { /** + * Sets the typed data manager. + * + * @param \Drupal\Core\TypedData\TypedDataManager $typed_data_manager + */ + public function setTypedDataManager(TypedDataManager $typed_data_manager); + + /** + * Gets the typed data manager. + * + * @return \Drupal\Core\TypedData\TypedDataManager + */ + public function getTypedDataManager(); + + /** * Returns a human readable label. * * @return string diff --git a/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php b/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php index e688661..e1c636e 100644 --- a/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php +++ b/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php @@ -43,23 +43,11 @@ protected $contextDefinitions; /** - * Defines the needed context of this plugin. - * - * @todo: Can we make this abstract somehow? - * - * @return \Drupal\Core\Plugin\Context\ContextDefinitionInterface[] - * The array of context definitions, keyed by context name. - */ - public static function contextDefinitions() { - return []; - } - - /** * {@inheritdoc} */ public function getContextDefinitions() { if (!isset($this->contextDefinitions)) { - $this->contextDefinitions = static::contextDefinitions(); + $this->contextDefinitions = static::contextDefinitions(\Drupal::service('typed_data_manager')); } return $this->contextDefinitions; } diff --git a/core/lib/Drupal/Core/Plugin/ContextAwarePluginInterface.php b/core/lib/Drupal/Core/Plugin/ContextAwarePluginInterface.php index e6112b2..e4dae54 100644 --- a/core/lib/Drupal/Core/Plugin/ContextAwarePluginInterface.php +++ b/core/lib/Drupal/Core/Plugin/ContextAwarePluginInterface.php @@ -9,6 +9,7 @@ use Drupal\Component\Plugin\ContextAwarePluginInterface as ComponentContextAwarePluginInterface; use Drupal\Core\Plugin\Context\ContextInterface; +use Drupal\Core\TypedData\TypedDataManager; /** * Interface for context-aware plugins. @@ -25,4 +26,12 @@ */ public function setContext($name, ContextInterface $context); + /** + * Defines the needed context of this plugin. + * + * @return \Drupal\Core\Plugin\Context\ContextDefinitionInterface[] + * The array of context definitions, keyed by context name. + */ + public static function contextDefinitions(); + } diff --git a/core/modules/block/src/BlockBase.php b/core/modules/block/src/BlockBase.php index 994b12e..47e10a7 100644 --- a/core/modules/block/src/BlockBase.php +++ b/core/modules/block/src/BlockBase.php @@ -8,12 +8,10 @@ namespace Drupal\block; use Drupal\Core\Plugin\ContextAwarePluginBase; -use Drupal\block\BlockInterface; use Drupal\Component\Utility\Unicode; use Drupal\Component\Utility\NestedArray; use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Cache\Cache; -use Drupal\Core\Cache\CacheableInterface; use Drupal\Core\Session\AccountInterface; /** @@ -30,6 +28,13 @@ /** * {@inheritdoc} */ + public static function contextDefinitions() { + return []; + } + + /** + * {@inheritdoc} + */ public function label() { if (!empty($this->configuration['label'])) { return $this->configuration['label']; diff --git a/core/modules/language/src/Plugin/Condition/Language.php b/core/modules/language/src/Plugin/Condition/Language.php index e6268c2..9fc91d9 100644 --- a/core/modules/language/src/Plugin/Condition/Language.php +++ b/core/modules/language/src/Plugin/Condition/Language.php @@ -9,18 +9,15 @@ use Drupal\Core\Condition\ConditionPluginBase; use Drupal\Core\Language\LanguageInterface; +use Drupal\Core\Plugin\Context\ContextDefinition; +use Drupal\Core\TypedData\TypedDataManager; /** * Provides a 'Language' condition. * * @Condition( * id = "language", - * label = @Translation("Language"), - * context = { - * "language" = { - * "type" = "language" - * } - * } + * label = @Translation("Language") * ) */ class Language extends ConditionPluginBase { @@ -28,6 +25,16 @@ class Language extends ConditionPluginBase { /** * {@inheritdoc} */ + public static function contextDefinitions() { + $definitions['language'] = ContextDefinition::create('language') + ->setLabel(t('Language')); + + return $definitions; + } + + /** + * {@inheritdoc} + */ public function buildConfigurationForm(array $form, array &$form_state) { $form = parent::buildConfigurationForm($form, $form_state); if (\Drupal::languageManager()->isMultilingual()) { diff --git a/core/modules/node/src/Plugin/Condition/NodeType.php b/core/modules/node/src/Plugin/Condition/NodeType.php index 5b093bf..d0843e7 100644 --- a/core/modules/node/src/Plugin/Condition/NodeType.php +++ b/core/modules/node/src/Plugin/Condition/NodeType.php @@ -8,18 +8,14 @@ namespace Drupal\node\Plugin\Condition; use Drupal\Core\Condition\ConditionPluginBase; +use Drupal\Core\Plugin\Context\ContextDefinition; /** * Provides a 'Node Type' condition. * * @Condition( * id = "node_type", - * label = @Translation("Node Bundle"), - * context = { - * "node" = { - * "type" = "entity:node" - * } - * } + * label = @Translation("Node Bundle") * ) */ class NodeType extends ConditionPluginBase { @@ -27,6 +23,16 @@ class NodeType extends ConditionPluginBase { /** * {@inheritdoc} */ + public static function contextDefinitions() { + $definitions['node'] = ContextDefinition::create('entity:node') + ->setLabel(t('Node')); + + return $definitions; + } + + /** + * {@inheritdoc} + */ public function buildConfigurationForm(array $form, array &$form_state) { $form = parent::buildConfigurationForm($form, $form_state); $options = array(); diff --git a/core/modules/system/src/Tests/Plugin/ContextPluginTest.php b/core/modules/system/src/Tests/Plugin/ContextPluginTest.php index cd7dbfe..268d797 100644 --- a/core/modules/system/src/Tests/Plugin/ContextPluginTest.php +++ b/core/modules/system/src/Tests/Plugin/ContextPluginTest.php @@ -7,14 +7,15 @@ namespace Drupal\system\Tests\Plugin; -use Drupal\simpletest\DrupalUnitTestBase; +use Drupal\Component\Plugin\Exception\ContextException; +use Drupal\Core\Plugin\Context\ContextDefinition; use Drupal\plugin_test\Plugin\MockBlockManager; -use Drupal\Component\Plugin\Exception\PluginException; +use Drupal\simpletest\KernelTestBase; /** * Tests that context aware plugins function correctly. */ -class ContextPluginTest extends DrupalUnitTestBase { +class ContextPluginTest extends KernelTestBase { public static $modules = array('system', 'user', 'node', 'field', 'filter', 'text'); @@ -36,51 +37,26 @@ function testContext() { // Create a node, add it as context, catch the exception. $node = entity_create('node', array('title' => $name, 'type' => 'page')); - // Try to get a valid context that has not been set. + // Try to get context that is missing its definition. try { - $plugin->getContext('user'); + $plugin->getContextDefinition('not_exists'); $this->fail('The user context should not yet be set.'); } - catch (PluginException $e) { - $this->assertEqual($e->getMessage(), 'The user context is not yet set.'); + catch (ContextException $e) { + $this->assertEqual($e->getMessage(), 'The not_exists context is not a valid context.'); } - // Try to get an invalid context. - try { - $plugin->getContext('node'); - $this->fail('The node context should not be a valid context.'); - } - catch (PluginException $e) { - $this->assertEqual($e->getMessage(), 'The node context is not a valid context.'); - } + // Test the getContextDefinitions() method. + $this->assertEqual($plugin->getContextDefinitions(), array('user' => ContextDefinition::create('entity:user')->setLabel(t('User')))); - // Try to get a valid context value that has not been set. - try { - $plugin->getContextValue('user'); - $this->fail('The user context should not yet be set.'); - } - catch (PluginException $e) { - $this->assertEqual($e->getMessage(), 'The user context is not yet set.'); - } + // Test the getContextDefinition() method for a valid context. + $this->assertEqual($plugin->getContextDefinition('user'), ContextDefinition::create('entity:user')->setLabel(t('User'))); - // Try to call a method of the plugin that requires context before it has - // been set. - try { - $plugin->getTitle(); - $this->fail('The user context should not yet be set.'); - } - catch (PluginException $e) { - $this->assertEqual($e->getMessage(), 'The user context is not yet set.'); - } + // Try to get a context with valid definition. + $this->assertNotNull($plugin->getContext('user'), 'Succeeded to get a context with a valid definition.'); - // Try to get a context value that is not valid. - try { - $plugin->getContextValue('node'); - $this->fail('The node context should not be a valid context.'); - } - catch (PluginException $e) { - $this->assertEqual($e->getMessage(), 'The node context is not a valid context.'); - } + // Try to get a value of a valid context, while this value has not been set. + $this->assertNull($plugin->getContextValue('user'), 'Requesting a non-set value of a valid context should return NULL.'); // Try to pass the wrong class type as a context value. $plugin->setContextValue('user', $node); @@ -93,75 +69,10 @@ function testContext() { $plugin->setContextValue('user', $user); $this->assertEqual($user->label(), $plugin->getTitle()); - // Test the getContextDefinitions() method. - $this->assertIdentical($plugin->getContextDefinitions(), array('user' => array('class' => 'Drupal\user\UserInterface'))); - - // Test the getContextDefinition() method for a valid context. - $this->assertEqual($plugin->getContextDefinition('user'), array('class' => 'Drupal\user\UserInterface')); - - // Test the getContextDefinition() method for an invalid context. - try { - $plugin->getContextDefinition('node'); - $this->fail('The node context should not be a valid context.'); - } - catch (PluginException $e) { - $this->assertEqual($e->getMessage(), 'The node context is not a valid context.'); - } - - // Test typed data context plugins. - $typed_data_plugin = $manager->createInstance('string_context'); - - // Try to get a valid context value that has not been set. - try { - $typed_data_plugin->getContextValue('string'); - $this->fail('The string context should not yet be set.'); - } - catch (PluginException $e) { - $this->assertEqual($e->getMessage(), 'The string context is not yet set.'); - } - - // Try to call a method of the plugin that requires a context value before - // it has been set. - try { - $typed_data_plugin->getTitle(); - $this->fail('The string context should not yet be set.'); - } - catch (PluginException $e) { - $this->assertEqual($e->getMessage(), 'The string context is not yet set.'); - } - - // Set the context value appropriately and check the title. - $typed_data_plugin->setContextValue('string', $name); - $this->assertEqual($name, $typed_data_plugin->getTitle()); - // Test Complex compound context handling. $complex_plugin = $manager->createInstance('complex_context'); - - // With no contexts set, try to get the contexts. - try { - $complex_plugin->getContexts(); - $this->fail('There should not be any contexts set yet.'); - } - catch (PluginException $e) { - $this->assertEqual($e->getMessage(), 'There are no set contexts.'); - } - - // With no contexts set, try to get the context values. - $values = $complex_plugin->getContextValues(); - $this->assertIdentical(array_filter($values), array(), 'There are no set contexts.'); - - // Set the user context value. $complex_plugin->setContextValue('user', $user); - // With only the user context set, try to get the contexts. - try { - $complex_plugin->getContexts(); - $this->fail('The node context should not yet be set.'); - } - catch (PluginException $e) { - $this->assertEqual($e->getMessage(), 'The node context is not yet set.'); - } - // With only the user context set, try to get the context values. $values = $complex_plugin->getContextValues(); $this->assertNull($values['node'], 'The node context is not yet set.'); diff --git a/core/modules/system/tests/modules/plugin_test/src/Plugin/MockBlockManager.php b/core/modules/system/tests/modules/plugin_test/src/Plugin/MockBlockManager.php index cd3d030..7f5c252 100644 --- a/core/modules/system/tests/modules/plugin_test/src/Plugin/MockBlockManager.php +++ b/core/modules/system/tests/modules/plugin_test/src/Plugin/MockBlockManager.php @@ -76,28 +76,18 @@ public function __construct() { $this->discovery->setDefinition('user_name', array( 'label' => t('User name'), 'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockUserNameBlock', - 'context' => array( - 'user' => array('class' => 'Drupal\user\UserInterface') - ), )); // A block plugin that requires a typed data string context to function. $this->discovery->setDefinition('string_context', array( 'label' => t('String typed data'), 'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\TypedDataStringBlock', - 'context' => array( - 'string' => array('type' => 'string'), - ), )); // A complex context plugin that requires both a user and node for context. $this->discovery->setDefinition('complex_context', array( 'label' => t('Complex context'), 'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockComplexContextBlock', - 'context' => array( - 'user' => array('class' => 'Drupal\user\UserInterface'), - 'node' => array('class' => 'Drupal\node\NodeInterface'), - ), )); // In addition to finding all of the plugins available for a type, a plugin 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 1cb657a..2d78d88 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 @@ -7,6 +7,7 @@ namespace Drupal\plugin_test\Plugin\plugin_test\mock_block; +use Drupal\Core\Plugin\Context\ContextDefinition; use Drupal\Core\Plugin\ContextAwarePluginBase; /** @@ -16,6 +17,15 @@ */ class MockComplexContextBlock extends ContextAwarePluginBase { + /** + * {@inheritdoc} + */ + public static function contextDefinitions() { + $definitions['user'] = ContextDefinition::create('entity:user')->setLabel(t('User')); + $definitions['node'] = ContextDefinition::create('entity:node')->setLabel(t('Node')); + return $definitions; + } + public function getTitle() { $user = $this->getContextValue('user'); $node = $this->getContextValue('node'); 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 9150167..6719396 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 @@ -7,6 +7,7 @@ namespace Drupal\plugin_test\Plugin\plugin_test\mock_block; +use Drupal\Core\Plugin\Context\ContextDefinition; use Drupal\Core\Plugin\ContextAwarePluginBase; /** @@ -16,6 +17,14 @@ */ class MockUserNameBlock extends ContextAwarePluginBase { + /** + * {@inheritdoc} + */ + public static function contextDefinitions() { + $context['user'] = ContextDefinition::create('entity:user')->setLabel(t('User')); + return $context; + } + public function getTitle() { $user = $this->getContextValue('user'); return $user->label(); 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 14e0ab3..f911bfd 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 @@ -17,6 +17,13 @@ */ class TypedDataStringBlock extends ContextAwarePluginBase { + /** + * {@inheritdoc} + */ + public static function contextDefinitions() { + return []; + } + public function getTitle() { return $this->getContextValue('string'); } diff --git a/core/modules/user/src/Plugin/Condition/UserRole.php b/core/modules/user/src/Plugin/Condition/UserRole.php index e9740da..150489d 100644 --- a/core/modules/user/src/Plugin/Condition/UserRole.php +++ b/core/modules/user/src/Plugin/Condition/UserRole.php @@ -8,18 +8,14 @@ namespace Drupal\user\Plugin\Condition; use Drupal\Core\Condition\ConditionPluginBase; +use Drupal\Core\Plugin\Context\ContextDefinition; /** * Provides a 'User Role' condition. * * @Condition( * id = "user_role", - * label = @Translation("User Role"), - * context = { - * "user" = { - * "type" = "entity:user" - * } - * } + * label = @Translation("User Role") * ) */ class UserRole extends ConditionPluginBase { @@ -27,6 +23,16 @@ class UserRole extends ConditionPluginBase { /** * {@inheritdoc} */ + public static function contextDefinitions() { + $definitions['user'] = ContextDefinition::create('entity:user') + ->setLabel(t('User')); + + return $definitions; + } + + /** + * {@inheritdoc} + */ public function buildConfigurationForm(array $form, array &$form_state) { $form = parent::buildConfigurationForm($form, $form_state); $form['roles'] = array(