admin_toolbar_content-1.0.0/src/AdminToolbarContentPluginBase.php

src/AdminToolbarContentPluginBase.php
<?php

namespace Drupal\admin_toolbar_content;

use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\ImmutableConfig;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Plugin\PluginBase;
use Drupal\Core\Routing\RouteProviderInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides a basic deriver with caching capabilities.
 */
abstract class AdminToolbarContentPluginBase extends PluginBase implements AdminToolbarContentPluginInterface, ContainerFactoryPluginInterface {

  use StringTranslationTrait;

  /**
   * The entire list of links this deriver is providing.
   *
   * @var array
   */
  protected array $links;

  /**
   * The collections for this plugin.
   *
   * @var array
   */
  protected array $collections;

  /**
   * The items this plugin is handling.
   *
   * @var array
   */
  protected array $items;

  /**
   * The base menu link plugin definition.
   *
   * @var mixed
   */
  protected mixed $baseMenuLinkPluginDefinition;

  /**
   * The language manager.
   *
   * @var \Drupal\Core\Language\LanguageManagerInterface
   */
  protected LanguageManagerInterface $languageManager;

  /**
   * The current user.
   *
   * @var \Drupal\Core\Session\AccountProxyInterface
   */
  protected AccountProxyInterface $currentUser;

  /**
   * The entity type manager service.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected EntityTypeManagerInterface $entityTypeManager;

  /**
   * The route provider.
   *
   * @var \Drupal\Core\Routing\RouteProviderInterface
   */
  protected RouteProviderInterface $routeProvider;

  /**
   * The module handler.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
   */
  protected ModuleHandlerInterface $moduleHandler;

  /**
   * The admin toolbar config settings.
   *
   * @var \Drupal\Core\Config\ImmutableConfig
   */
  protected ImmutableConfig $config;

  /**
   * The entity repository.
   *
   * @var \Drupal\Core\Entity\EntityRepositoryInterface
   */
  protected EntityRepositoryInterface $entityRepository;

