Version 1
[yaffs-website] / web / modules / contrib / bootstrap_layouts / src / BootstrapLayoutsManager.php
1 <?php
2
3 namespace Drupal\bootstrap_layouts;
4
5 use Drupal\bootstrap_layouts\Plugin\Layout\BootstrapLayoutsBase;
6 use Drupal\Component\Serialization\Yaml;
7 use Drupal\Component\Utility\NestedArray;
8 use Drupal\Component\Utility\Unicode;
9 use Drupal\Core\Cache\CacheBackendInterface;
10 use Drupal\Core\Extension\ModuleHandlerInterface;
11 use Drupal\Core\Extension\ThemeHandlerInterface;
12 use Drupal\Core\Theme\ThemeManagerInterface;
13 use Drupal\layout_plugin\Plugin\Layout\LayoutPluginManager;
14 use Symfony\Component\DependencyInjection\ContainerInterface;
15
16 /**
17  * Class BootstrapLayoutsManager
18  */
19 class BootstrapLayoutsManager extends BootstrapLayoutsPluginManager {
20
21   /**
22    * @var \Drupal\layout_plugin\Plugin\Layout\LayoutPluginManager
23    */
24   protected $layoutManager;
25
26   /**
27    * @var \Drupal\bootstrap_layouts\BootstrapLayoutsUpdateManager
28    */
29   protected $updateManager;
30
31   /**
32    * Constructs a new \Drupal\bootstrap_layouts\BootstrapLayoutsManager object.
33    *
34    * @param \Traversable $namespaces
35    *   An object that implements \Traversable which contains the root paths
36    *   keyed by the corresponding namespace to look for plugin implementations.
37    * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
38    *   Cache backend instance to use.
39    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
40    *   The module handler to invoke the alter hook with.
41    * @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler
42    *   The theme manager used to invoke the alter hook with.
43    * @param \Drupal\Core\Theme\ThemeManagerInterface $theme_manager
44    *   The theme manager used to invoke the alter hook with.
45    * @param \Drupal\layout_plugin\Plugin\Layout\LayoutPluginManager $layout_manager
46    *   The Layout Manager.
47    * @param \Drupal\bootstrap_layouts\BootstrapLayoutsUpdateManager $update_manager
48    *   The Bootstrap Layouts update manager.
49    */
50   public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, ThemeHandlerInterface $theme_handler, ThemeManagerInterface $theme_manager, LayoutPluginManager $layout_manager, BootstrapLayoutsUpdateManager $update_manager) {
51     parent::__construct($namespaces, $cache_backend, $module_handler, $theme_handler, $theme_manager, 'Drupal\bootstrap_layouts\Plugin\BootstrapLayouts\BootstrapLayoutsHandlerInterface', 'Drupal\bootstrap_layouts\Annotation\BootstrapLayoutsHandler');
52     $this->layoutManager = $layout_manager;
53     $this->updateManager = $update_manager;
54     $this->alterInfo('bootstrap_layouts_handler_info');
55     $this->setCacheBackend($cache_backend, 'bootstrap_layouts_handler_info');
56   }
57
58   /**
59    * {@inheritdoc}
60    */
61   public static function create(ContainerInterface $container) {
62     return new static(
63       $container->get('container.namespaces'),
64       $container->get('cache.discovery'),
65       $container->get('module_handler'),
66       $container->get('theme_handler'),
67       $container->get('theme.manager'),
68       $container->get('plugin.manager.layout_plugin'),
69       $container->get('plugin.manager.bootstrap_layouts.update')
70     );
71   }
72
73   /**
74    * {@inheritdoc}
75    */
76   protected function findDefinitions() {
77     $definitions = parent::findDefinitions();
78     // The handler plugin identifiers represent the module or theme that
79     // implements said layouts. Remove any handler plugins that not installed.
80     foreach (array_keys($definitions) as $provider) {
81       if (!$this->providerExists($provider)) {
82         unset($definitions[$provider]);
83       }
84       else {
85         // Attempt to retrieve the theme human readable label first.
86         try {
87           $label = $this->themeHandler->getName($provider);
88         }
89         // Otherwise attempt to retrieve the module human readable label.
90         catch (\Exception $e) {
91           $label = $this->moduleHandler->getName($provider);
92         }
93         $definitions[$provider]['label'] = $label;
94       }
95     }
96     return $definitions;
97   }
98
99   /**
100    * Retrieves classes that can be used in Bootstrap layouts as select options.
101    *
102    * @return array
103    *   An associative array of grouped classes to be used in select options.
104    */
105   public function getClassOptions() {
106     static $classes;
107
108     if (!isset($classes)) {
109       $utility = [];
110       $col = [];
111       $hidden = [];
112       $visible = [];
113       $bg = [];
114       $text_color = [];
115       $text_alignment = [
116         'text-left' => $this->t('Left'),
117         'text-right' => $this->t('Right'),
118         'text-center' => $this->t('Center'),
119         'text-justify' => $this->t('Justify'),
120         'text-nowrap' => $this->t('No Wrap'),
121       ];
122       $text_transformation = [
123         'text-lowercase' => $this->t('Lowercase'),
124         'text-uppercase' => $this->t('Uppercase'),
125         'text-capitalize' => $this->t('Capitalize'),
126       ];
127
128       // Utility.
129       $utility['clearfix'] = $this->t('Clear Fix');
130       $utility['row'] = $this->t('Row');
131
132       $sizes = [
133         'xs' => $this->t('Extra Small'),
134         'sm' => $this->t('Small'),
135         'md' => $this->t('Medium'),
136         'lg' => $this->t('Large'),
137       ];
138
139       foreach ($sizes as $size => $size_label) {
140         $hidden["hidden-$size"] = $size_label;
141         $visible["visible-$size"] = $size_label;
142         foreach (range(1, 12) as $column) {
143           $col["col-$size-$column"] = $this->t('@size: @column', [
144             '@size' => $size_label,
145             '@column' => $column,
146           ]);
147         }
148       }
149
150       // Background/text color classes.
151       foreach (['primary', 'danger', 'info', 'warning', 'success'] as $type) {
152         $bg["bg-$type"] = $this->t('@type', ['@type' => Unicode::ucfirst($type)]);
153         $text_color["text-$type"] = $this->t('@type', ['@type' => Unicode::ucfirst($type)]);
154       }
155       $text_color['text-muted'] = $this->t('Muted');
156
157       // Groups.
158       $groups = [
159         'utility' => $this->t('Utility'),
160         'columns' => $this->t('Columns'),
161         'hidden' => $this->t('Hidden'),
162         'visible' => $this->t('Visible'),
163         'background' => $this->t('Background'),
164         'text_alignment' => $this->t('Text alignment'),
165         'text_color' => $this->t('Text color'),
166         'text_transformation' => $this->t('Text transformation'),
167       ];
168
169       // Classes, keyed by group.
170       $classes = [
171         'utility' => $utility,
172         'columns' => $col,
173         'hidden' => $hidden,
174         'visible' => $visible,
175         'background' => $bg,
176         'text_alignment' => $text_alignment,
177         'text_color' => $text_color,
178         'text_transformation' => $text_transformation,
179       ];
180
181       // Invokes hook_bootstrap_layouts_class_options_alter().
182       $this->moduleHandler->alter('bootstrap_layouts_class_options', $classes, $groups);
183       $this->themeManager->alter('bootstrap_layouts_class_options', $classes, $groups);
184
185       // Render the group labels and use them for optgroup values.
186       $grouped = [];
187       foreach ($classes as $group => $data) {
188         $group = (string) (isset($groups[$group]) ? $groups[$group] : $group);
189         $grouped[$group] = $data;
190       }
191       $classes = $grouped;
192     }
193
194     return $classes;
195   }
196
197   /**
198    * Indicates if provided layout identifier is a Bootstrap Layouts layout.
199    *
200    * @param string $id
201    *   The layout identifier to test.
202    *
203    * @return bool
204    *   TRUE or FALSE
205    */
206   public function isBootstrapLayout($id) {
207     static $layouts;
208     if (!isset($layouts)) {
209       $layouts = [];
210       foreach (array_keys($this->layoutManager->getDefinitions()) as $layout_id) {
211         $plugin = $this->layoutManager->createInstance($layout_id);
212         if ($plugin instanceof BootstrapLayoutsBase) {
213           $layouts[] = $layout_id;
214         }
215       }
216     }
217     return in_array($id, $layouts);
218   }
219
220   /**
221    * Retrieves all available handler instances.
222    *
223    * @return \Drupal\bootstrap_layouts\Plugin\BootstrapLayouts\BootstrapLayoutsHandlerInterface[]
224    */
225   public function getHandlers() {
226     $instances = [];
227     foreach (array_keys($this->getDefinitions()) as $plugin_id) {
228       $instances[$plugin_id] = $this->createInstance($plugin_id);
229     }
230     return $instances;
231   }
232
233   /**
234    * Runs update(s) for a specific schema version.
235    *
236    * @param int $schema
237    *   The schema version to update.
238    * @param bool $display_messages
239    *   Flag determining whether a message will be displayed indicating whether
240    *   the layout was processed successfully or not.
241    */
242   public function update($schema, $display_messages = TRUE) {
243     $handlers = $this->getHandlers();
244     $data = [];
245     foreach ($this->updateManager->getUpdates($schema) as $update) {
246       // See if there's an adjoining YML file with the update plugin.
247       $r = new \ReflectionClass($update);
248       $data_paths = [dirname($r->getFileName()), $update->getPath()];
249
250       // Merge in any update data.
251       foreach ($data_paths as $path) {
252         $file = "$path/bootstrap_layouts.update.$schema.yml";
253         if (file_exists($file) && ($yaml = Yaml::decode(file_get_contents($file)))) {
254           $data = NestedArray::mergeDeep($data, $yaml);
255         }
256       }
257
258       // Perform the update.
259       $update->update($this, $data, $display_messages);
260
261       // Process any existing layouts after the update.
262       foreach ($handlers as $handler_id => $handler) {
263         foreach ($handler->loadInstances() as $storage_id => $layout) {
264           $update->processExistingLayout($layout, $data, $display_messages);
265
266           // Determine if the layout has changed and then save it.
267           if ($layout->hasChanged()) {
268             try {
269               $handler->saveInstance($storage_id, $layout);
270               if ($display_messages) {
271                 \drupal_set_message($this->t('Successfully updated the existing Bootstrap layout found in "@id".', ['@id' => $storage_id]));
272               }
273             } catch (\Exception $e) {
274               \drupal_set_message($this->t('Unable to update the existing Bootstrap layout found in "@id":', ['@id' => $storage_id]), 'error');
275               \drupal_set_message($e->getMessage(), 'error');
276             }
277           }
278         }
279       }
280     }
281   }
282
283 }