Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / web / core / modules / breakpoint / src / BreakpointManager.php
1 <?php
2
3 namespace Drupal\breakpoint;
4
5 use Drupal\Core\Cache\Cache;
6 use Drupal\Core\Cache\CacheBackendInterface;
7 use Drupal\Core\Extension\ModuleHandlerInterface;
8 use Drupal\Core\Extension\ThemeHandlerInterface;
9 use Drupal\Core\Plugin\DefaultPluginManager;
10 use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator;
11 use Drupal\Core\Plugin\Discovery\YamlDiscovery;
12 use Drupal\Core\Plugin\Factory\ContainerFactory;
13 use Drupal\Core\StringTranslation\StringTranslationTrait;
14 use Drupal\Core\StringTranslation\TranslationInterface;
15
16 /**
17  * Defines a breakpoint plugin manager to deal with breakpoints.
18  *
19  * Extension can define breakpoints in a EXTENSION_NAME.breakpoints.yml file
20  * contained in the extension's base directory. Each breakpoint has the
21  * following structure:
22  * @code
23  *   MACHINE_NAME:
24  *     label: STRING
25  *     mediaQuery: STRING
26  *     weight: INTEGER
27  *     multipliers:
28  *       - STRING
29  * @endcode
30  * For example:
31  * @code
32  * bartik.mobile:
33  *   label: mobile
34  *   mediaQuery: '(min-width: 0px)'
35  *   weight: 0
36  *   multipliers:
37  *     - 1x
38  *     - 2x
39  * @endcode
40  * Optionally a breakpoint can provide a group key. By default an extensions
41  * breakpoints will be placed in a group labelled with the extension name.
42  *
43  * @see \Drupal\breakpoint\Breakpoint
44  * @see \Drupal\breakpoint\BreakpointInterface
45  * @see plugin_api
46  */
47 class BreakpointManager extends DefaultPluginManager implements BreakpointManagerInterface {
48   use StringTranslationTrait;
49
50   /**
51    * {@inheritdoc}
52    */
53   protected $defaults = [
54     // Human readable label for breakpoint.
55     'label' => '',
56     // The media query for the breakpoint.
57     'mediaQuery' => '',
58     // Weight used for ordering breakpoints.
59     'weight' => 0,
60     // Breakpoint multipliers.
61     'multipliers' => [],
62     // The breakpoint group.
63     'group' => '',
64     // Default class for breakpoint implementations.
65     'class' => 'Drupal\breakpoint\Breakpoint',
66     // The plugin id. Set by the plugin system based on the top-level YAML key.
67     'id' => '',
68   ];
69
70   /**
71    * The theme handler.
72    *
73    * @var \Drupal\Core\Extension\ThemeHandlerInterface
74    */
75   protected $themeHandler;
76
77   /**
78    * Static cache of breakpoints keyed by group.
79    *
80    * @var array
81    */
82   protected $breakpointsByGroup;
83
84   /**
85    * The plugin instances.
86    *
87    * @var array
88    */
89   protected $instances = [];
90
91   /**
92    * Constructs a new BreakpointManager instance.
93    *
94    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
95    *   The module handler.
96    * @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler
97    *   The theme handler.
98    * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
99    *   The cache backend.
100    * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
101    *   The string translation service.
102    */
103   public function __construct(ModuleHandlerInterface $module_handler, ThemeHandlerInterface $theme_handler, CacheBackendInterface $cache_backend, TranslationInterface $string_translation) {
104     $this->factory = new ContainerFactory($this);
105     $this->moduleHandler = $module_handler;
106     $this->themeHandler = $theme_handler;
107     $this->setStringTranslation($string_translation);
108     $this->alterInfo('breakpoints');
109     $this->setCacheBackend($cache_backend, 'breakpoints', ['breakpoints']);
110   }
111
112   /**
113    * {@inheritdoc}
114    */
115   protected function getDiscovery() {
116     if (!isset($this->discovery)) {
117       $this->discovery = new YamlDiscovery('breakpoints', $this->moduleHandler->getModuleDirectories() + $this->themeHandler->getThemeDirectories());
118       $this->discovery = new ContainerDerivativeDiscoveryDecorator($this->discovery);
119     }
120     return $this->discovery;
121   }
122
123   /**
124    * {@inheritdoc}
125    */
126   public function processDefinition(&$definition, $plugin_id) {
127     parent::processDefinition($definition, $plugin_id);
128     // Allow custom groups and therefore more than one group per extension.
129     if (empty($definition['group'])) {
130       $definition['group'] = $definition['provider'];
131     }
132     // Ensure a 1x multiplier exists.
133     if (!in_array('1x', $definition['multipliers'])) {
134       $definition['multipliers'][] = '1x';
135     }
136     // Ensure that multipliers are sorted correctly.
137     sort($definition['multipliers']);
138   }
139
140   /**
141    * {@inheritdoc}
142    */
143   protected function providerExists($provider) {
144     return $this->moduleHandler->moduleExists($provider) || $this->themeHandler->themeExists($provider);
145   }
146
147   /**
148    * {@inheritdoc}
149    */
150   public function getBreakpointsByGroup($group) {
151     if (!isset($this->breakpointsByGroup[$group])) {
152       if ($cache = $this->cacheBackend->get($this->cacheKey . ':' . $group)) {
153         $this->breakpointsByGroup[$group] = $cache->data;
154       }
155       else {
156         $breakpoints = [];
157         foreach ($this->getDefinitions() as $plugin_id => $plugin_definition) {
158           if ($plugin_definition['group'] == $group) {
159             $breakpoints[$plugin_id] = $plugin_definition;
160           }
161         }
162         uasort($breakpoints, ['Drupal\Component\Utility\SortArray', 'sortByWeightElement']);
163         $this->cacheBackend->set($this->cacheKey . ':' . $group, $breakpoints, Cache::PERMANENT, ['breakpoints']);
164         $this->breakpointsByGroup[$group] = $breakpoints;
165       }
166     }
167
168     $instances = [];
169     foreach ($this->breakpointsByGroup[$group] as $plugin_id => $definition) {
170       if (!isset($this->instances[$plugin_id])) {
171         $this->instances[$plugin_id] = $this->createInstance($plugin_id);
172       }
173       $instances[$plugin_id] = $this->instances[$plugin_id];
174     }
175     return $instances;
176   }
177
178   /**
179    * {@inheritdoc}
180    */
181   public function getGroups() {
182     // Use a double colon so as to not clash with the cache for each group.
183     if ($cache = $this->cacheBackend->get($this->cacheKey . '::groups')) {
184       $groups = $cache->data;
185     }
186     else {
187       $groups = [];
188       foreach ($this->getDefinitions() as $plugin_definition) {
189         if (!isset($groups[$plugin_definition['group']])) {
190           $groups[$plugin_definition['group']] = $plugin_definition['group'];
191         }
192       }
193       $this->cacheBackend->set($this->cacheKey . '::groups', $groups, Cache::PERMANENT, ['breakpoints']);
194     }
195     // Get the labels. This is not cacheable due to translation.
196     $group_labels = [];
197     foreach ($groups as $group) {
198       $group_labels[$group] = $this->getGroupLabel($group);
199     }
200     asort($group_labels);
201     return $group_labels;
202   }
203
204   /**
205    * {@inheritdoc}
206    */
207   public function getGroupProviders($group) {
208     $providers = [];
209     $breakpoints = $this->getBreakpointsByGroup($group);
210     foreach ($breakpoints as $breakpoint) {
211       $provider = $breakpoint->getProvider();
212       $extension = FALSE;
213       if ($this->moduleHandler->moduleExists($provider)) {
214         $extension = $this->moduleHandler->getModule($provider);
215       }
216       elseif ($this->themeHandler->themeExists($provider)) {
217         $extension = $this->themeHandler->getTheme($provider);
218       }
219       if ($extension) {
220         $providers[$extension->getName()] = $extension->getType();
221       }
222     }
223     return $providers;
224   }
225
226   /**
227    * {@inheritdoc}
228    */
229   public function clearCachedDefinitions() {
230     parent::clearCachedDefinitions();
231     $this->breakpointsByGroup = NULL;
232     $this->instances = [];
233   }
234
235   /**
236    * Gets the label for a breakpoint group.
237    *
238    * @param string $group
239    *   The breakpoint group.
240    *
241    * @return string
242    *   The label.
243    */
244   protected function getGroupLabel($group) {
245     // Extension names are not translatable.
246     if ($this->moduleHandler->moduleExists($group)) {
247       $label = $this->moduleHandler->getName($group);
248     }
249     elseif ($this->themeHandler->themeExists($group)) {
250       $label = $this->themeHandler->getName($group);
251     }
252     else {
253       // Custom group label that should be translatable.
254       $label = $this->t($group, [], ['context' => 'breakpoint']);
255     }
256     return $label;
257   }
258
259 }