  /**
   * Constructs a \Drupal\Component\Plugin\PluginBase object.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin_id for the plugin instance.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\Core\Language\LanguageManagerInterface $languageManager
   *   The language manager.
   * @param \Drupal\Core\Session\AccountProxyInterface $current_user
   *   The current user.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager service.
   * @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
   *   The route provider.
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
   *   The module handler.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The config factory.
   * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
   *   The entity repository.
   */
  public function __construct(array $configuration,
                              string $plugin_id,
                              mixed $plugin_definition,
                              LanguageManagerInterface $languageManager,
                              AccountProxyInterface $current_user,
                              EntityTypeManagerInterface $entity_type_manager,
                              RouteProviderInterface $route_provider,
                              ModuleHandlerInterface $module_handler,
                              ConfigFactoryInterface $config_factory,
                              EntityRepositoryInterface $entity_repository
  ) {

    parent::__construct($configuration, $plugin_id, $plugin_definition);

    $this->languageManager = $languageManager;
    $this->currentUser = $current_user;
    $this->entityTypeManager = $entity_type_manager;
    $this->routeProvider = $route_provider;
    $this->moduleHandler = $module_handler;
    $this->config = $config_factory->get('admin_toolbar_content.settings');
    $this->entityRepository = $entity_repository;

  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('language_manager'),
      $container->get('current_user'),
      $container->get('entity_type.manager'),
      $container->get('router.route_provider'),
      $container->get('module_handler'),
      $container->get('config.factory'),
      $container->get('entity.repository'),
    );
  }

  /**
   * {@inheritdoc}
   */
  public function buildConfigForm(array &$form, FormStateInterface $form_state): array {
    $elements = [];

    $elements['enabled'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Enable'),
      '#description' => $this->t('Enabled the %plugin plugin.', ['%plugin' => $this->getPluginDefinition()['name']]),
      '#default_value' => $this->config->get("plugins." . $this->getPluginId() . ".enabled") ?? FALSE,
    ];

    return $elements;
  }



  /**
   * {@inheritdoc}
   */
  public function initialize(array &$links, mixed $base_plugin_link_definition): void {
    $this->links = &$links;
    $this->baseMenuLinkPluginDefinition = $base_plugin_link_definition;
  }

  /**
   * {@inheritdoc}
   */
  public function alterDiscoveredMenuLinks(array &$links): void {
    // Base class does nothing.
  }

  /**
   * {@inheritdoc}
   */
  public function needsMenuLinkRebuild(EntityInterface $entity): bool {
    return FALSE;
  }

  /**
   * {@inheritdoc}
   */
  public function preprocessMenu(array &$variables): void {
    $this->filterMenuItems($variables['items']);
  }

  /**
   * Hides links from admin menu, if user doesn't have access rights.
   */
  protected function filterMenuItems(array &$items, &$parent = NULL) {
    foreach ($items as $menu_id => &$item) {
      if (!empty($item['below'])) {
        // Recursively call this function for the child items.
        $this->filterMenuItems($item['below'], $item);
      }
      if ($this->filterMenuItem($item, $parent)) {
        unset($items[$menu_id]);
      }
    }
  }

  /**
   * Determines if a menu item needs to be filtered out or not.
   *
   * The base class will filter out collection items with no children.
   *
   * @param array $item
   *   The item to check for filtering.
   * @param array|null $parent
   *   The parent item of the given $item.
   *
   * @return bool
   *   True if the items needs to be filtered out, false if we can leave it in.
   */
  protected function filterMenuItem(array &$item, array &$parent = NULL): bool {
    if (empty($item['below']) && ($this->config->get('common.hide_empty_collections') ?? FALSE)) {
      $attributes = $item['url']->getOption('attributes') ?? [];
      if (in_array('admin-toolbar-content--collection', $attributes['class'])) {
        return TRUE;
      }
    }

    return FALSE;
  }

  /**
   * {@inheritdoc}
   */
  abstract public function createMenuLinkItems(): void;

  /**
   * Determine if a route exists.
   *
   * @param string $route_name
   *   The name of the route to check.
   *
   * @return bool
   *   True if the route exists or not.
   */
  protected function isRouteAvailable(string $route_name): bool {
    return (count($this->routeProvider->getRoutesByNames([$route_name])) === 1);
  }

  /**
   * Check if this plugin is enabled or not.
   *
   * @return bool
   *   Whether this plugin is enabled.
   */
  public function isEnabled(): bool {

    // Check if plugin is enabled in config.
    $enabled = $this->config->get("plugins." . $this->getPluginId() . '.enabled') ?? FALSE;

    if ($enabled) {
      // If the plugin deals with entities, make sure the type it handles
      // exists.
      $definition = $this->getPluginDefinition();
      $entity_type = $definition['entity_type'] ?? FALSE;
      if ($entity_type) {
        try {
          // Try to fetch the storage for the entity type.
          $this->entityTypeManager->getStorage($entity_type);
        }
        catch (InvalidPluginDefinitionException | PluginNotFoundException $e) {
          return FALSE;
        }
      }
    }

    return $enabled;
  }

  /**
   * Get the collection an item belongs to.
   *
   * @param mixed $item
   *   The item.
   * @param array|null $collections
   *   The collections.
   *
   * @return array
   *   The collections for the item.
   */
  protected function getItemCollection(mixed $item, array $collections = NULL): array {

    $found = [];
    $default = [];

    if (!isset($collections)) {
      $collections = $this->getCollections();
      // On the initial call when $collection is null, we set a default
      // collection, that way the recursive call only returns a valid (nonempty)
      // result if it is found in 'items' of the recursive collections. On the
      // recursive call, default remains empty.
      $default = [
        'id' => $this->getPluginId(),
      ];
    }

    foreach ($collections as $collection) {
      if (in_array($item->id(), $collection['items'] ?? [])) {
        $found = $collection;
      }
      else {
        $found = $this->getItemCollection($item, $collection['collections'] ?? []);
      }

      if (!empty($found)) {
        break;
      }
    }

    return $found + $default;
  }

  /**
   * Get the collection structure and stores it into the class.
   *
   * @return array
   *   A flattened array of collections to process for this plugin.
   */
  protected function getCollections(): array {

    if (empty($this->collections)) {
      $this->collections = $this->moduleHandler->invokeAll('admin_toolbar_content_collections');
      foreach ($this->collections as $plugin_id => &$collection) {
        // Sort collections so grouping will use alphabetic order.
        asort($collection);

        // The initial parent of a collection is the plugin id.
        $this->prepCollection($collection, $plugin_id);
      }
    }

    return $this->collections[$this->getPluginId()] ?? [];
  }

  /**
   * Preps the collections array, so it can be used for creating items.
   *
   * @param array $collections
   *   The collections.
   * @param string|null $parent
   *   The parent.
   */
  protected function prepCollection(array &$collections, string $parent = NULL): void {
    // Get the starting weight, or 0 if no grouping for collections is set.
    $group_collections_weight = [
      'bottom' => 100,
      'top' => -100,
    ][$this->config->get('common.group_collections')] ?? 0;

    foreach ($collections as $id => &$collection) {

      // The id represents the hierarchy of the collections, so add the parent.
      $collection['id'] = $parent ? "{$parent}.{$id}" : $id;

      // If the parent is an id from a link we have generated from within this
      // plugin add the base definition of this plugin.
      if (isset($this->links[$parent])) {
        $collection['parent'] = $this->baseMenuLinkPluginDefinition['id'] . ':' . $parent;
      }
      else {
        $collection['parent'] = $parent;
      }

      // Use group collections weight if group collections is enabled.
      if (!empty($group_collections_weight) && empty($collection['weight'])) {
        $collection['weight'] = $group_collections_weight;
        $group_collections_weight++;
      }

      if (isset($collection['collections'])) {
        asort($collection['collections']);
        $this->prepCollection($collection['collections'], $collection['id']);
      }
    }
  }

  /**
   * Get an array of items to create item links for.
   *
   * By default, this will get entities of the type given in the 'entity_type'
   * annotation attribute of the plugin definition.
   *
   * @return array
   *   The items as array.
   */
  protected function getItems(): array {

    if (empty($this->items)) {
      try {
        $definition = $this->getPluginDefinition();
        $this->items = $this->entityTypeManager
          ->getStorage($definition['entity_type'])
          ->loadMultiple();
      }
      catch (InvalidPluginDefinitionException | PluginNotFoundException $e) {
        return [];
      }
    }

    return $this->items;
  }

  /**
   * Creates a new menu link item.
   *
   * The new menu item is created in the 'admin' menu under 'system.admin'.
   *
   * The id of the menu link is the plugin id.
   *
   * Example:
   * $this->links['content']
   *
   * @param mixed $title
   *   Either a string or a TranslatableMarkup object.
   * @param string $route_name
   *   The route this menu item should point to.
   * @param array $route_parameters
   *   Optional parameters for the given route.
   * @param int $weight
   *   Optional weight for the menu item.
   */
  protected function createRootLink(mixed $title, string $route_name, array $route_parameters = [], int $weight = 0): void {
    if ($this->isRouteAvailable($route_name)) {
      $this->links[$this->getPluginId()] = [
        'title' => $title,
        'route_name' => $route_name,
        'route_parameters' => $route_parameters,
        'menu_name' => 'admin',
        'parent' => 'system.admin',
        'weight' => $weight,
      ] + $this->baseMenuLinkPluginDefinition;
    }
  }

  /**
   * Creates the collection links menu items tree.
   *
   * Example:
   *
   * $links['content.collection_a']
   * $links['content.collection_b']
   *
   * @param string $route
   *   The route.
   * @param array $route_parameters
   *   The route parameters.
   * @param array|null $collections
   *   The collections.
   *
   * @see \Drupal\admin_toolbar_content\AdminToolbarContentPluginBase::getCollections()
   */
  protected function createCollectionLinks(string $route, array $route_parameters = [], array $collections = NULL): void {

    if (!isset($collections)) {
      $collections = $this->getCollections();
    }

    foreach ($collections as $collection) {

      $this->createCollectionLink($collection, $route, $route_parameters);

      if (!empty($collection['collections'])) {
        $this->createCollectionLinks($route, $route_parameters, $collection['collections']);
      }

    }
  }

  /**
   * Creates a single collection link.
   *
   * It's up to the extending class to add:
   * - route_name
   * - route_parameters
   * - parent
   * - additional classes.
   *
   * @param array $collection
   *   The collection to create a link for.
   * @param string $route_name
   *   The route name.
   * @param array $route_parameters
   *   The route parameters.
   */
  protected function createCollectionLink(array $collection, string $route_name, array $route_parameters = []): void {

    $route_parameters = [
      'collection' => $collection['id'],
    ] + $route_parameters;

    if ($this->isRouteAvailable($route_name)) {
      $this->links[$collection['id']] = [
        'title' => $collection['label'],
        'route_name' => $route_name,
        'route_parameters' => $route_parameters,
        'menu_name' => 'admin',
        'parent' => $collection['parent'],
        'weight' => $collection['weight'] ?? 0,
        'options' => [
          'attributes' => [
            'class' => [
              'admin-toolbar-content--collection',
              'admin-toolbar-content--collection--' . $this->getPluginId(),
              'admin-toolbar-content--collection--' . $this->getPluginId() . '--' . str_replace('.', '--', $collection['id']),
            ],
          ],
        ],
      ] + $this->baseMenuLinkPluginDefinition;
    }

  }

  /**
   * Helper to get the translation of an item in a collection.
   *
   * @param mixed $item
   *   The item.
   *
   * @return \Drupal\Core\StringTranslation\TranslatableMarkup
   *   The translated title.
   */
  protected function getItemTitle(mixed $item): TranslatableMarkup {
    return $item->label();
  }

  /**
   * Creates the item links for a collection.
   *
   * @param string $route_name
   *   The route name.
   * @param string $route_item_parameter
   *   The route item parameter.
   */
  protected function createItemLinks(string $route_name, string $route_item_parameter): void {

    $items = $this->getItems();

    foreach ($items as $item) {
      $this->createItemLink($item, $route_name, $route_item_parameter);
    }

  }

  /**
   * Creates a single item link for a collection.
   *
   * @param mixed $item
   *   The item to create the link for.
   * @param string $route_name
   *   The route name.
   * @param string $route_item_parameter
   *   The route item parameter.
   */
  protected function createItemLink(mixed $item, string $route_name, string $route_item_parameter): void {

    if ($this->isRouteAvailable($route_name)) {

      // Find the collection for the item and default to the plugin id
      // if not found.
      $collection = $this->getItemCollection($item);

      $definition = $this->getPluginDefinition();

      $route_parameters = [
        $route_item_parameter => $item->id(),
      ];

      if ($collection['id'] !== $this->getPluginId()) {
        $route_parameters['collection'] = $collection['id'];
      }

      $this->links[$collection['id'] . '.' . $item->id()] = [
        'class' => 'Drupal\admin_toolbar_tools\Plugin\Menu\MenuLinkEntity',
        // 'title' => $this->getItemTitle($item),
        'route_name' => $route_name,
        'route_parameters' => $route_parameters,
        'menu_name' => 'admin',
        'parent' => $this->baseMenuLinkPluginDefinition['id'] . ':' . $collection['id'],
        'options' => [
          'attributes' => [
            'class' => [
              'admin-toolbar-content--edit-item',
              'admin-toolbar-content--edit-item--' . $item->id(),
            ],
          ],
        ],
        'metadata' => [
          'entity_type' => $definition['entity_type'],
          'entity_id' => $item->id(),
        ],
      ] + $this->baseMenuLinkPluginDefinition;
    }
  }

  /**
   * Creates the add new item links.
   *
   * @param string $route_name
   *   The route name.
   * @param array $route_parameters
   *   The route parameters.
   */
  protected function createItemAddLinks(string $route_name, array $route_parameters = []): void {

    $items = $this->getItems();

    foreach ($items as $item) {
      $this->createItemAddLink($item, $route_name, $route_parameters);
    }

  }

  /**
   * Creates a single add new item link for an existing item link.
   *
   * CreateItemLinks needs to run first.
   *
   * @param mixed $item
   *   The item to create the link for.
   * @param string $route_name
   *   The route name.
   * @param array $route_parameters
   *   The route parameters.
   */
  protected function createItemAddLink(mixed $item, string $route_name, array $route_parameters = []): void {

    // Find the collection for the item and default to the plugin id
    // if not found.
    $collection = $this->getItemCollection($item);

    if (isset($this->links[$collection['id'] . '.' . $item->id()])) {

      if ($this->isRouteAvailable($route_name)) {

        $definition = $this->getPluginDefinition();

        $route_parameters = [
          $definition['entity_type'] => $item->id(),
        ] + $route_parameters;

        $this->links[$collection['id'] . '.' . $item->id() . '.add'] = [
          'title' => $this->t('Add new'),
          'route_name' => $route_name,
          'route_parameters' => $route_parameters,
          'menu_name' => 'admin',
          'parent' => $this->baseMenuLinkPluginDefinition['id'] . ':' . $collection['id'] . '.' . $item->id(),
          'options' => [
            'attributes' => [
              'class' => [
                'admin-toolbar-content--add-new-item',
                'admin-toolbar-content--add-new-item--' . $item->id(),
              ],
            ],
          ],
          'metadata' => [
            'entity_type' => $definition['entity_type'],
            'entity_id' => $item->id(),
          ],
        ] + $this->baseMenuLinkPluginDefinition;
      }
    }
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc