toolshed-8.x-1.x-dev/src/Strategy/ThemeStrategyDiscoveryTrait.php
src/Strategy/ThemeStrategyDiscoveryTrait.php
<?php
namespace Drupal\toolshed\Strategy;
use Drupal\Component\Discovery\DiscoverableInterface;
use Drupal\Core\Extension\ThemeHandlerInterface;
use Drupal\Core\Theme\ThemeManagerInterface;
use Drupal\toolshed\Discovery\YamlDiscovery;
use Drupal\toolshed\Event\StrategyDefinitionAlterEvent;
/**
* Trait to add theme provide strategy discovery methods to a strategy manager.
*/
trait ThemeStrategyDiscoveryTrait {
/**
* The theme handler.
*
* @var \Drupal\Core\Extension\ThemeHandlerInterface|null
*/
protected ?ThemeHandlerInterface $themeHandler;
/**
* The theme manager.
*
* @var \Drupal\Core\Theme\ThemeManagerInterface|null
*/
protected ?ThemeManagerInterface $themeManager;
/**
* The discovery name to use when searching for definitions in themes.
*
* Generally this will be implemented by the strategy manager class.
*
* @return string
* The discovery name to use when searching for theme provided strategy
* definitions.
*
* @see \Drupal\toolshed\Strategy\StrategyDefinition::getDiscoveryName()
*/
abstract public function getDiscoveryName(): string;
/**
* Converts discovered array data into a StrategyDefinitionInterface object.
*
* Generally this will be implemented by the strategy manager class.
*
* @return \Drupal\toolshed\Strategy\StrategyDefinitionInterface
* The strategy definition object built from the definition data.
*
* @see \Drupal\toolshed\Strategy\StrategyDefinition::processDefinition()
*/
abstract protected function processDefinition(string $id, array $definition): StrategyDefinitionInterface;
/**
* Injects the theme handler and theme manager services.
*
* Can be called from an constructor to initialize these services or can be
* called from the services.yml file when defining services.
*
* The following is an example from the services definition:
*
* @code
* strategy.manager.example:
* class: Drupal\toolshed\ExampleManager
* arguments:
* - 'name'
* - '@module_handler'
* - '@cache.discovery'
* calls:
* - [setThemeServices, ['@theme_handler', '@theme.manager']]
* @endcode
*
* The latter is preferred, and keeps the constructor simpler. This also
* makes it easier to apply this trait without having to the need to override
* constructors.
*
* @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler
* The theme handler.
* @param \Drupal\Core\Theme\ThemeManagerInterface $theme_manager
* The theme manager.
*/
public function setThemeServices(ThemeHandlerInterface $theme_handler, ThemeManagerInterface $theme_manager): void {
$this->themeHandler = $theme_handler;
$this->themeManager = $theme_manager;
}
/**
* Gets the theme name of the default theme.
*
* The machine name of the theme to use when a theme is not specified
* explicitly. In general this is likely to be the "active" theme, but could
* be the "default" theme, or even based on context based criteria.
*
* Strategy managers (and other uses of this trait) should override this when
* if they determine the default theme in different ways, or conditionally.
*
* @return string
* The theme machine name to use as the default theme.
*/
protected function getDefaultTheme(): string {
return $this->themeManager->getActiveTheme()->getName();
}
/**
* Get the discovery instance to find theme provided strategy definitions.
*
* @return \Drupal\Component\Discovery\DiscoverableInterface
* The theme discovery object.
*/
protected function getThemeDiscovery(): DiscoverableInterface {
$dirs = $this->themeHandler->getThemeDirectories();
$discovery = new YamlDiscovery($this->getDiscoveryName(), $dirs);
$discovery->addTranslatableProperty('label', 'label_context');
$discovery->addTranslatableProperty('description', 'description_context');
return $discovery;
}
/**
* Get theme provided strategy definitons grouped by the theme.
*
* The definitions are organized by the themes that define them as follows:
*
* @code
* $this->themeDefinitions = [
* "<theme_name>" => [
* "<strategy_id>" => StrategyDefinition,
* "<strategy_id>" => StrategyDefinition,
* ...
* ],
* ];
* @endcode
*
* @return \Drupal\toolshed\Strategy\StrategyDefinitionInterface[][]
* Get the theme definitions provided by themes. The definitions are
* grouped by the providing themes.
*/
public function findThemeDefinitions(): array {
$discovery = $this->getThemeDiscovery();
$byProvider = $discovery->findAll();
// Ensure that all the definitions have their ID and provider info set.
foreach ($byProvider as $theme => &$definitions) {
foreach ($definitions as $id => &$definition) {
$definition += [
'id' => $id,
'provider' => $theme,
'provider_type' => 'theme',
];
}
}
unset($definitions, $definition);
// Allow other modules to alter the discovered strategy definitions before
// they are converted to the StrategyDefinitionInterface instances.
if (!empty($this->alterEventName) && !empty($this->eventDispatcher)) {
$event = new StrategyDefinitionAlterEvent('theme', $byProvider);
$this->eventDispatcher->dispatch($event, $this->alterEventName);
}
$strategies = [];
foreach ($byProvider as $theme => $definitions) {
foreach ($definitions as $id => $def) {
$strategies[$theme][$id] = $this->processDefinition($id, $def);
}
}
return $strategies;
}
}
