Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/context #27

Merged
merged 6 commits into from May 29, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
107 changes: 107 additions & 0 deletions src/Context/Context.php
@@ -0,0 +1,107 @@
<?php

/**
* @file
* Contains \Drupal\rules\Context\Context.
*/

namespace Drupal\rules\Context;

use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\TypedData\TypedDataInterface;

/**
* A context class for Rules.
*/
class Context implements ContextInterface {

/**
* The data associated with the context.
*
* @var \Drupal\Core\TypedData\TypedDataInterface
*/
protected $contextData;

/**
* The definition to which a context must conform.
*
* @var \Drupal\rules\Context\ContextDefinitionInterface
*/
protected $contextDefinition;

/**
* Sets the contextDefinition for us without needing to call the setter.
*/
public function __construct(ContextDefinitionInterface $context_definition) {
$this->contextDefinition = $context_definition;
}

/**
* {@inheritdoc}
*/
public function getContextValue() {
// Special case entities.
// @todo: Remove once entities do not implemented TypedDataInterface any
// more.
if ($this->contextData instanceof ContentEntityInterface) {
return $this->contextData;
}
return $this->contextData->getValue();
}

/**
* {@inheritdoc}
*/
public function setContextValue($value) {
if ($value instanceof TypedDataInterface) {
return $this->setContextData($value);
}
else {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need for else here.

return $this->setContextData(\Drupal::typedDataManager()->create($this->contextDefinition->getDataDefinition(), $value));
}
}

/**
* {@inheritdoc}
*/
public function getContextData() {
return $this->getContextData;
}

/**
* {@inheritdoc}
*/
public function setContextData(TypedDataInterface $data) {
$this->contextData = $data;
return $this;
}

/**
* {@inheritdoc}
*/
public function getContextDefinition() {
return $this->contextDefinition;
}

/**
* {@inheritdoc}
*/
public function setContextDefinition(array $context_definition) {
$this->contextDefinition = $context_definition;
}

/**
* {@inheritdoc}
*/
public function getConstraints() {
return $this->contextDefinition->getConstraints();
}

/**
* {@inheritdoc}
*/
public function validate() {
return $this->getContextData()->validate();
}

}
128 changes: 128 additions & 0 deletions src/Context/ContextAwarePluginBase.php
@@ -0,0 +1,128 @@
<?php

/**
* @file
* Contains \Drupal\rules\Context\ContextAwarePluginBase.
*/

namespace Drupal\rules\Context;

use Drupal\Component\Plugin\Exception\ContextException;
use Drupal\Component\Plugin\PluginBase;
use Symfony\Component\Validator\ConstraintViolationList;

/**
* Base class for plugins that are context aware.
*/
abstract class ContextAwarePluginBase extends PluginBase implements ContextAwarePluginInterface {

/**
* The contexts of this plugin.
*
* @var \Drupal\rules\Context\ContextInterface[]
*/
protected $contexts;

/**
* The context definitions of this plugin.
*
* @var \Drupal\rules\Context\ContextDefinitionInterface[]
*/
protected $contextDefinitions;

/**
* Defines the needed context of this plugin.
*
* @todo: Can we make this abstract somehow?
*
* @return \Drupal\rules\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();
}
return $this->contextDefinitions;
}

/**
* {@inheritdoc}
*/
public function getContextDefinition($name) {
$definitions = $this->getContextDefinitions();
if (empty($definitions[$name])) {
throw new ContextException("The $name context is not a valid context.");
}
return $definitions[$name];
}

/**
* {@inheritdoc}
*/
public function getContexts() {
// Make sure all context objects are initialized.
foreach ($this->getContextDefinitions() as $name => $definition) {
$this->getContext($name);
}
return $this->contexts;
}

/**
* {@inheritdoc}
*/
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 getContextValues() {
$values = array();
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->getContext($name)->setContextValue($value);
return $this;
}

/**
* {@inheritdoc}
*/
public function validateContexts() {
$violations = new ConstraintViolationList();
// @todo: Implement symfony validator API to let the validator traverse
// and set property paths accordingly.

foreach ($this->getContexts() as $name => $context) {
$violations->addAll($context->validate());
}
return $violations;
}

}
70 changes: 70 additions & 0 deletions src/Context/ContextAwarePluginInterface.php
@@ -0,0 +1,70 @@
<?php

/**
* @file
* Contains \Drupal\rules\Context\ContextAwarePluginInterface.
*/

namespace Drupal\rules\Context;

use \Drupal\Component\Plugin\ContextAwarePluginInterface as CoreContextAwarePluginInterface;

/**
* Interface for Rules-context aware plugins.
*/
interface ContextAwarePluginInterface extends CoreContextAwarePluginInterface {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure I understand why most of the functions that already declared in CoreContextAwarePluginInterface are redeclared here, but I guess it's because you need to return different types than the parent interface. I don't think that's a safe idea: that would make the two interfaces not swappable and basically makes them hidden-ly incompatible.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the goal would be to get our interface in core. For now, that's what we can do easily.


/**
* Gets the context definitions of the plugin.
*
* @return \Drupal\rules\Context\ContextDefinitionInterface[]
* The array of context definitions, keyed by context name.
*/
public function getContextDefinitions();

/**
* Gets a specific context definition of the plugin.
*
* @param string $name
* The name of the context in the plugin definition.
*
* @throws \Drupal\Component\Plugin\Exception\ContextException
* If the requested context is not defined.
*
* @return \Drupal\rules\Context\ContextDefinitionInterface
* The definition against which the context value must validate.
*/
public function getContextDefinition($name);

/**
* Gets the defined contexts.
*
* @return \Drupal\rules\Context\ContextInterface[]
* The set context objects.
*/
public function getContexts();

/**
* Gets a defined context.
*
* @param string $name
* The name of the context in the plugin configuration.
*
* @throws \Drupal\Component\Plugin\Exception\ContextException
* If the requested context is not defined.
*
* @return \Drupal\rules\Context\ContextInterface
* The context object.
*/
public function getContext($name);

/**
* 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 validateContexts();

}