diff --git a/core/lib/Drupal/Component/Plugin/Context/Context.php b/core/lib/Drupal/Component/Plugin/Context/Context.php new file mode 100644 index 0000000..ce8ccf4 --- /dev/null +++ b/core/lib/Drupal/Component/Plugin/Context/Context.php @@ -0,0 +1,55 @@ +contextDefinition = $contextDefinition; + } + + public function setContext($context) { + $context = $this->validate($context); + $this->context = $context; + } + + public function getContext() { + return $this->context; + } + + public function validate($context) { + if (is_string($this->contextDefinition)) { + if ($context instanceof $this->contextDefinition) { + return $context; + } + throw new ContextException("The context passed was not an instance of $this->contextDefinition."); + } + throw new ContextException("An error was encountered while trying to validate the context."); + } + +} \ No newline at end of file diff --git a/core/lib/Drupal/Component/Plugin/ContextualPluginBase.php b/core/lib/Drupal/Component/Plugin/ContextualPluginBase.php new file mode 100644 index 0000000..a48d3e6 --- /dev/null +++ b/core/lib/Drupal/Component/Plugin/ContextualPluginBase.php @@ -0,0 +1,97 @@ +getDefinition(); + return !empty($definition['context']) ? $definition['context'] : NULL; + } + + /** + * Returns the a specific context class definition of the plugin. + * + * @return string + * The name of a class to which the set context must conform. + */ + public function getContextDefinition($key) { + $definition = $this->getDefinition(); + if (empty($definition['context'][$key])) { + throw new PluginException("The $key context is not a valid context."); + } + return $definition['context'][$key]; + } + + /** + * Returns the set values for all defined contexts. + * + * @return array + * Returns the array of all set contexts. + */ + public function getContexts() { + if (empty($this->configuration['context'])) { + throw new PluginException("There are no set contexts."); + } + return $this->configuration['context']; + } + + /** + * Returns the set value for a defined context. + * + * @return object + * Returns instantiated object of a context. + */ + public function getContext($key) { + return $this->getContextWrapper($key)->getContext(); + } + + /** + * Returns the set context wrapper for a defined context. + * + * @return object + * Returns a context wrapper object. + */ + public function getContextWrapper($key) { + $definition = $this->getDefinition(); + if (empty($definition['context'][$key])) { + throw new PluginException("The $key context is not a valid context."); + } + if (empty($this->configuration['context'][$key])) { + throw new PluginException("The $key context is not yet set."); + } + + return $this->configuration['context'][$key]; + } + + /** + * Sets a defined context to the passed value. + * + * @return $this + * Returns the plugin instance. + */ + public function setContext($key, $value) { + $class = $this->getContextDefinition($key); + $this->configuration['context'][$key] = new Context($class); + $this->configuration['context'][$key]->setContext($value); + + return $this; + } + +} diff --git a/core/lib/Drupal/Component/Plugin/Exception/ContextException.php b/core/lib/Drupal/Component/Plugin/Exception/ContextException.php new file mode 100644 index 0000000..fbb1c2d --- /dev/null +++ b/core/lib/Drupal/Component/Plugin/Exception/ContextException.php @@ -0,0 +1,15 @@ +contextDefinition)) { + if ($context instanceof $this->contextDefinition) { + return $context; + } + throw new ContextException("The context passed was not an instance of $this->contextDefinition."); + } + // Check to see if we have a typed data definition instead of a class name. + if (is_array($this->contextDefinition)) { + $typed_data_manager = new TypedDataManager(); + $typed_data = $typed_data_manager->create($this->contextDefinition, $context); + // If we do have a typed data definition, validate it and return the + // typed data instance instead. + if ($typed_data->validate()) { + return $typed_data; + } + throw new ContextException("The context passed could not be validated through typed data."); + } + throw new ContextException("An error was encountered while trying to validate the context."); + } + +} \ No newline at end of file diff --git a/core/lib/Drupal/Core/Plugin/ContextualPluginBase.php b/core/lib/Drupal/Core/Plugin/ContextualPluginBase.php new file mode 100644 index 0000000..ea47c33 --- /dev/null +++ b/core/lib/Drupal/Core/Plugin/ContextualPluginBase.php @@ -0,0 +1,32 @@ +getContextDefinition($key); + $this->configuration['context'][$key] = new Context($class); + $this->configuration['context'][$key]->setContext($value); + + return $this; + } + +} diff --git a/core/lib/Drupal/Core/TypedData/Type/Boolean.php b/core/lib/Drupal/Core/TypedData/Type/Boolean.php index c8797ef..b0f5027 100644 --- a/core/lib/Drupal/Core/TypedData/Type/Boolean.php +++ b/core/lib/Drupal/Core/TypedData/Type/Boolean.php @@ -35,6 +35,6 @@ public function setValue($value) { * Implements TypedDataInterface::validate(). */ public function validate() { - // TODO: Implement validate() method. + return is_bool($this->value); } } diff --git a/core/lib/Drupal/Core/TypedData/Type/Email.php b/core/lib/Drupal/Core/TypedData/Type/Email.php index e9a9c5a..8a1acb6 100644 --- a/core/lib/Drupal/Core/TypedData/Type/Email.php +++ b/core/lib/Drupal/Core/TypedData/Type/Email.php @@ -18,7 +18,7 @@ class Email extends String { * Implements \Drupal\Core\TypedData\TypedDataInterface::validate(). */ public function validate() { - // @todo Implement validate() method. + return filter_var($this->value, FILTER_VALIDATE_EMAIL) ? TRUE : FALSE; } } diff --git a/core/lib/Drupal/Core/TypedData/Type/Float.php b/core/lib/Drupal/Core/TypedData/Type/Float.php index 3e8369b..34730fb 100644 --- a/core/lib/Drupal/Core/TypedData/Type/Float.php +++ b/core/lib/Drupal/Core/TypedData/Type/Float.php @@ -35,6 +35,6 @@ public function setValue($value) { * Implements TypedDataInterface::validate(). */ public function validate() { - // TODO: Implement validate() method. + return filter_var($this->value, FILTER_VALIDATE_FLOAT) ? TRUE : FALSE; } } diff --git a/core/lib/Drupal/Core/TypedData/Type/Integer.php b/core/lib/Drupal/Core/TypedData/Type/Integer.php index 4303511..43f7886 100644 --- a/core/lib/Drupal/Core/TypedData/Type/Integer.php +++ b/core/lib/Drupal/Core/TypedData/Type/Integer.php @@ -35,6 +35,6 @@ public function setValue($value) { * Implements TypedDataInterface::validate(). */ public function validate() { - // TODO: Implement validate() method. + return filter_var($this->value, FILTER_VALIDATE_INT) ? TRUE : FALSE; } } diff --git a/core/lib/Drupal/Core/TypedData/Type/String.php b/core/lib/Drupal/Core/TypedData/Type/String.php index 9248239..ed1d5a3 100644 --- a/core/lib/Drupal/Core/TypedData/Type/String.php +++ b/core/lib/Drupal/Core/TypedData/Type/String.php @@ -35,6 +35,6 @@ public function setValue($value) { * Implements TypedDataInterface::validate(). */ public function validate() { - // TODO: Implement validate() method. + return is_string($this->value); } } diff --git a/core/lib/Drupal/Core/TypedData/Type/Uri.php b/core/lib/Drupal/Core/TypedData/Type/Uri.php index 52b9c3f..ee3dc9f 100644 --- a/core/lib/Drupal/Core/TypedData/Type/Uri.php +++ b/core/lib/Drupal/Core/TypedData/Type/Uri.php @@ -34,6 +34,6 @@ public function setValue($value) { * Implements TypedDataInterface::validate(). */ public function validate() { - // TODO: Implement validate() method. + return filter_var($this->value, FILTER_VALIDATE_URL) ? TRUE : FALSE; } } diff --git a/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php b/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php new file mode 100644 index 0000000..470b795 --- /dev/null +++ b/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php @@ -0,0 +1,119 @@ + 'Contextual Plugins', + 'description' => 'Tests that contexts are properly set and working within plugins.', + 'group' => 'Plugin API', + ); + } + + /** + * Tests getDefinitions() and getDefinition() with a derivativeDecorator. + */ + function testContext() { + $name = $this->randomName(); + $manager = new MockBlockManager(); + $plugin = $manager->createInstance('user_name'); + // Create a node, add it as context, catch the exception. + $node = new MockNode(array('title' => $name)); + + // Try to get a valid context that has not been set. + try { + $plugin->getContext('user'); + } + catch (PluginException $e) { + $this->assertEqual($e->getMessage(), 'The user context is not yet set.'); + } + + // Try to call a method of the plugin that requires context before it has + // been set. + try { + $plugin->getTitle(); + } + catch (PluginException $e) { + $this->assertEqual($e->getMessage(), 'The user context is not yet set.'); + } + + // Try to get a context that is not valid. + try { + $plugin->getContext('node'); + } + catch (PluginException $e) { + $this->assertEqual($e->getMessage(), 'The node context is not a valid context.'); + } + + // Try to pass the wrong class type as a context. + try { + $plugin->setContext('user', $node); + } + catch (ContextException $e) { + $this->assertEqual($e->getMessage(), 'The context passed was not an instance of Drupal\plugin_test\MockUser.'); + } + + // Set an appropriate context appropriately and check to make sure its + // methods work as expected. + $user = new MockUser(array('name' => $name)); + $plugin->setContext('user', $user); + $this->assertEqual($user->label(), $plugin->getTitle()); + + // Test the getContextDefinitions() method. + $this->assertIdentical($plugin->getContextDefinitions(), array('user' => 'Drupal\plugin_test\MockUser')); + + // Test the getContextDefinition() method for a valid context. + $this->assertEqual($plugin->getContextDefinition('user'), 'Drupal\plugin_test\MockUser'); + + // Test the getContextDefinition() method for an invalid context. + try { + $plugin->getContextDefinition('node'); + } + catch (PluginException $e) { + $this->assertEqual($e->getMessage(), 'The node context is not a valid context.'); + } + + // Test TypedData Context Plugins + $typed_data_plugin = $manager->createInstance('string_context'); + + // Try to get a valid context that has not been set. + try { + $typed_data_plugin->getContext('string'); + } + catch (PluginException $e) { + $this->assertEqual($e->getMessage(), 'The string context is not yet set.'); + } + + // Try to call a method of the plugin that requires context before it has + // been set. + try { + $typed_data_plugin->getTitle(); + } + catch (PluginException $e) { + $this->assertEqual($e->getMessage(), 'The string context is not yet set.'); + } + + // Set the context appropriately. + $typed_data_plugin->setContext('string', $name); + $this->assertEqual($name, $typed_data_plugin->getTitle()); + } +} diff --git a/core/modules/system/lib/Drupal/system/Tests/Plugin/PluginTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Plugin/PluginTestBase.php index 5db9322..892d30c0 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Plugin/PluginTestBase.php +++ b/core/modules/system/lib/Drupal/system/Tests/Plugin/PluginTestBase.php @@ -70,6 +70,20 @@ public function setUp() { 'label' => 'Layout Foo', 'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockLayoutBlock', ), + 'user_name' => array( + 'label' => 'User Name', + 'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockUserNameBlock', + 'context' => array( + 'user' => 'Drupal\plugin_test\MockUser' + ), + ), + 'string_context' => array( + 'label' => 'String Typed Data', + 'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\TypedDataStringBlock', + 'context' => array( + 'string' => array('type' => 'string'), + ), + ) ); $this->defaultsTestPluginExpectedDefinitions = array( 'test_block1' => array( diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/MockEntity.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/MockEntity.php new file mode 100644 index 0000000..941330d --- /dev/null +++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/MockEntity.php @@ -0,0 +1,26 @@ +title; + } +} diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/MockNode.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/MockNode.php new file mode 100644 index 0000000..fba6a65 --- /dev/null +++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/MockNode.php @@ -0,0 +1,18 @@ +title = isset($values['title']) ? $values['title'] : ''; + } +} diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/MockUser.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/MockUser.php new file mode 100644 index 0000000..374ec95 --- /dev/null +++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/MockUser.php @@ -0,0 +1,18 @@ +title = isset($values['name']) ? $values['name'] : ''; + } +} diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php index fcf1824..793c012 100644 --- a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php +++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php @@ -66,6 +66,25 @@ public function __construct() { 'derivative' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockLayoutBlockDeriver', )); + // A block plugin that requires context to function. This block requires a + // user object in order to return the user name from the getTitle() method. + $this->discovery->setDefinition('user_name', array( + 'label' => t('User Name'), + 'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockUserNameBlock', + 'context' => array( + 'user' => 'Drupal\plugin_test\MockUser' + ), + )); + + // 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'), + ), + )); + // In addition to finding all of the plugins available for a type, a plugin // type must also be able to create instances of that plugin. For example, a // specific instance of a "Main menu" menu block, configured to show just diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockUserNameBlock.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockUserNameBlock.php new file mode 100644 index 0000000..86b4365 --- /dev/null +++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockUserNameBlock.php @@ -0,0 +1,24 @@ +getContext('user'); + return $user->label(); + } +} diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/TypedDataStringBlock.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/TypedDataStringBlock.php new file mode 100644 index 0000000..2c62f49 --- /dev/null +++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/TypedDataStringBlock.php @@ -0,0 +1,24 @@ +getContext('string'); + return $context->getValue(); + } +}