You are here

public function ContextHandler::applyContextMapping in Drupal 8

Same name and namespace in other branches
  1. 9 core/lib/Drupal/Core/Plugin/Context/ContextHandler.php \Drupal\Core\Plugin\Context\ContextHandler::applyContextMapping()

Prepares a plugin for evaluation.

Parameters

\Drupal\Core\Plugin\ContextAwarePluginInterface $plugin: A plugin about to be evaluated.

\Drupal\Core\Plugin\Context\ContextInterface[] $contexts: An array of contexts to set on the plugin. They will only be set if they match the plugin's context definitions.

array $mappings: (optional) A mapping of the expected assignment names to their context names. For example, if one of the $contexts is named 'current_user', but the plugin expects a context named 'user', then this map would contain 'user' => 'current_user'.

Throws

\Drupal\Component\Plugin\Exception\ContextException Thrown when a context assignment was not satisfied.

\Drupal\Component\Plugin\Exception\MissingValueContextException Thrown when a context is provided but has no value. Only thrown if no contexts are missing.

Overrides ContextHandlerInterface::applyContextMapping

File

core/lib/Drupal/Core/Plugin/Context/ContextHandler.php, line 84

Class

ContextHandler
Provides methods to handle sets of contexts.

Namespace

Drupal\Core\Plugin\Context

Code

public function applyContextMapping(ContextAwarePluginInterface $plugin, $contexts, $mappings = []) {

  /** @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
          ->setContext($plugin_context_id, $contexts[$context_id]);
      }
      elseif ($plugin_context_definition
        ->isRequired()) {

        // Collect required contexts that exist but are missing a value.
        $missing_value[] = $plugin_context_id;
      }

      // Proceed to the next definition.
      continue;
    }
    try {
      $context = $plugin
        ->getContext($context_id);
    } catch (ContextException $e) {
      $context = NULL;
    } catch (PluginException $e) {
      $context = NULL;
    }
    if ($context && $context
      ->hasContextValue()) {

      // Ignore mappings if the plugin has a value for a missing context.
      unset($mappings[$plugin_context_id]);
      continue;
    }
    if ($plugin_context_definition
      ->isRequired()) {

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

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

  // If there are any mappings that were not satisfied, throw an exception.
  // This is a more severe problem than missing values, so check and throw
  // this first.
  if (!empty($mappings)) {
    throw new ContextException('Assigned contexts were not satisfied: ' . implode(',', array_keys($mappings)));
  }

  // If there are any required contexts without a value, throw an exception.
  if ($missing_value) {
    throw new MissingValueContextException($missing_value);
  }
}