diff --git a/core/lib/Drupal/Component/Plugin/Context/Context.php b/core/lib/Drupal/Component/Plugin/Context/Context.php index 9f4396b..b117a72 100644 --- a/core/lib/Drupal/Component/Plugin/Context/Context.php +++ b/core/lib/Drupal/Component/Plugin/Context/Context.php @@ -8,6 +8,8 @@ namespace Drupal\Component\Plugin\Context; use Drupal\Component\Plugin\Exception\ContextException; +use Symfony\Component\Validator\Constraints\Type; +use Symfony\Component\Validator\Validation; /** * A generic context class for wrapping data a plugin needs to operate. @@ -39,7 +41,6 @@ public function __construct(array $context_definition) { * Implements \Drupal\Component\Plugin\Context\ContextInterface::setContextValue(). */ public function setContextValue($value) { - $value = $this->validate($value); $this->contextValue = $value; } @@ -65,22 +66,22 @@ public function getContextDefinition() { } /** - * Implements \Drupal\Component\Plugin\Context\ContextInterface::validate(). - * - * The default validation method only supports instance of checks between the - * contextDefintion and the contextValue. Other formats of context - * definitions can be supported through a subclass. + * Implements \Drupal\Component\Plugin\Context\ContextInterface::getConstraints(). */ - public function validate($value) { - // Check to make sure we have a class name, and that the passed context is - // an instance of that class name. - if (!empty($this->contextDefinition['class'])) { - if ($value instanceof $this->contextDefinition['class']) { - return $value; - } - throw new ContextException("The context passed was not an instance of {$this->contextDefinition['class']}."); + public function getConstraints() { + if (empty($this->contextDefinition['class'])) { + throw new ContextException("An error was encountered while trying to validate the context."); } - throw new ContextException("An error was encountered while trying to validate the context."); + return array(new Type($this->contextDefinition['class'])); + } + + /** + * Implements \Drupal\Component\Plugin\Context\ContextInterface::validate(). + */ + public function validate() { + $validator = Validation::createValidatorBuilder() + ->getValidator(); + return $validator->validateValue($this->getContextValue(), $this->getConstraints()); } } diff --git a/core/lib/Drupal/Component/Plugin/Context/ContextInterface.php b/core/lib/Drupal/Component/Plugin/Context/ContextInterface.php index 5c4373d..c5cd743 100644 --- a/core/lib/Drupal/Component/Plugin/Context/ContextInterface.php +++ b/core/lib/Drupal/Component/Plugin/Context/ContextInterface.php @@ -7,8 +7,6 @@ namespace Drupal\Component\Plugin\Context; -use Drupal\Component\Plugin\Exception\ContextException; - /** * A generic context interface for wrapping data a plugin needs to operate. */ @@ -18,8 +16,9 @@ * Sets the context value. * * @param mixed $value - * The value of this context, generally an object based upon the class - * matching the definition passed to setContextDefinition(). + * The value of this context, matching the context definition. + * + * @see \Drupal\Component\Plugin\Context\ContextInterface::setContextDefinition(). */ public function setContextValue($value); @@ -27,42 +26,45 @@ public function setContextValue($value); * Gets the context value. * * @return mixed - * The currently set context value within this class. + * The currently set context value, or NULL if it is not set. */ public function getContextValue(); /** * Sets the definition that the context must conform to. * - * @param mixed $contextDefinition + * @param array $contextDefinition * A defining characteristic representation of the context against which - * that context can be validated. This is typically a class name, but could - * be extended to support other validation notation. + * that context can be validated. This is typically an array having a + * class name set under the 'class' key, but it could be extended to support + * other notations. */ public function setContextDefinition(array $contextDefinition); /** * Gets the provided definition that the context must conform to. * - * @return mixed + * @return array * The defining characteristic representation of the context. */ public function getContextDefinition(); /** - * Validate the provided context value against the provided definition. - * - * @param mixed $value - * The context value that should be validated against the context - * definition. + * Gets a list of validation constraints. * - * @return mixed - * Returns the context value passed to it. If it fails validation, an - * exception will be thrown. + * @return array + * Array of constraints, each being an instance of + * \Symfony\Component\Validator\Constraint. + */ + public function getConstraints(); + + /** + * Validates the set context value. * - * @throws \Drupal\Component\Plugin\Exception\ContextException - * If validation fails. + * @return \Symfony\Component\Validator\ConstraintViolationListInterface + * A list of constraint violations. If the list is empty, validation + * succeeded. */ - public function validate($value); + public function validate(); } diff --git a/core/lib/Drupal/Component/Plugin/ContextAwarePluginBase.php b/core/lib/Drupal/Component/Plugin/ContextAwarePluginBase.php index a628f99..2b97103 100644 --- a/core/lib/Drupal/Component/Plugin/ContextAwarePluginBase.php +++ b/core/lib/Drupal/Component/Plugin/ContextAwarePluginBase.php @@ -9,6 +9,7 @@ use Drupal\Component\Plugin\Exception\PluginException; use Drupal\Component\Plugin\Context\Context; +use Symfony\Component\Validator\ConstraintViolationList; /** * Base class for plugins that are context aware. @@ -27,18 +28,18 @@ */ public function getContextDefinitions() { $definition = $this->getDefinition(); - return !empty($definition['context']) ? $definition['context'] : NULL; + return !empty($definition['context']) ? $definition['context'] : array(); } /** * Implements \Drupal\Component\Plugin\ContextAwarePluginInterface::getContextDefinition(). */ - public function getContextDefinition($key) { + public function getContextDefinition($name) { $definition = $this->getDefinition(); - if (empty($definition['context'][$key])) { - throw new PluginException("The $key context is not a valid context."); + if (empty($definition['context'][$name])) { + throw new PluginException("The $name context is not a valid context."); } - return $definition['context'][$key]; + return $definition['context'][$name]; } /** @@ -46,19 +47,15 @@ public function getContextDefinition($key) { */ public function getContexts() { $definitions = $this->getContextDefinitions(); - // If there are no contexts defined by the plugin, return an empty array. - if (empty($definitions)) { - return array(); - } - if (empty($this->context)) { + if ($definitions && empty($this->context)) { throw new PluginException("There are no set contexts."); } $contexts = array(); - foreach (array_keys($definitions) as $key) { - if (empty($this->context[$key])) { - throw new PluginException("The $key context is not yet set."); + foreach (array_keys($definitions) as $name) { + if (empty($this->context[$name])) { + throw new PluginException("The $name context is not yet set."); } - $contexts[$key] = $this->context[$key]; + $contexts[$name] = $this->context[$name]; } return $contexts; } @@ -66,44 +63,67 @@ public function getContexts() { /** * Implements \Drupal\Component\Plugin\ContextAwarePluginInterface::getContext(). */ - public function getContext($key) { + public function getContext($name) { // Check for a valid context definition. - $this->getContextDefinition($key); + $this->getContextDefinition($name); // Check for a valid context value. - if (empty($this->context[$key])) { - throw new PluginException("The $key context is not yet set."); + if (!isset($this->context[$name])) { + throw new PluginException("The $name context is not yet set."); } - return $this->context[$key]; + return $this->context[$name]; } /** * Implements \Drupal\Component\Plugin\ContextAwarePluginInterface::getContextValues(). */ public function getContextValues() { - $contexts = array(); - foreach ($this->getContexts() as $key => $context) { - $contexts[$key] = $context->getContextValue(); + $values = array(); + foreach ($this->getContextDefinitions() as $name => $definition) { + $values[$name] = isset($this->context[$name]) ? $this->context[$name]->getContextValue() : NULL; } - return $contexts; + return $values; } /** * Implements \Drupal\Component\Plugin\ContextAwarePluginInterface::getContextValue(). */ - public function getContextValue($key) { - return $this->getContext($key)->getContextValue(); + public function getContextValue($name) { + return $this->getContext($name)->getContextValue(); } /** * Implements \Drupal\Component\Plugin\ContextAwarePluginInterface::setContextValue(). */ - public function setContextValue($key, $value) { - $context_definition = $this->getContextDefinition($key); - $this->context[$key] = new Context($context_definition); - $this->context[$key]->setContextValue($value); + public function setContextValue($name, $value) { + $context_definition = $this->getContextDefinition($name); + $this->context[$name] = new Context($context_definition); + $this->context[$name]->setContextValue($value); + // Verify the provided value validates. + $violations = $this->context[$name]->validate(); + if (count($violations) > 0) { + throw new PluginException("The provided context value does not pass validation."); + } return $this; } + /** + * Implements \Drupal\Core\Executable\ExecutableInterface::valdidate(). + */ + public function validate() { + $violations = new ConstraintViolationList(); + // @todo: Implement symfony validator API to let the validator traverse + // and set property paths accordingly. + + foreach ($this->getContextDefinitions() as $name => $definition) { + // Validate any set values. + if (isset($this->context[$name])) { + $violations->addAll($this->context[$name]->validate()); + } + // @todo: If no value is set, make sure any mapping is validated. + } + return $violations; + } + } diff --git a/core/lib/Drupal/Component/Plugin/ContextAwarePluginInterface.php b/core/lib/Drupal/Component/Plugin/ContextAwarePluginInterface.php index 68d8012..01c0968 100644 --- a/core/lib/Drupal/Component/Plugin/ContextAwarePluginInterface.php +++ b/core/lib/Drupal/Component/Plugin/ContextAwarePluginInterface.php @@ -8,35 +8,43 @@ namespace Drupal\Component\Plugin; use Drupal\Component\Plugin\Exception\PluginException; -use Drupal\Component\Plugin\Context\Context; /** * Interface for defining context aware plugins. + * + * Context aware plugins can specify an array of context definitions keyed by + * context name at the plugin definition under the "context" key. */ interface ContextAwarePluginInterface extends PluginInspectionInterface { /** * Gets the context definitions of the plugin. * - * @return array|null - * The context definitions if set, otherwise NULL. + * @return array + * The array of context definitions, keyed by context name. */ public function getContextDefinitions(); /** - * Gets the a specific context definition of the plugin. + * Gets a specific context definition of the plugin. * - * @param string $key + * @param string $name * The name of the context in the plugin definition. * - * @return mixed + * @throws \Drupal\Component\Plugin\Exception\PluginException + * If the requested context ist not defined. + * + * @return array * The definition against which the context value must validate. */ - public function getContextDefinition($key); + public function getContextDefinition($name); /** * Gets the defined contexts. * + * @throws \Drupal\Component\Plugin\Exception\PluginException + * If contexts are defined but not set. + * * @return array * The set context objects. */ @@ -45,47 +53,64 @@ public function getContexts(); /** * Gets a defined context. * - * @param string $key - * The name of the context in the plugin configuration. This string is - * usually identical to the representative string in the plugin definition. + * @param string $name + * The name of the context in the plugin definition. + * + * @throws \Drupal\Component\Plugin\Exception\PluginException + * If the requested context is not set. * * @return \Drupal\Component\Plugin\Context\ContextInterface * The context object. */ - public function getContext($key); + public function getContext($name); /** * Gets the values for all defined contexts. * * @return array - * The set context object values. + * An array of set context values, keyed by context name. If a context is + * unset its value is returned as NULL. */ public function getContextValues(); /** * Gets the value for a defined context. * - * @param string $key - * The name of the context in the plugin configuration. This string is - * usually identical to the representative string in the plugin definition. + * @param string $name + * The name of the context in the plugin configuration. + * + * @throws \Drupal\Component\Plugin\Exception\PluginException + * If the requested context is not set. * * @return mixed * The currently set context value. */ - public function getContextValue($key); + public function getContextValue($name); /** * Sets the value for a defined context. * - * @param string $key + * @param string $name * The name of the context in the plugin definition. * @param mixed $value - * The variable to set the context to. This should validate against the + * The value to set the context to. The value has to validate against the * provided context definition. * + * @throws \Drupal\Component\Plugin\Exception\PluginException + * If the value does not pass validation. + * * @return \Drupal\Component\Plugin\ContextAwarePluginInterface. * A context aware plugin object for chaining. */ - public function setContextValue($key, $value); + public function setContextValue($name, $value); + + /** + * Validates the set values for the defined contexts. + * + * @return \Symfony\Component\Validator\ConstraintViolationListInterface + * A list of constraint violations. If the list is empty, validation + * succeeded. + */ + public function validate(); } diff --git a/core/lib/Drupal/Core/Condition/ConditionInterface.php b/core/lib/Drupal/Core/Condition/ConditionInterface.php new file mode 100644 index 0000000..00538ba --- /dev/null +++ b/core/lib/Drupal/Core/Condition/ConditionInterface.php @@ -0,0 +1,35 @@ +discovery = new AnnotatedClassDiscovery('Core', 'Condition'); + $this->discovery = new DerivativeDiscoveryDecorator($this->discovery); + $this->discovery = new AlterDecorator($this->discovery, 'condition_info'); + $this->discovery = new CacheDecorator($this->discovery, 'condition:' . language(LANGUAGE_TYPE_INTERFACE)->langcode); + + $this->factory = new DefaultFactory($this); + } + + /** + * Override of Drupal\Component\Plugin\PluginManagerBase::createInstance(). + */ + public function createInstance($plugin_id, array $configuration = array()) { + $plugin = $this->factory->createInstance($plugin_id, $configuration); + return $plugin->setExecutableManager($this); + } + + /** + * Implements Drupal\Core\Executable\ExecutableManagerInterface::execute(). + */ + public function execute(ExecutableInterface $condition) { + $result = $condition->evaluate(); + return $condition->isNegated() ? !$result : $result; + } + +} diff --git a/core/lib/Drupal/Core/Condition/ConditionPluginBase.php b/core/lib/Drupal/Core/Condition/ConditionPluginBase.php new file mode 100644 index 0000000..2bd7910 --- /dev/null +++ b/core/lib/Drupal/Core/Condition/ConditionPluginBase.php @@ -0,0 +1,63 @@ +getDefinition(); + return implode('_', array($definition['module'], $definition['id'], 'condition')); + } + + /** + * Implements \Drupal\condition\Plugin\ConditionInterface::isNegated(). + */ + public function isNegated() { + return !empty($this->configuration['negate']); + } + + /** + * Implements \Drupal\Core\Form\FormInterface::buildForm(). + */ + public function buildForm(array $form, array &$form_state) { + $form['negate'] = array( + '#type' => 'checkbox', + '#title' => t('Negate the condition.'), + '#default_value' => isset($this->configuration['negate']) ? $this->configuration['negate'] : FALSE, + ); + return $form; + } + + /** + * Implements \Drupal\Core\Form\FormInterface::validateForm(). + */ + public function validateForm(array &$form, array &$form_state) {} + + /** + * Implements \Drupal\Core\Form\FormInterface::submitForm(). + */ + public function submitForm(array &$form, array &$form_state) { + $this->configuration['negate'] = $form_state['values']['negate']; + } + + /** + * Implements \Drupal\Core\Executable\ExecutablePluginBase::execute(). + */ + public function execute() { + return $this->executableManager->execute($this); + } + +} diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php index 035f282..a91106b 100644 --- a/core/lib/Drupal/Core/CoreBundle.php +++ b/core/lib/Drupal/Core/CoreBundle.php @@ -270,6 +270,8 @@ public function build(ContainerBuilder $container) { $container->register('flood', 'Drupal\Core\Flood\DatabaseBackend') ->addArgument(new Reference('database')); + $container->register('plugin.manager.condition', 'Drupal\Core\Condition\ConditionManager'); + $container->addCompilerPass(new RegisterMatchersPass()); $container->addCompilerPass(new RegisterRouteFiltersPass()); // Add a compiler pass for registering event subscribers. diff --git a/core/lib/Drupal/Core/Executable/ExecutableException.php b/core/lib/Drupal/Core/Executable/ExecutableException.php new file mode 100644 index 0000000..1f105c4 --- /dev/null +++ b/core/lib/Drupal/Core/Executable/ExecutableException.php @@ -0,0 +1,16 @@ + $value) { + $context_definition = $this->getContextDefinition($key); + $this->context[$key] = new Context($context_definition); + $this->context[$key]->setContextValue($value); + } + } + + /** + * Implements \Drupal\Core\Executable\ExecutableInterace::setExecutableManager(). + */ + public function setExecutableManager(ExecutableManagerInterface $executableManager) { + $this->executableManager = $executableManager; + return $this; + } + + /** + * Gets an array of definitions of available configuration options. + * + * @todo: This needs to go into an interface. + * + * @return array + * An array of typed data definitions describing available configuration + * options, keyed by option name. + */ + public function getConfigDefinitions() { + $definition = $this->getDefinition(); + if (!empty($definition['configuration'])) { + return $definition['configuration']; + } + return array(); + } + + /** + * Gets the definition of a configuration option. + * + * @todo: This needs to go into an interface. + * + * @return array + * The typed data definition describing the configuration option, or FALSE + * if the option does not exist. + */ + public function getConfigDefinition($key) { + $definition = $this->getDefinition(); + if (!empty($definition['configuration'][$key])) { + return $definition['configuration'][$key]; + } + return FALSE; + } + + /** + * Gets all configuration values. + * + * @todo: This needs to go into an interface. + * + * @see \Drupal\Component\Plugin\PluginBase::$configuration + * + * @return array + * The array of all configuration values, keyed by configuration option + * name. + */ + public function getConfig() { + return $this->configuration; + } + + /** + * Sets the value of a particular configuration option. + * + * @param string $name + * The name of the configuration option to set. + * @param mixed $value + * The value to set. + * + * @todo This doesn't belong here. Move this into a new base class in + * http://drupal.org/node/1764380. + * @todo This does not set a value in config(), so the name is confusing. + * + * @return \Drupal\Core\Executable\ExecutablePluginBase. + * The executable object for chaining. + */ + public function setConfig($key, $value) { + if ($definition = $this->getConfigDefinition($key)) { + $typed_data = typed_data()->create($definition, $value); + + if ($typed_data->validate()->count() > 0) { + throw new PluginException("The provided configuration value does not pass validation."); + } + } + $this->configuration[$key] = $value; + return $this; + } +} + diff --git a/core/lib/Drupal/Core/Plugin/Context/Context.php b/core/lib/Drupal/Core/Plugin/Context/Context.php index bcab7e1..3eb195d 100644 --- a/core/lib/Drupal/Core/Plugin/Context/Context.php +++ b/core/lib/Drupal/Core/Plugin/Context/Context.php @@ -8,9 +8,11 @@ namespace Drupal\Core\Plugin\Context; use Drupal\Component\Plugin\Context\Context as ComponentContext; -use Drupal\Component\Plugin\Exception\ContextException; -use Drupal\Core\TypedData\TypedDataManager; +use Drupal\Core\TypedData\ComplexDataInterface; +use Drupal\Core\TypedData\ListInterface; use Drupal\Core\TypedData\TypedDataInterface; +use Drupal\Core\Validation\DrupalTranslator; +use Symfony\Component\Validator\Validation; /** * A Drupal specific context wrapper class. @@ -26,18 +28,32 @@ class Context extends ComponentContext { */ public function getContextValue() { $typed_value = parent::getContextValue(); - // If the data is of a primitive type, directly return the plain value. - // That way, e.g. a string will be return as plain PHP string. - if ($typed_value instanceof \Drupal\Core\TypedData\TypedDataInterface) { - $type_definition = typed_data()->getDefinition($typed_value->getType()); - if (!empty($type_definition['primitive type'])) { - return $typed_value->getValue(); - } + // If the typed data is complex, pass it on as typed data. Else pass on its + // plain value, such that e.g. a string will be directly returned as PHP + // string. + $is_complex = $typed_value instanceof ComplexDataInterface; + if (!$is_complex && $typed_value instanceof ListInterface) { + $is_complex = $typed_value[0] instanceof ComplexDataInterface; + } + // @todo We won't need the getType == entity check once #1868004 lands. + if ($typed_value instanceof TypedDataInterface && (!$is_complex || $typed_value->getType() == 'entity')) { + return $typed_value->getValue(); } return $typed_value; } /** + * Implements \Drupal\Component\Plugin\Context\ContextInterface::setContextValue(). + */ + public function setContextValue($value) { + // Make sure the value set is a typed data object. + if (!empty($this->contextDefinition['type']) && !$value instanceof TypedDataInterface) { + $value = typed_data()->create($this->contextDefinition, $value); + } + parent::setContextValue($value); + } + + /** * Gets the context value as typed data object. * * parent::getContextValue() does not do all the processing required to @@ -54,21 +70,31 @@ public function getTypedContext() { } /** - * Override for \Drupal\Component\Plugin\Context\Context::validate(). + * Overrides \Drupal\Component\Plugin\Context\Context::getConstraints(). */ - public function validate($value) { + public function getConstraints() { if (!empty($this->contextDefinition['type'])) { - $typed_data_manager = new TypedDataManager(); - $typed_data = $typed_data_manager->create($this->contextDefinition, $value); - // If we do have a typed data definition, validate it and return the - // typed data instance instead. - $violations = $typed_data->validate(); - if (count($violations) == 0) { - return $typed_data; - } - throw new ContextException("The context passed could not be validated through typed data."); + // If we do have typed data, leverage it for getting constraints. + return $this->getTypedContext()->getConstraints(); } - return parent::validate($value); + return parent::getConstraints(); } + /** + * Overrides \Drupal\Component\Plugin\Context\Context::getConstraints(). + */ + public function validate() { + $validator = Validation::createValidatorBuilder() + ->setTranslator(new DrupalTranslator()) + ->getValidator(); + + // @todo We won't need to special case "entity" here once #1868004 lands. + if (!empty($this->contextDefinition['type']) && $this->contextDefinition['type'] == 'entity') { + $value = $this->getTypedContext(); + } + else { + $value = $this->getContextValue(); + } + return $validator->validateValue($value, $this->getConstraints()); + } } diff --git a/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php b/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php index 028befd..a67a3c8 100644 --- a/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php +++ b/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php @@ -8,6 +8,7 @@ namespace Drupal\Core\Plugin; use Drupal\Component\Plugin\ContextAwarePluginBase as PluginBase; +use Drupal\Component\Plugin\Exception\PluginException; use Drupal\Core\Plugin\Context\Context; /** @@ -22,11 +23,16 @@ /** * Override of \Drupal\Component\Plugin\ContextAwarePluginBase::setContextValue(). */ - public function setContextValue($key, $value) { - $context_definition = $this->getContextDefinition($key); - $this->context[$key] = new Context($context_definition); - $this->context[$key]->setContextValue($value); + public function setContextValue($name, $value) { + $context_definition = $this->getContextDefinition($name); + // Use the Drupal specific context class. + $this->context[$name] = new Context($context_definition); + $this->context[$name]->setContextValue($value); + // Verify the provided value validates. + if ($this->context[$name]->validate()->count() > 0) { + throw new PluginException("The provided context value does not pass validation."); + } return $this; } diff --git a/core/lib/Drupal/Core/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php b/core/lib/Drupal/Core/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php index 21b2ac2..1e1aba4 100644 --- a/core/lib/Drupal/Core/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php +++ b/core/lib/Drupal/Core/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php @@ -22,7 +22,7 @@ public function validate($typed_data, Constraint $constraint) { $entity = isset($typed_data) ? $typed_data->getValue() : FALSE; if (!empty($entity) && $entity->entityType() != $constraint->type) { - $this->context->addViolation($constraint->message, array('%type', $constraint->type)); + $this->context->addViolation($constraint->message, array('%type' => $constraint->type)); } } } diff --git a/core/modules/node/lib/Drupal/node/Plugin/Core/Condition/NodeType.php b/core/modules/node/lib/Drupal/node/Plugin/Core/Condition/NodeType.php new file mode 100644 index 0000000..f6d0b22 --- /dev/null +++ b/core/modules/node/lib/Drupal/node/Plugin/Core/Condition/NodeType.php @@ -0,0 +1,92 @@ +type] = $type->name; + } + $form['bundles'] = array( + '#type' => 'checkboxes', + '#options' => $options, + '#required' => TRUE, + '#default_value' => isset($this->configuration['bundles']) ? $this->configuration['bundles'] : array(), + ); + return $form; + } + + /** + * Implements \Drupal\Core\Form\FormInterface::validateForm(). + */ + public function validateForm(array &$form, array &$form_state) { + foreach ($form_state['values']['bundles'] as $bundle) { + if (!in_array($bundle, array_keys(node_type_get_types()))) { + form_set_error('bundles', t('You have chosen an invalid node bundle, please check your selection and try again.')); + } + } + } + + /** + * Implements \Drupal\Core\Form\FormInterface::submitForm(). + */ + public function submitForm(array &$form, array &$form_state) { + $this->configuration['bundles'] = $form_state['values']['bundles']; + parent::submitForm($form, $form_state); + } + + /** + * Implements \Drupal\Core\Executable\ExecutableInterface::summary(). + */ + public function summary() { + if (count($this->configuration['bundles']) > 1) { + $bundles = $this->configuration['bundles']; + $last = array_pop($bundles); + $bundles = implode(', ', $bundles); + return t('The node bundle is @bundles or @last', array('@bundles' => $bundles, '@last' => $last)); + } + $bundle = $this->configuration['bundles'][0]; + return t('The node bundle is @bundle', array('@bundle' => $bundle)); + } + + /** + * Implements \Drupal\condition\ConditionInterface::evaluate(). + */ + public function evaluate() { + $node = $this->getContextValue('node'); + return in_array($node->type, $this->configuration['bundles']); + } + +} diff --git a/core/modules/node/lib/Drupal/node/Tests/Condition/NodeConditionTest.php b/core/modules/node/lib/Drupal/node/Tests/Condition/NodeConditionTest.php new file mode 100644 index 0000000..addc5c0 --- /dev/null +++ b/core/modules/node/lib/Drupal/node/Tests/Condition/NodeConditionTest.php @@ -0,0 +1,88 @@ + 'Node Condition Plugins', + 'description' => 'Tests that conditions, provided by the node module, are working properly.', + 'group' => 'Condition API', + ); + } + + protected function setUp() { + parent::setUp(); + $this->installSchema('node', 'node_type'); + $this->installSchema('node', 'node'); + $this->installSchema('node', 'node_revision'); + $this->installSchema('field', 'field_config'); + $this->installSchema('field', 'field_config_instance'); + } + + /** + * Tests conditions. + */ + function testConditions() { + $manager = new ConditionManager(); + + // Get some nodes of various types to check against. + $page = entity_create('node', array('type' => 'page', 'title' => $this->randomName())); + $page->save(); + $article = entity_create('node', array('type' => 'article', 'title' => $this->randomName())); + $article->save(); + $test = entity_create('node', array('type' => 'test', 'title' => $this->randomName())); + $test->save(); + + // Grab the node type condition and configure it to check against node type + // of 'article' and set the context to the page type node. + $condition = $manager->createInstance('node_type') + ->setConfig('bundles', array('article')) + ->setContextValue('node', $page); + $this->assertFalse($condition->execute(), 'Page type nodes fail node type checks for articles.'); + // Check for the proper summary. + $this->assertEqual('The node bundle is article', $condition->summary()); + + // Set the node type check to page. + $condition->setConfig('bundles', array('page')); + $this->assertTrue($condition->execute(), 'Page type nodes pass node type checks for pages'); + // Check for the proper summary. + $this->assertEqual('The node bundle is page', $condition->summary()); + + // Set the node type check to page or article. + $condition->setConfig('bundles', array('page', 'article')); + $this->assertTrue($condition->execute(), 'Page type nodes pass node type checks for pages or articles'); + // Check for the proper summary. + $this->assertEqual('The node bundle is page or article', $condition->summary()); + + // Set the context to the article node. + $condition->setContextValue('node', $article); + $this->assertTrue($condition->execute(), 'Article type nodes pass node type checks for pages or articles'); + + // Set the context to the test node. + $condition->setContextValue('node', $test); + $this->assertFalse($condition->execute(), 'Test type nodes pass node type checks for pages or articles'); + + // Check a greater than 2 bundles summary scenario. + $condition->setConfig('bundles', array('page', 'article', 'test')); + $this->assertEqual('The node bundle is page, article or test', $condition->summary()); + + // Test Constructor injection. + $condition = $manager->createInstance('node_type', array('bundles' => array('article'), 'context' => array('node' => $article))); + $this->assertTrue($condition->execute(), 'Constructor injection of context and configuration working as anticipated.'); + } +} diff --git a/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php b/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php index 888f1e6..c22f222 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php @@ -93,8 +93,8 @@ function testContext() { $plugin->setContextValue('user', $node); $this->fail('The node context should fail validation for a user context.'); } - catch (ContextException $e) { - $this->assertEqual($e->getMessage(), 'The context passed was not an instance of Drupal\user\Plugin\Core\Entity\User.'); + catch (PluginException $e) { + $this->assertEqual($e->getMessage(), 'The provided context value does not pass validation.'); } // Set an appropriate context value appropriately and check to make sure @@ -157,13 +157,8 @@ function testContext() { } // With no contexts set, try to get the context values. - try { - $complex_plugin->getContextValues(); - $this->fail('There should not be any contexts set yet.'); - } - catch (PluginException $e) { - $this->assertEqual($e->getMessage(), 'There are no set contexts.'); - } + $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); @@ -178,13 +173,9 @@ function testContext() { } // With only the user context set, try to get the context values. - try { - $complex_plugin->getContextValues(); - $this->fail('The node context should not yet be set.'); - } - catch (PluginException $e) { - $this->assertEqual($e->getMessage(), 'The node context is not yet set.'); - } + $values = $complex_plugin->getContextValues(); + $this->assertNull($values['node'], 'The node context is not yet set.'); + $this->assertNotNull($values['user'], 'The user context is set'); $complex_plugin->setContextValue('node', $node); $context_wrappers = $complex_plugin->getContexts();