breezy_utility-1.0.x-dev/src/BreezyUtilityClassesManager.php
src/BreezyUtilityClassesManager.php
<?php
namespace Drupal\breezy_utility;
use Drupal\Component\Plugin\Exception\PluginException;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Extension\ModuleExtensionList;
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;
/**
* Provides a plugin manager for BreezyUtilityClasses plugins.
*
* @see plugin_api
*/
class BreezyUtilityClassesManager extends DefaultPluginManager implements BreezyUtilityClassesManagerInterface {
use StringTranslationTrait;
/**
* The theme handler.
*
* @var \Drupal\Core\Extension\ThemeHandlerInterface
*/
protected ThemeHandlerInterface $themeHandler;
/**
* A cache of loaded utility classes, keyed by group.
*
* @var array
*/
protected array $utilityClasses;
/**
* ModuleExtensionList definition.
*
* @var \Drupal\Core\Extension\ModuleExtensionList
*/
protected ?ModuleExtensionList $moduleExtensionList;
/**
* An array of instances.
*
* @var array
*/
protected array $instances;
/**
* Default values for each BreezyUtilityClasses plugin.
*
* @var array
*/
protected $defaults = [
'id' => '',
'label' => '',
'group' => '',
'api' => '',
'css_property' => '',
'classes' => [],
// Default class for breezy_utility_classes implementations.
'class' => 'Drupal\breezy_utility\UtilityClass',
];
/**
* Constructs a new BreezyUtilityClassesManager object.
*
* @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.
* @param \Drupal\Core\Extension\ModuleExtensionList|null $module_extension_list
* The module extension list.
*/
public function __construct(ModuleHandlerInterface $module_handler, ThemeHandlerInterface $theme_handler, CacheBackendInterface $cache_backend, TranslationInterface $string_translation, ?ModuleExtensionList $module_extension_list = NULL) {
$this->factory = new ContainerFactory($this);
$this->moduleHandler = $module_handler;
$this->themeHandler = $theme_handler;
if ($module_extension_list === NULL) {
@trigger_error('Calling ' . __METHOD__ . '() without the $module_extension_list argument is deprecated in drupal:10.3.0 and will be required in drupal:12.0.0. See https://www.drupal.org/node/3310017', E_USER_DEPRECATED);
// @phpstan-ignore-next-line
$module_extension_list = \Drupal::service('extension.list.module');
}
$this->moduleExtensionList = $module_extension_list;
$this->setStringTranslation($string_translation);
$this->alterInfo('breezy_utility_classes');
$this->setCacheBackend($cache_backend, 'breezy_utility', ['breezy_utility']);
}
/**
* {@inheritdoc}
*/
protected function getDiscovery() {
if (!isset($this->discovery)) {
$this->discovery = new YamlDiscovery('utility_classes', $this->moduleHandler->getModuleDirectories() + $this->themeHandler->getThemeDirectories());
$this->discovery = new ContainerDerivativeDiscoveryDecorator($this->discovery);
}
return $this->discovery;
}
/**
* {@inheritdoc}
*/
public function processDefinition(&$definition, $plugin_id) {
parent::processDefinition($definition, $plugin_id);
$definition['id'] = $plugin_id;
foreach (['label', 'group', 'css_property', 'classes'] as $required_property) {
if (empty($definition[$required_property])) {
throw new PluginException(sprintf('The utility class %s must define the %s property.', $plugin_id, $required_property));
}
}
}
/**
* {@inheritdoc}
*/
protected function providerExists($provider) {
return $this->moduleHandler->moduleExists($provider) || $this->themeHandler->themeExists($provider);
}
/**
* {@inheritdoc}
*/
public function getUtilityClassesByGroup(string $group) {
if (!isset($this->utilityClasses[$group])) {
if ($cache = $this->cacheBackend->get($this->cacheKey . ':' . $group)) {
$this->utilityClasses[$group] = $cache->data;
}
else {
$utility_classes = [];
foreach ($this->getDefinitions() as $plugin_id => $plugin_definition) {
if ($plugin_definition['group'] == $group) {
$utility_classes[$plugin_id] = $plugin_definition;
}
}
$this->cacheBackend->set($this->cacheKey . ':' . $group, $utility_classes, Cache::PERMANENT, ['utility_classes']);
$this->utilityClasses[$group] = $utility_classes;
}
}
$instances = [];
foreach ($this->utilityClasses[$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 = [];
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, ['utility_classes']);
}
// Get the labels. This is not cacheable due to translation.
$group_labels = [];
foreach ($groups as $group) {
$group_labels[$group] = $this->getGroupLabel($group);
}
asort($group_labels);
return $group_labels;
}
/**
* {@inheritdoc}
*/
public function getGroupProviders(string $group) {
$providers = [];
$utility_classes = $this->getUtilityClassesByGroup($group);
foreach ($utility_classes as $utility_class) {
$provider = $utility_class->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->utilityClasses = [];
$this->instances = [];
}
/**
* Gets the label for a utility class group.
*
* @param string $group
* The utility_class group.
*
* @return string
* The label.
*/
protected function getGroupLabel($group) {
// Extension names are not translatable.
if ($this->moduleHandler->moduleExists($group)) {
$label = $this->moduleExtensionList->getName($group);
}
elseif ($this->themeHandler->themeExists($group)) {
$label = $this->themeHandler->getName($group);
}
else {
// Custom group label that should be translatable.
$label = $this->t('@group', ['@group' => $group], ['context' => 'utility_classes']);
}
return $label;
}
}
