diff options
Diffstat (limited to 'core/modules/breakpoint/src/BreakpointManager.php')
-rw-r--r-- | core/modules/breakpoint/src/BreakpointManager.php | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/core/modules/breakpoint/src/BreakpointManager.php b/core/modules/breakpoint/src/BreakpointManager.php new file mode 100644 index 0000000..757f2cf --- /dev/null +++ b/core/modules/breakpoint/src/BreakpointManager.php @@ -0,0 +1,274 @@ +<?php + +/** + * @file + * Contains \Drupal\breakpoint\BreakpointManager. + */ + +namespace Drupal\breakpoint; + +use Drupal\Core\Cache\Cache; +use Drupal\Core\Cache\CacheBackendInterface; +use Drupal\Core\Extension\ModuleHandlerInterface; +use Drupal\Core\Extension\ThemeHandlerInterface; +use Drupal\Core\Plugin\DefaultPluginManager; +use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator; +use Drupal\Core\Plugin\Discovery\YamlDiscovery; +use Drupal\Core\Plugin\Factory\ContainerFactory; +use Drupal\Core\StringTranslation\StringTranslationTrait; +use Drupal\Core\StringTranslation\TranslationInterface; + +/** + * Defines a breakpoint plugin manager to deal with breakpoints. + * + * Extension can define breakpoints in a EXTENSION_NAME.breakpoints.yml file + * contained in the extension's base directory. Each breakpoint has the + * following structure: + * @code + * MACHINE_NAME: + * label: STRING + * mediaQuery: STRING + * weight: INTEGER + * multipliers: + * - STRING + * @endcode + * For example: + * @code + * bartik.mobile: + * label: mobile + * mediaQuery: '(min-width: 0px)' + * weight: 0 + * multipliers: + * - 1x + * - 2x + * @endcode + * Optionally a breakpoint can provide a group key. By default an extensions + * breakpoints will be placed in a group labelled with the extension name. + * + * @see \Drupal\breakpoint\Breakpoint + * @see \Drupal\breakpoint\BreakpointInterface + * @see plugin_api + */ +class BreakpointManager extends DefaultPluginManager implements BreakpointManagerInterface { + use StringTranslationTrait; + + /** + * {@inheritdoc} + */ + protected $defaults = array( + // Human readable label for breakpoint. + 'label' => '', + // The media query for the breakpoint. + 'mediaQuery' => '', + // Weight used for ordering breakpoints. + 'weight' => 0, + // Breakpoint multipliers. + 'multipliers' => array(), + // The breakpoint group. + 'group' => '', + // Default class for breakpoint implementations. + 'class' => 'Drupal\breakpoint\Breakpoint', + // The plugin id. Set by the plugin system based on the top-level YAML key. + 'id' => '', + ); + + /** + * The theme handler. + * + * @var \Drupal\Core\Extension\ThemeHandlerInterface + */ + protected $themeHandler; + + /** + * Static cache of breakpoints keyed by group. + * + * @var array + */ + protected $breakpointsByGroup; + + /** + * The plugin instances. + * + * @var array + */ + protected $instances = array(); + + /** + * Constructs a new BreakpointManager instance. + * + * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler + * The module handler. + * @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler + * The theme handler. + * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend + * The cache backend. + * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation + * The string translation service. + */ + public function __construct(ModuleHandlerInterface $module_handler, ThemeHandlerInterface $theme_handler, CacheBackendInterface $cache_backend, TranslationInterface $string_translation) { + $this->discovery = new YamlDiscovery('breakpoints', $module_handler->getModuleDirectories() + $theme_handler->getThemeDirectories()); + $this->discovery = new ContainerDerivativeDiscoveryDecorator($this->discovery); + $this->factory = new ContainerFactory($this); + $this->moduleHandler = $module_handler; + $this->themeHandler = $theme_handler; + $this->setStringTranslation($string_translation); + $this->alterInfo('breakpoints'); + $this->setCacheBackend($cache_backend, 'breakpoints', array('breakpoints' => TRUE)); + } + + /** + * {@inheritdoc} + */ + public function processDefinition(&$definition, $plugin_id) { + parent::processDefinition($definition, $plugin_id); + // Allow custom groups and therefore more than one group per extension. + if (empty($definition['group'])) { + $definition['group'] = $definition['provider']; + } + // Ensure a 1x multiplier exists. + if (!in_array('1x', $definition['multipliers'])) { + $definition['multipliers'][] = '1x'; + } + // Ensure that multipliers are sorted correctly. + sort($definition['multipliers']); + } + + /** + * {@inheritdoc} + */ + protected function findDefinitions() { + $definitions = $this->discovery->getDefinitions(); + foreach ($definitions as $plugin_id => &$definition) { + $this->processDefinition($definition, $plugin_id); + } + if ($this->alterHook) { + $this->moduleHandler->alter($this->alterHook, $definitions); + } + // If this plugin was provided by a module that does not exist, remove the + // plugin definition. + foreach ($definitions as $plugin_id => $plugin_definition) { + // If the plugin definition is an object, attempt to convert it to an + // array, if that is not possible, skip further processing. + if (is_object($plugin_definition) && !($plugin_definition = (array) $plugin_definition)) { + continue; + } + // Allow themes to provide breakpoints. + if (isset($plugin_definition['provider']) && !in_array($plugin_definition['provider'], array('core', 'component')) && !$this->moduleHandler->moduleExists($plugin_definition['provider']) && !$this->themeHandler->themeExists($plugin_definition['provider'])) { + unset($definitions[$plugin_id]); + } + } + return $definitions; + } + + /** + * {@inheritdoc} + */ + public function getBreakpointsByGroup($group) { + if (!isset($this->breakpointsByGroup[$group])) { + if ($cache = $this->cacheBackend->get($this->cacheKey . ':' . $group)) { + $this->breakpointsByGroup[$group] = $cache->data; + } + else { + $breakpoints = array(); + foreach ($this->getDefinitions() as $plugin_id => $plugin_definition) { + if ($plugin_definition['group'] == $group) { + $breakpoints[$plugin_id] = $plugin_definition; + } + } + uasort($breakpoints, array('Drupal\Component\Utility\SortArray', 'sortByWeightElement')); + $this->cacheBackend->set($this->cacheKey . ':' . $group, $breakpoints, Cache::PERMANENT, array('breakpoints' => TRUE)); + $this->breakpointsByGroup[$group] = $breakpoints; + } + } + $instances = array(); + foreach ($this->breakpointsByGroup[$group] as $plugin_id => $definition) { + if (!isset($this->instances[$plugin_id])) { + $this->instances[$plugin_id] = $this->createInstance($plugin_id); + } + $instances[$plugin_id] = $this->instances[$plugin_id]; + } + return $instances; + } + + /** + * {@inheritdoc} + */ + public function getGroups() { + // Use a double colon so as to not clash with the cache for each group. + if ($cache = $this->cacheBackend->get($this->cacheKey . '::groups')) { + $groups = $cache->data; + } + else { + $groups = array(); + foreach ($this->getDefinitions() as $plugin_definition) { + if (!isset($groups[$plugin_definition['group']])) { + $groups[$plugin_definition['group']] = $plugin_definition['group']; + } + } + $this->cacheBackend->set($this->cacheKey . '::groups', $groups, Cache::PERMANENT, array('breakpoints' => TRUE)); + } + // Get the labels. This is not cacheable due to translation. + $group_labels = array(); + foreach ($groups as $group) { + $group_labels[$group] = $this->getGroupLabel($group); + } + asort($group_labels); + return $group_labels; + } + + /** + * {@inheritdoc} + */ + public function getGroupProviders($group) { + $providers = array(); + $breakpoints = $this->getBreakpointsByGroup($group); + foreach ($breakpoints as $breakpoint) { + $provider = $breakpoint->getProvider(); + $extension = FALSE; + if ($this->moduleHandler->moduleExists($provider)) { + $extension = $this->moduleHandler->getModule($provider); + } + elseif ($this->themeHandler->themeExists($provider)) { + $extension = $this->themeHandler->getTheme($provider); + } + if ($extension) { + $providers[$extension->getName()] = $extension->getType(); + } + } + return $providers; + } + + /** + * {@inheritdoc} + */ + public function clearCachedDefinitions() { + parent::clearCachedDefinitions(); + $this->breakpointsByGroup = NULL; + $this->instances = array(); + } + + /** + * Gets the label for a breakpoint group. + * + * @param string $group + * The breakpoint group. + * + * @return string + * The label. + */ + protected function getGroupLabel($group) { + // Extension names are not translatable. + if ($this->moduleHandler->moduleExists($group)) { + $label = $this->moduleHandler->getName($group); + } + elseif ($this->themeHandler->themeExists($group)) { + $label = $this->themeHandler->getName($group); + } + else { + // Custom group label that should be translatable. + $label = $this->t($group, array(), array('context' => 'breakpoint')); + } + return $label; + } + +} |