diff --git a/core/lib/Drupal/Component/Plugin/Context/Context.php b/core/lib/Drupal/Component/Plugin/Context/Context.php index f30158333211da1c812d7dac30aeb637af27ae29..04cb7b2ba88d9d294541b05dc823f70293336b9d 100644 --- a/core/lib/Drupal/Component/Plugin/Context/Context.php +++ b/core/lib/Drupal/Component/Plugin/Context/Context.php @@ -54,11 +54,15 @@ public function getContextValue() { // Support optional contexts. if (!isset($this->contextValue)) { $definition = $this->getContextDefinition(); - if ($definition->isRequired()) { + $default_value = $definition->getDefaultValue(); + + if (!isset($default_value) && $definition->isRequired()) { $type = $definition->getDataType(); throw new ContextException(sprintf("The %s context is required and not present.", $type)); } - return NULL; + // Keep the default value here so that subsequent calls don't have to look + // it up again. + $this->contextValue = $default_value; } return $this->contextValue; } diff --git a/core/lib/Drupal/Component/Plugin/Context/ContextDefinitionInterface.php b/core/lib/Drupal/Component/Plugin/Context/ContextDefinitionInterface.php index c7b69a068b38b4c30b8dbe7166ca042e312ad9d6..1b3c1f45e56306d912d34067379ece05f3115de9 100644 --- a/core/lib/Drupal/Component/Plugin/Context/ContextDefinitionInterface.php +++ b/core/lib/Drupal/Component/Plugin/Context/ContextDefinitionInterface.php @@ -109,6 +109,24 @@ public function isRequired(); */ public function setRequired($required = TRUE); + /** + * Provides the default value for this context definition. + * + * @return mixed + * The default value or NULL if no default value is set. + */ + public function getDefaultValue(); + + /** + * Sets the default data value. + * + * @param mixed $default_value + * The default value to be set or NULL to remove any default value. + * + * @return $this + */ + public function setDefaultValue($default_value); + /** * Returns an array of validation constraints. * diff --git a/core/lib/Drupal/Core/Annotation/ContextDefinition.php b/core/lib/Drupal/Core/Annotation/ContextDefinition.php index 987bab95af975752031ecc67bc865b1f31451a2a..e820f0c3655c369dac468324c946ea79a877646b 100644 --- a/core/lib/Drupal/Core/Annotation/ContextDefinition.php +++ b/core/lib/Drupal/Core/Annotation/ContextDefinition.php @@ -50,6 +50,16 @@ * } * @endcode * + * Specifying a default value for the context definition: + * @code + * context = { + * "message" = @ContextDefinition("string", + * label = @Translation("Message"), + * default_value = @Translation("Checkout complete! Thank you for your purchase.") + * ) + * } + * @endcode + * * @see annotation * * @} @@ -85,6 +95,8 @@ class ContextDefinition extends Plugin { * - required: (optional) Whether the context definition is required. * - multiple: (optional) Whether the context definition is multivalue. * - description: (optional) The UI description of this context definition. + * - default_value: (optional) The default value in case the underlying + * value is not set. * - class: (optional) A custom ContextDefinitionInterface class. * * @throws \Exception @@ -95,6 +107,7 @@ public function __construct(array $values) { $values += array( 'required' => TRUE, 'multiple' => FALSE, + 'default_value' => NULL, ); // Annotation classes extract data from passed annotation classes directly // used in the classes they pass to. @@ -111,7 +124,7 @@ public function __construct(array $values) { throw new \Exception('ContextDefinition class must implement \Drupal\Core\Plugin\Context\ContextDefinitionInterface.'); } $class = isset($values['class']) ? $values['class'] : 'Drupal\Core\Plugin\Context\ContextDefinition'; - $this->definition = new $class($values['value'], $values['label'], $values['required'], $values['multiple'], $values['description']); + $this->definition = new $class($values['value'], $values['label'], $values['required'], $values['multiple'], $values['description'], $values['default_value']); } /** diff --git a/core/lib/Drupal/Core/Plugin/Context/Context.php b/core/lib/Drupal/Core/Plugin/Context/Context.php index fb06a1ec485a7a45f4777d26d6e9a3e5366c2617..9835dd7a6be4b1c526a0f471e421782ac1660bf8 100644 --- a/core/lib/Drupal/Core/Plugin/Context/Context.php +++ b/core/lib/Drupal/Core/Plugin/Context/Context.php @@ -40,11 +40,18 @@ class Context extends ComponentContext implements ContextInterface { public function getContextValue() { if (!isset($this->contextData)) { $definition = $this->getContextDefinition(); - if ($definition->isRequired()) { + $default_value = $definition->getDefaultValue(); + + if (isset($default_value)) { + // Keep the default value here so that subsequent calls don't have to + // look it up again. + $this->setContextValue($default_value); + } + elseif ($definition->isRequired()) { $type = $definition->getDataType(); throw new ContextException(SafeMarkup::format("The @type context is required and not present.", array('@type' => $type))); } - return NULL; + return $default_value; } return $this->getTypedDataManager()->getCanonicalRepresentation($this->contextData); } @@ -72,6 +79,15 @@ public function getConstraints() { * {@inheritdoc} */ public function getContextData() { + if (!isset($this->contextData)) { + $definition = $this->getContextDefinition(); + $default_value = $definition->getDefaultValue(); + if (isset($default_value)) { + // Store the default value so that subsequent calls don't have to look + // it up again. + $this->contextData = $this->getTypedDataManager()->create($definition->getDataDefinition(), $default_value); + } + } return $this->contextData; } diff --git a/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php b/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php index b6d16227a837b6c436da7271c11b8158dc2721e7..34ad3621bdde69332518d22b9ec0af589a2dc6ca 100644 --- a/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php +++ b/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php @@ -56,6 +56,13 @@ class ContextDefinition implements ContextDefinitionInterface { */ protected $isRequired = TRUE; + /** + * The default value. + * + * @var mixed + */ + protected $defaultValue; + /** * An array of constraints. * @@ -90,15 +97,18 @@ public static function create($data_type = 'any') { * Whether the context definition is required. * @param bool $multiple * Whether the context definition is multivalue. - * @param mixed string|null $description + * @param string|null $description * The description of this context definition for the UI. + * @param mixed $default_value + * The default value of this definition. */ - public function __construct($data_type = 'any', $label = NULL, $required = TRUE, $multiple = FALSE, $description = NULL) { + public function __construct($data_type = 'any', $label = NULL, $required = TRUE, $multiple = FALSE, $description = NULL, $default_value = NULL) { $this->dataType = $data_type; $this->label = $label; $this->isRequired = $required; $this->isMultiple = $multiple; $this->description = $description; + $this->defaultValue = $default_value; } /** @@ -176,6 +186,21 @@ public function setRequired($required = TRUE) { return $this; } + /** + * {@inheritdoc} + */ + public function getDefaultValue() { + return $this->defaultValue; + } + + /** + * {@inheritdoc} + */ + public function setDefaultValue($default_value) { + $this->defaultValue = $default_value; + return $this; + } + /** * {@inheritdoc} */ diff --git a/core/tests/Drupal/Tests/Component/Plugin/Context/ContextTest.php b/core/tests/Drupal/Tests/Component/Plugin/Context/ContextTest.php index 77c78a771e503035e0e635fab022350ee3e2a006..c453b6bd6f2993e23ae6de1f58e1cc3917b8318f 100644 --- a/core/tests/Drupal/Tests/Component/Plugin/Context/ContextTest.php +++ b/core/tests/Drupal/Tests/Component/Plugin/Context/ContextTest.php @@ -7,6 +7,7 @@ namespace Drupal\Tests\Component\Plugin\Context; +use Drupal\Component\Plugin\Context\Context; use Drupal\Tests\UnitTestCase; /** @@ -86,4 +87,20 @@ public function testGetContextValue($expected, $context_value, $is_required, $da } } + /** + * @covers ::getContextValue + */ + public function testDefaultValue() { + $mock_definition = $this->getMockBuilder('Drupal\Component\Plugin\Context\ContextDefinitionInterface') + ->setMethods(array('getDefaultValue')) + ->getMockForAbstractClass(); + + $mock_definition->expects($this->once()) + ->method('getDefaultValue') + ->willReturn('test'); + + $context = new Context($mock_definition); + $this->assertEquals('test', $context->getContextValue()); + } + } diff --git a/core/tests/Drupal/Tests/Core/Plugin/Context/ContextDefinitionTest.php b/core/tests/Drupal/Tests/Core/Plugin/Context/ContextDefinitionTest.php index 57db699c18426299a156bfab45402339666e6e12..1a871bb8489a00f53c21bd67b53905d2f18cfeaf 100644 --- a/core/tests/Drupal/Tests/Core/Plugin/Context/ContextDefinitionTest.php +++ b/core/tests/Drupal/Tests/Core/Plugin/Context/ContextDefinitionTest.php @@ -7,6 +7,7 @@ namespace Drupal\Tests\Core\Plugin\Context; +use Drupal\Core\Plugin\Context\ContextDefinition; use Drupal\Tests\UnitTestCase; /** @@ -205,4 +206,15 @@ public function testGetConstraint($expected, $constraint_array, $constraint) { $this->assertEquals($expected, $mock_context_definition->getConstraint($constraint)); } + /** + * @covers ::getDefaultValue + * @covers ::setDefaultValue + */ + public function testDefaultValue() { + $context_definition = new ContextDefinition(); + $this->assertNull($context_definition->getDefaultValue()); + $context_definition->setDefaultValue('test'); + $this->assertSame('test', $context_definition->getDefaultValue()); + } + } diff --git a/core/tests/Drupal/Tests/Core/Plugin/Context/ContextTest.php b/core/tests/Drupal/Tests/Core/Plugin/Context/ContextTest.php new file mode 100644 index 0000000000000000000000000000000000000000..97702c7ccd8ab9a55c28a76f017dcf399d8bf393 --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Plugin/Context/ContextTest.php @@ -0,0 +1,91 @@ +<?php + +/** + * @file + * Contains \Drupal\Tests\Core\Plugin\Context\ContextTest. + */ + +namespace Drupal\Tests\Core\Plugin\Context; + +use Drupal\Core\Plugin\Context\Context; +use Drupal\Tests\UnitTestCase; + +/** + * @coversDefaultClass \Drupal\Core\Plugin\Context\Context + * @group Plugin + */ +class ContextTest extends UnitTestCase { + + /** + * The mocked context definition object. + * + * @var \Drupal\Core\Plugin\Context\ContextDefinitionInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $contextDefinition; + + /** + * The mocked Typed Data manager. + * + * @var \Drupal\Core\TypedData\TypedDataManager|\PHPUnit_Framework_MockObject_MockObject + */ + protected $typedDataManager; + + /** + * The mocked Typed Data object. + * + * @var \Drupal\Core\TypedData\TypedDataInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $typedData; + + /** + * {@inheritdoc} + */ + public function setUp() { + parent::setUp(); + + $mock_data_definition = $this->getMock('Drupal\Core\TypedData\DataDefinitionInterface'); + + $this->contextDefinition = $this->getMockBuilder('Drupal\Core\Plugin\Context\ContextDefinitionInterface') + ->setMethods(array('getDefaultValue', 'getDataDefinition')) + ->getMockForAbstractClass(); + + $this->contextDefinition->expects($this->once()) + ->method('getDefaultValue') + ->willReturn('test'); + + $this->contextDefinition->expects($this->once()) + ->method('getDataDefinition') + ->willReturn($mock_data_definition); + + $this->typedData = $this->getMock('Drupal\Core\TypedData\TypedDataInterface'); + + $this->typedDataManager = $this->getMockBuilder('Drupal\Core\TypedData\TypedDataManager') + ->disableOriginalConstructor() + ->setMethods(array('create')) + ->getMock(); + + $this->typedDataManager->expects($this->once()) + ->method('create') + ->with($mock_data_definition, 'test') + ->willReturn($this->typedData); + } + + /** + * @covers ::getContextValue + */ + public function testDefaultValue() { + $context = new Context($this->contextDefinition); + $context->setTypedDataManager($this->typedDataManager); + $this->assertEquals('test', $context->getContextValue()); + } + + /** + * @covers ::getContextData + */ + public function testDefaultDataValue() { + $context = new Context($this->contextDefinition); + $context->setTypedDataManager($this->typedDataManager); + $this->assertEquals($this->typedData, $context->getContextData()); + } + +}