c7517a9bdd0e6a68d9a4aa91f8b1380e87a95c79
[yaffs-website] / web / core / lib / Drupal / Core / Plugin / Context / ContextHandler.php
1 <?php
2
3 namespace Drupal\Core\Plugin\Context;
4
5 use Drupal\Component\Plugin\Definition\ContextAwarePluginDefinitionInterface;
6 use Drupal\Component\Plugin\Exception\ContextException;
7 use Drupal\Component\Plugin\Exception\MissingValueContextException;
8 use Drupal\Core\Cache\CacheableDependencyInterface;
9 use Drupal\Core\Plugin\ContextAwarePluginInterface;
10
11 /**
12  * Provides methods to handle sets of contexts.
13  */
14 class ContextHandler implements ContextHandlerInterface {
15
16   /**
17    * {@inheritdoc}
18    */
19   public function filterPluginDefinitionsByContexts(array $contexts, array $definitions) {
20     return array_filter($definitions, function ($plugin_definition) use ($contexts) {
21       $context_definitions = $this->getContextDefinitions($plugin_definition);
22
23       if ($context_definitions) {
24         // Check the set of contexts against the requirements.
25         return $this->checkRequirements($contexts, $context_definitions);
26       }
27       // If this plugin doesn't need any context, it is available to use.
28       return TRUE;
29     });
30   }
31
32   /**
33    * Returns the context definitions associated with a plugin definition.
34    *
35    * @param array|\Drupal\Component\Plugin\Definition\ContextAwarePluginDefinitionInterface $plugin_definition
36    *   The plugin definition.
37    *
38    * @return \Drupal\Component\Plugin\Context\ContextDefinitionInterface[]|null
39    *   The context definitions, or NULL if the plugin definition does not
40    *   support contexts.
41    */
42   protected function getContextDefinitions($plugin_definition) {
43     if ($plugin_definition instanceof ContextAwarePluginDefinitionInterface) {
44       return $plugin_definition->getContextDefinitions();
45     }
46     if (is_array($plugin_definition) && isset($plugin_definition['context'])) {
47       return $plugin_definition['context'];
48     }
49     return NULL;
50   }
51
52   /**
53    * {@inheritdoc}
54    */
55   public function checkRequirements(array $contexts, array $requirements) {
56     foreach ($requirements as $requirement) {
57       if ($requirement->isRequired() && !$this->getMatchingContexts($contexts, $requirement)) {
58         return FALSE;
59       }
60     }
61     return TRUE;
62   }
63
64   /**
65    * {@inheritdoc}
66    */
67   public function getMatchingContexts(array $contexts, ContextDefinitionInterface $definition) {
68     return array_filter($contexts, function (ContextInterface $context) use ($definition) {
69       return $definition->isSatisfiedBy($context);
70     });
71   }
72
73   /**
74    * {@inheritdoc}
75    */
76   public function applyContextMapping(ContextAwarePluginInterface $plugin, $contexts, $mappings = []) {
77     /** @var $contexts \Drupal\Core\Plugin\Context\ContextInterface[] */
78     $mappings += $plugin->getContextMapping();
79     // Loop through each of the expected contexts.
80
81     $missing_value = [];
82
83     foreach ($plugin->getContextDefinitions() as $plugin_context_id => $plugin_context_definition) {
84       // If this context was given a specific name, use that.
85       $context_id = isset($mappings[$plugin_context_id]) ? $mappings[$plugin_context_id] : $plugin_context_id;
86       if (!empty($contexts[$context_id])) {
87         // This assignment has been used, remove it.
88         unset($mappings[$plugin_context_id]);
89
90         // Plugins have their on context objects, only the value is applied.
91         // They also need to know about the cacheability metadata of where that
92         // value is coming from, so pass them through to those objects.
93         $plugin_context = $plugin->getContext($plugin_context_id);
94         if ($plugin_context instanceof ContextInterface && $contexts[$context_id] instanceof CacheableDependencyInterface) {
95           $plugin_context->addCacheableDependency($contexts[$context_id]);
96         }
97
98         // Pass the value to the plugin if there is one.
99         if ($contexts[$context_id]->hasContextValue()) {
100           $plugin->setContextValue($plugin_context_id, $contexts[$context_id]->getContextData());
101         }
102         elseif ($plugin_context_definition->isRequired()) {
103           // Collect required contexts that exist but are missing a value.
104           $missing_value[] = $plugin_context_id;
105         }
106       }
107       elseif ($plugin_context_definition->isRequired()) {
108         // Collect required contexts that are missing.
109         $missing_value[] = $plugin_context_id;
110       }
111       else {
112         // Ignore mappings for optional missing context.
113         unset($mappings[$plugin_context_id]);
114       }
115     }
116
117     // If there are any mappings that were not satisfied, throw an exception.
118     // This is a more severe problem than missing values, so check and throw
119     // this first.
120     if (!empty($mappings)) {
121       throw new ContextException('Assigned contexts were not satisfied: ' . implode(',', array_keys($mappings)));
122     }
123
124     // If there are any required contexts without a value, throw an exception.
125     if ($missing_value) {
126       throw new MissingValueContextException($missing_value);
127     }
128   }
129
130 }