You are here

class ContextHandler in Zircon Profile 8

Same name and namespace in other branches
  1. 8.0 core/lib/Drupal/Core/Plugin/Context/ContextHandler.php \Drupal\Core\Plugin\Context\ContextHandler

Provides methods to handle sets of contexts.

Hierarchy

Expanded class hierarchy of ContextHandler

1 file declares its use of ContextHandler
ContextHandlerTest.php in core/tests/Drupal/Tests/Core/Plugin/ContextHandlerTest.php
Contains \Drupal\Tests\Core\Plugin\ContextHandlerTest.
1 string reference to 'ContextHandler'
core.services.yml in core/core.services.yml
core/core.services.yml
1 service uses ContextHandler
context.handler in core/core.services.yml
Drupal\Core\Plugin\Context\ContextHandler

File

core/lib/Drupal/Core/Plugin/Context/ContextHandler.php, line 17
Contains \Drupal\Core\Plugin\Context\ContextHandler.

Namespace

Drupal\Core\Plugin\Context
View source
class ContextHandler implements ContextHandlerInterface {

  /**
   * {@inheritdoc}
   */
  public function filterPluginDefinitionsByContexts(array $contexts, array $definitions) {
    return array_filter($definitions, function ($plugin_definition) use ($contexts) {

      // If this plugin doesn't need any context, it is available to use.
      if (!isset($plugin_definition['context'])) {
        return TRUE;
      }

      // Check the set of contexts against the requirements.
      return $this
        ->checkRequirements($contexts, $plugin_definition['context']);
    });
  }

  /**
   * {@inheritdoc}
   */
  public function checkRequirements(array $contexts, array $requirements) {
    foreach ($requirements as $requirement) {
      if ($requirement
        ->isRequired() && !$this
        ->getMatchingContexts($contexts, $requirement)) {
        return FALSE;
      }
    }
    return TRUE;
  }

  /**
   * {@inheritdoc}
   */
  public function getMatchingContexts(array $contexts, ContextDefinitionInterface $definition) {
    return array_filter($contexts, function (ContextInterface $context) use ($definition) {
      $context_definition = $context
        ->getContextDefinition();

      // If the data types do not match, this context is invalid unless the
      // expected data type is any, which means all data types are supported.
      if ($definition
        ->getDataType() != 'any' && $definition
        ->getDataType() != $context_definition
        ->getDataType()) {
        return FALSE;
      }

      // If any constraint does not match, this context is invalid.
      foreach ($definition
        ->getConstraints() as $constraint_name => $constraint) {
        if ($context_definition
          ->getConstraint($constraint_name) != $constraint) {
          return FALSE;
        }
      }

      // All contexts with matching data type and contexts are valid.
      return TRUE;
    });
  }

  /**
   * {@inheritdoc}
   */
  public function applyContextMapping(ContextAwarePluginInterface $plugin, $contexts, $mappings = array()) {

    /** @var $contexts \Drupal\Core\Plugin\Context\ContextInterface[] */
    $mappings += $plugin
      ->getContextMapping();

    // Loop through each of the expected contexts.
    $missing_value = [];
    foreach ($plugin
      ->getContextDefinitions() as $plugin_context_id => $plugin_context_definition) {

      // If this context was given a specific name, use that.
      $context_id = isset($mappings[$plugin_context_id]) ? $mappings[$plugin_context_id] : $plugin_context_id;
      if (!empty($contexts[$context_id])) {

        // This assignment has been used, remove it.
        unset($mappings[$plugin_context_id]);

        // Plugins have their on context objects, only the value is applied.
        // They also need to know about the cacheability metadata of where that
        // value is coming from, so pass them through to those objects.
        $plugin_context = $plugin
          ->getContext($plugin_context_id);
        if ($plugin_context instanceof ContextInterface && $contexts[$context_id] instanceof CacheableDependencyInterface) {
          $plugin_context
            ->addCacheableDependency($contexts[$context_id]);
        }

        // Pass the value to the plugin if there is one.
        if ($contexts[$context_id]
          ->hasContextValue()) {
          $plugin
            ->setContextValue($plugin_context_id, $contexts[$context_id]
            ->getContextData());
        }
        elseif ($plugin_context_definition
          ->isRequired()) {

          // Collect required contexts that exist but are missing a value.
          $missing_value[] = $plugin_context_id;
        }
      }
      elseif ($plugin_context_definition
        ->isRequired()) {

        // Collect required contexts that are missing.
        $missing_value[] = $plugin_context_id;
      }
      else {

        // Ignore mappings for optional missing context.
        unset($mappings[$plugin_context_id]);
      }
    }

    // If there are any required contexts without a value, throw an exception.
    if ($missing_value) {
      throw new ContextException(sprintf('Required contexts without a value: %s.', implode(', ', $missing_value)));
    }

    // If there are any mappings that were not satisfied, throw an exception.
    if (!empty($mappings)) {
      throw new ContextException('Assigned contexts were not satisfied: ' . implode(',', array_keys($mappings)));
    }
  }

}

Members

Namesort descending Modifiers Type Description Overrides
ContextHandler::applyContextMapping public function Prepares a plugin for evaluation. Overrides ContextHandlerInterface::applyContextMapping
ContextHandler::checkRequirements public function Checks a set of requirements against a set of contexts. Overrides ContextHandlerInterface::checkRequirements
ContextHandler::filterPluginDefinitionsByContexts public function Determines plugins whose constraints are satisfied by a set of contexts. Overrides ContextHandlerInterface::filterPluginDefinitionsByContexts
ContextHandler::getMatchingContexts public function Determines which contexts satisfy the constraints of a given definition. Overrides ContextHandlerInterface::getMatchingContexts