navigation_extra-1.0.x-dev/src/Plugin/Navigation/Extra/VersionPlugin.php

src/Plugin/Navigation/Extra/VersionPlugin.php
<?php

namespace Drupal\navigation_extra\Plugin\Navigation\Extra;

use Drupal\Component\Utility\NestedArray;
use Drupal\Component\Uuid\UuidInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\InfoParserInterface;
use Drupal\Core\Extension\ModuleExtensionList;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Link;
use Drupal\Core\Menu\MenuLinkManagerInterface;
use Drupal\Core\Routing\RouteProviderInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\Url;
use Drupal\navigation_extra\NavigationExtraPluginBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Routing\Exception\RouteNotFoundException;

/**
 * An NavigationExtraPlugin for media navigation links.
 *
 * @NavigationExtraPlugin(
 *   id = "version",
 *   name = @Translation("Version"),
 *   description = @Translation("Displays a release version number and
 *   environment indicator."), weight = 0
 * )
 */
class VersionPlugin extends NavigationExtraPluginBase {

  /**
   * The UUID service.
   *
   * @var \Drupal\Component\Uuid\UuidInterface
   */
  protected UuidInterface $uuidService;

  /**
   * The ModuleExtensionList service.
   *
   * @var \Drupal\Core\Extension\ModuleExtensionList
   */
  protected ModuleExtensionList $moduleExtensionList;

  /**
   * The InfoParser service.
   *
   * @var \Drupal\Core\Extension\InfoParserInterface
   */
  protected InfoParserInterface $infoParser;

  /**
   * The menu link manager service.
   *
   * @var \Drupal\Core\Menu\MenuLinkManagerInterface
   */
  protected MenuLinkManagerInterface $menuLinkManager;

  /**
   * The file system service.
   *
   * @var \Drupal\Core\File\FileSystemInterface
   */
  protected FileSystemInterface $fileSystem;

  /**
   * The current installed profile.
   *
   * @var string
   */
  protected string $installProfile;

  /**
   * The request stack used to get the current request.
   *
   * @var \Symfony\Component\HttpFoundation\RequestStack
   */
  private RequestStack $requestStack;

  /**
   * 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.
   * @param \Drupal\Component\Uuid\UuidInterface $uuid_service
   *   The UUID service.
   * @param \Drupal\Core\Extension\InfoParserInterface $info_parser
   *   The InfoParser service.
   * @param \Drupal\Core\Extension\ModuleExtensionList $module_extension_list
   *   The ModuleExtensionList service.
   * @param \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager
   *   The menu link manager service.
   * @param \Drupal\Core\File\FileSystemInterface $file_system
   *   The file system service.
   * @param string $install_profile
   *   The name of the install profile.
   * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
   *   The request stack used to determine the current time.
   */
  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,
    UuidInterface $uuid_service,
    InfoParserInterface $info_parser,
    ModuleExtensionList $module_extension_list,
    MenuLinkManagerInterface $menu_link_manager,
    FileSystemInterface $file_system,
    string $install_profile,
    RequestStack $request_stack,
  ) {
    parent::__construct(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $languageManager,
      $current_user,
      $entity_type_manager,
      $route_provider,
      $module_handler,
      $config_factory,
      $entity_repository
    );

    $this->uuidService = $uuid_service;
    $this->infoParser = $info_parser;
    $this->moduleExtensionList = $module_extension_list;
    $this->menuLinkManager = $menu_link_manager;
    $this->fileSystem = $file_system;
    $this->installProfile = $install_profile;
    $this->requestStack = $request_stack;
  }

  /**
   * {@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'),
      $container->get('uuid'),
      $container->get('info_parser'),
      $container->get('extension.list.module'),
      $container->get('plugin.manager.menu.link'),
      $container->get('file_system'),
      $container->getParameter('install_profile'),
      $container->get('request_stack')
    );
  }

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

    // Weight doesn't matter for version settings.
    $elements['weight']['#type'] = 'hidden';
    $elements['weight']['#value'] = 0;

    $elements['info'] = [
      '#type' => 'html_tag',
      '#tag' => 'div',
      '#attributes' => [],
      '#value' => $this->t('Important! Once enabled, goto %url and add a Navigation Extra - Version block to the navigation area.', [
        '%url' => Link::fromTextAndUrl($this->t('Navigation blocks'), Url::fromUserInput('/admin/config/user-interface/navigation-block'))
          ->toString(),
      ]),
    ];

    $elements += $this->buildConfigFormSourceFields($form, $form_state);

    $elements += $this->buildConfigFormOutputFields($form, $form_state);

    $triggering_element = $form_state->getTriggeringElement();

    $elements['environments'] = [
      '#type' => 'details',
      '#open' => (bool) $triggering_element,
      '#title' => $this->t('Environments'),
      '#prefix' => '<div id="navigation-extra-version-environments-wrapper">',
      '#suffix' => '</div>',
    ];

    if ($triggering_element) {
      $parents = $form_state->getTriggeringElement()['#parents'];
      $action = array_pop($parents);
      if ($action == 'delete') {
        array_pop($parents);
      }
      $environments = $form_state->getValue($parents);
    }
    else {
      $environments = $this->config->get('plugins.version.environments');
    }

    foreach ($environments ?? [] as $id => $environment) {
      $elements['environments'][$id] = $this->buildConfigFormEnvironmentFields($form, $form_state, $environment, $id);
    }

    $elements['environments']['add'] = [
      '#type' => 'submit',
      '#value' => (string) $this->t('Add environment'),
      '#submit' => [[$this, 'submitAddEnvironment']],
      '#ajax' => [
        'callback' => [$this, 'ajaxUpdateEnvironments'],
        'wrapper' => 'navigation-extra-version-environments-wrapper',
      ],
      '#name' => 'navigation-extra-version-environments-add',
    ];

    return $elements;
  }

  /**
   * Build Config Form Source Fields function.
   */
  protected function buildConfigFormSourceFields(array &$form, FormStateInterface $form_state): array {
    $elements = [];

    $elements['source'] = [
      '#type' => 'details',
      '#title' => $this->t('Source'),
    ];

    $elements['source']['provider'] = [
      '#type' => 'select',
      '#options' => [
        '' => $this->t('None'),
        'git_tag' => $this->t('Git tag'),
        'module' => $this->t('Module info'),
        'file' => $this->t('File'),
        'env' => $this->t('Environment variable'),
      ],
      '#title' => $this->t('Provider'),
      '#description' => $this->t('The source provider to grab the version information from.'),
      '#default_value' => $this->config->get("plugins.version.source.provider") ?? '',
    ];

    /** @var \Drupal\Core\Extension\ExtensionList $list */
    $list = $this->moduleExtensionList->getList();
    $list_options = [];
    foreach ($list as $name => $item) {
      $list_options[$name] = $item->getName();
    }

    $elements['source']['module'] = [
      '#type' => 'select',
      '#options' => $list_options,
      '#title' => $this->t('Module'),
      '#description' => $this->t('Uses the module info.yml version setting.'),
      '#default_value' => $this->config->get("plugins.version.source.module") ?? $this->installProfile,
      '#states' => [
        'visible' => [
          [
            ':input[name="version[source][provider]"]' => ['value' => 'module'],
          ],
        ],
      ],
    ];

    $elements['source']['file'] = [
      '#type' => 'textfield',
      '#title' => $this->t('File'),
      '#description' => $this->t('The file to grab the version information from. Use a path relative to the webroot.'),
      '#default_value' => $this->config->get("plugins.version.source.file") ?? '',
      '#states' => [
        'visible' => [
          [
            ':input[name="version[source][provider]"]' => ['value' => 'file'],
          ],
        ],
      ],
    ];

    $elements['source']['env'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Environment variable'),
      '#description' => $this->t('The environment variable to grab the version information from.'),
      '#default_value' => $this->config->get("plugins.version.source.env") ?? '',
      '#states' => [
        'visible' => [
          [
            ':input[name="version[source][provider]"]' => ['value' => 'env'],
          ],
        ],
      ],
    ];

    $elements['source']['pattern'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Pattern'),
      '#description' => $this->t('A regex pattern to grab the version information from the source. See <a href="https://www.php.net/manual/en/function.preg-replace.php">preg_replace</a> for details.'),
      '#placeholder' => '/^(\d+\.\d+\.\d+)$/',
      '#default_value' => $this->config->get("plugins.version.source.pattern") ?? '',
      '#states' => [
        'invisible' => [
          [
            ':input[name="version[source][provider]"]' => [
              ['value' => 'module'],
              'or',
              ['value' => ''],
            ],
          ],
        ],
      ],
    ];

    $elements['source']['format'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Format'),
      '#description' => $this->t('The source format string. Use capture groups from the source pattern. See <a href="https://www.php.net/manual/en/function.preg-replace.php">preg_replace</a> for details.'),
      '#placeholder' => '$1',
      '#default_value' => $this->config->get("plugins.version.source.format") ?? $this->config->get("plugins.version.source.format"),
      '#states' => [
        'invisible' => [
          [
            ':input[name="version[source][provider]"]' => [
              ['value' => 'module'],
              'or',
              ['value' => ''],
            ],
          ],
        ],
      ],
    ];

    return $elements;
  }

  /**
   * Build config form output fields function.
   */
  protected function buildConfigFormOutputFields(array &$form, FormStateInterface $form_state): array {
    $elements['output'] = [
      '#type' => 'details',
      '#title' => $this->t('Output'),
    ];

    $elements['output']['title'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Title format'),
      '#description' => $this->t('The title format string. You can use %version, %drupal and %env as available tokens.'),
      '#placeholder' => '%drupal - %version',
      '#default_value' => $this->config->get("plugins.version.output.title") ?? '',
    ];

    $elements['output']['description'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Description/tooltip format'),
      '#description' => $this->t('The description format string. You can use %version, %drupal and %env as available tokens.'),
      '#placeholder' => '%drupal - %version',
      '#default_value' => $this->config->get("plugins.version.output.description") ?? '',
    ];

    $elements['output']['url'] = [
      '#type' => 'textfield',
      '#title' => $this->t('URL'),
      '#description' => $this->t('The output format url. Use %version as a token. You can also use a valid route name.'),
      '#placeholder' => 'system.status',
      '#default_value' => $this->config->get("plugins.version.output.url") ?? $this->config->get("plugins.version.output.url"),
    ];

    $elements['output']['updates'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Show updates'),
      '#description' => $this->t('Notify user when there are updates available.'),
      '#default_value' => $this->config->get("plugins.version.output.updates") ?? '',
    ];

    return $elements;
  }

  /**
   * Build config form environment fields function.
   */
  protected function buildConfigFormEnvironmentFields(array &$form, FormStateInterface $form_state, $environment = [], $id = 0): array {
    $default = $this->getDefaultEnvironment();

    return [
      '#type' => 'details',
      '#title' => !empty($environment['name']) ? $environment['name'] : $this->t('Environment %id', ['%id' => $id]),
      '#open' => FALSE,
      'name' => [
        '#type' => 'textfield',
        '#title' => $this->t('Name'),
        '#description' => $this->t('The name that should be displayed in the toolbar using the %env token.'),
        '#default_value' => $environment['name'] ?? $default['name'],
      ],
      'color' => [
        '#type' => 'color',
        '#title' => $this->t('Color'),
        '#description' => $this->t('Pick a text color for the toolbar logo and version item'),
        '#default_value' => $environment['color'] ?? $default['color'],
      ],
      'background' => [
        '#type' => 'color',
        '#title' => $this->t('Background'),
        '#description' => $this->t('Pick a background color for the toolbar logo and version item'),
        '#default_value' => $environment['background'] ?? $default['background'],
      ],
      'source' => [
        '#type' => 'details',
        '#open' => TRUE,
        '#title' => $this->t('Source'),
        'provider' => [
          '#type' => 'select',
          '#title' => $this->t('Provider'),
          '#options' => [
            'domain' => $this->t('Domain'),
            'env' => $this->t('Environment variable'),
            'header' => $this->t('Header'),
          ],
          '#description' => $this->t('Where to get the environment value from.'),
          '#default_value' => $environment['source']['provider'] ?? $default['source']['provider'],
        ],
        'env' => [
          '#type' => 'textfield',
          '#title' => $this->t('Environment variable'),
          '#description' => $this->t('Enter the name of the $_ENV key containing the environment value'),
          '#placeholder' => 'APPLICATION_ENV',
          '#default_value' => $environment['source']['env'] ?? '',
          '#states' => [
            'visible' => [
              [
                ':input[name="version[environments][' . $id . '][source][provider]"]' => ['value' => 'env'],
              ],
            ],
          ],
        ],
        'header' => [
          '#type' => 'textfield',
          '#title' => $this->t('Header'),
          '#description' => $this->t('Enter the name of the header containing the environment value'),
          '#placeholder' => 'APPLICATION_ENV',
          '#default_value' => $environment['source']['header'] ?? '',
          '#states' => [
            'visible' => [
              [
                ':input[name="version[environments][' . $id . '][source][provider]"]' => ['value' => 'header'],
              ],
            ],
          ],
        ],
        'pattern' => [
          '#type' => 'textfield',
          '#title' => $this->t('Pattern'),
          '#description' => $this->t('A regex pattern to match the value of the source. See <a href="https://www.php.net/manual/en/function.preg-match.php">preg_match</a> for details.'),
          '#default_value' => $environment['source']['pattern'] ?? $default['source']['pattern'],
        ],
      ],
      "delete" => [
        '#type' => 'submit',
        '#value' => (string) $this->t('Delete'),
        '#submit' => [[$this, 'submitDeleteEnvironment']],
        '#ajax' => [
          'callback' => [$this, 'ajaxUpdateEnvironments'],
          'wrapper' => 'navigation-extra-version-environments-wrapper',
        ],
        '#name' => 'navigation-extra-version-environments-delete-' . $id,
      ],
    ];
  }

  /**
   * Submit add environment function.
   */
  public static function submitAddEnvironment(array &$form, FormStateInterface $form_state): void {
    $triggering_element = $form_state->getTriggeringElement();
    $parents = $triggering_element['#parents'];
    array_pop($parents);

    $environments = $form_state->getValue($parents);
    unset($environments['add']);
    $environments[] = [];
    $form_state->setValue($parents, $environments);

    $form_state->setRebuild();
  }

  /**
   * Submit delete environment function.
   */
  public static function submitDeleteEnvironment(array &$form, FormStateInterface $form_state): void {
    $triggering_element = $form_state->getTriggeringElement();
    $parents = $triggering_element['#parents'];
    array_pop($parents);
    $id = array_pop($parents);

    $environments = $form_state->getValue($parents);
    unset($environments[$id]);
    $form_state->setValue($parents, $environments);

    $form_state->setRebuild();
  }

  /**
   * AJAX update environments function.
   */
  public static function ajaxUpdateEnvironments(array &$form, FormStateInterface $form_state) {
    $triggering_element = $form_state->getTriggeringElement();

    $array_parents = $triggering_element['#array_parents'];
    $action = array_pop($array_parents);
    if ($action === 'delete') {
      array_pop($array_parents);
    }

    return NestedArray::getValue($form, $array_parents);
  }

  /**
   * Get the version string.
   *
   * @return string
   *   Return the version.
   */
  public function getVersion(): string {
    return match ($this->config->get("plugins.version.source.provider") ?? '') {
      'git_tag' => $this->getVersionFromGitTag(),
      'module' => $this->getVersionFromModule(),
      'env' => $this->getVersionFromEnvironmentVariable(),
      'file' => $this->getVersionFromFile(),
      default => '',
    };
  }

  /**
   * Get the formatted version string.
   *
   * @return string
   *   Return the formatted version.
   */
  public function getVersionFormatted($format = 'title'): string {
    $version = $this->getVersion();

    $environment = $this->getEnvironment();
    $env = $environment['name'] ?? '';

    $drupal = \Drupal::VERSION;

    $format = !empty($this->config->get("plugins.version.output.$format"))
      ? $this->config->get("plugins.version.output.$format")
      : '%drupal - %version - %env';

    $count = 0;

    $version = str_replace(['%version', '%drupal', '%env'], [
      $version,
      $drupal,
      $env,
    ], $format, $count);
    $version = str_replace('-  -', '-', $version);
    $version = trim($version, " -");

    return $count ? $version : '';
  }

  /**
   * Get the url for linking to a release note page.
   *
   * @return string
   *   Return the version url.
   */
  public function getVersionUrl(): string {
    $version = $this->getVersion();

    $url = !empty($this->config->get("plugins.version.output.url"))
      ? $this->config->get("plugins.version.output.url")
      : 'system.status';

    return str_replace('%version', $version, $url);
  }

  /**
   * Get the module version from configured module or install profile.
   *
   * @return string
   *   Return the version string from the configured source module or profile.
   */
  public function getVersionFromModule(): string {
    $module = $this->config->get("plugins.version.source.module") ?? $this->installProfile;

    $info = $this->moduleExtensionList->getExtensionInfo($module);

    return $this->getVersionFromString($info['version'] ?? '');
  }

  /**
   * Get the version from a git tag.
   *
   * @return string
   *   Return the version string from the configured git tag.
   */
  public function getVersionFromGitTag(): string {
    $files = glob($this->fileSystem->realpath(DRUPAL_ROOT . '/../.git/refs/tags/*'));

    $tag = basename(end($files));

    return $this->getVersionFromString($tag);
  }

  /**
   * Get the version from a line in a file.
   *
   * @return string
   *   Return the version string from the configured git tag.
   */
  public function getVersionFromFile(): string {
    $version = '';

    $file = $this->config->get("plugins.version.source.file") ?? '/';
    $file_path = $this->fileSystem->realpath(DRUPAL_ROOT . $file);

    if ($file_path) {
      $pattern = !empty($this->config->get("plugins.version.source.pattern"))
        ? $this->config->get("plugins.version.source.pattern")
        : '/^(\d+\.\d+\.\d+)$/';

      $fh = fopen($file_path, 'r');

      while (!feof($fh)) {
        $line = fgets($fh, 4096);

        if (preg_match($pattern, $line)) {
          $format = !empty($this->config->get("plugins.version.source.format"))
            ? $this->config->get("plugins.version.source.format")
            : '$1';

          $version = preg_replace($pattern, $format, $line) ?? '';

          break;
        }
      }

      fclose($fh);
    }

    return $version;
  }

  /**
   * Get the version from configured environment variable.
   *
   * @return string
   *   Return the version string from the configured environment variable.
   */
  public function getVersionFromEnvironmentVariable(): string {
    $variable = $this->config->get("plugins.version.source.env") ?? 'version';
    $value = getenv($variable);

    return $this->getVersionFromString($value);
  }

  /**
   * Helper to grab a version from a string value.
   *
   * @param string|null $string
   *   The source string to grab the version from.
   *
   * @return string
   *   Returns the version as found by the configured source pattern and format.
   */
  protected function getVersionFromString(?string $string): string {
    $pattern = !empty($this->config->get("plugins.version.source.pattern"))
      ? $this->config->get("plugins.version.source.pattern")
      : '/^[^0-9]*(\d+\.\d+\.\d+)[^0-9]*$/';

    $format = !empty($this->config->get("plugins.version.source.format"))
      ? $this->config->get("plugins.version.source.format")
      : '$1';

    return (string) preg_replace($pattern, $format, $string ?: '') ?? '';
  }

  /**
   * Get the environment config.
   *
   * @return array
   *   Return the environment config.
   */
  public function getEnvironment(): array {
    $match = [];

    $environments = $this->config->get("plugins.version.environments") ?? [];
    foreach ($environments as $environment) {
      $match = match ($environment['source']['provider']) {
        'header' => $this->getEnvironmentFromHeader($environment),
        'env' => $this->getEnvironmentFromEnvironmentVariable($environment),
        'domain' => $this->getEnvironmentFromDomain($environment),
        default => [],
      };

      if ($match) {
        break;
      }
    }

    if (empty($match)) {
      $match = $this->getDefaultEnvironment();
    }

    return $match;
  }

  /**
   * Get the default environment settings.
   *
   * @return array
   *   An array with default values for an environment.
   */
  protected function getDefaultEnvironment(): array {
    return [
      'background' => '#0000FF',
      'color' => '#FFFFFF',
      'name' => '',
      'source' => [
        'provider' => 'domain',
        'pattern' => '/.*/',
      ],
    ];
  }

  /**
   * Get environment from header function.
   */
  public function getEnvironmentFromHeader($environment): array {
    $header = $environment['source']['header'] ?? '';
    $value = $_SERVER[$header] ?? '';
    $pattern = !empty($environment['source']['pattern']) ? $environment['source']['pattern'] : '/no-valid-pattern/';

    return preg_match($pattern, $value) ? $environment : [];
  }

  /**
   * Get environment from environment variable function.
   */
  public function getEnvironmentFromEnvironmentVariable($environment): array {
    $variable = $environment['source']['env'] ?? '';
    $value = getenv($variable) ?? '';
    $pattern = !empty($environment['source']['pattern']) ? $environment['source']['pattern'] : '/no-valid-pattern/';

    return preg_match($pattern, $value) ? $environment : [];
  }

  /**
   * Get environment from domain function.
   */
  public function getEnvironmentFromDomain($environment): array {
    $value = $this->requestStack->getCurrentRequest()->getHost();
    $pattern = !empty($environment['source']['pattern']) ? $environment['source']['pattern'] : '/no-valid-pattern/';

    return preg_match($pattern, $value) ? $environment : [];
  }

  /**
   * {@inheritdoc}
   */
  public function alterDiscoveredMenuLinks(array &$links): void {
    $linkSettings = [
      'menu_name' => 'navigation_extra_version',
      'title' => $this->getVersionFormatted(),
      'description' => $this->getVersionFormatted('description') ?: $this->getVersionFormatted(),
      'weight' => -100,
      'options' => [
        'icon' => [
          'pack_id' => 'navigation_extra',
          'icon_id' => 'version',
          'settings' => [
            'class' => 'toolbar-button__icon',
            'size' => 25,
          ],
        ],
        'attributes' => [
          'class' => [
            'navigation-extra--version',
          ],
        ],
      ],
    ];

    $url = $this->getVersionUrl();
    $fallback = '<front>';
    if (empty($url)) {
      // Everyone has access to <front>, system.status not.
      $url = $fallback;
    }

    $isURL = FALSE;
    $isRoute = FALSE;

    try {
      Url::fromUri($url);
      $linkSettings['url'] = $url;

      $isURL = TRUE;
    }
    catch (\Exception) {
    }

    if (!$isURL) {
      try {
        $this->routeProvider->getRouteByName($url);
        $linkSettings['route_name'] = $url;

        $isRoute = TRUE;
      }
      catch (RouteNotFoundException) {
      }
    }

    if (!$isRoute && !$isURL) {
      $linkSettings['route_name'] = $fallback;
    }

    // Create the root element if it does not exist.
    // We will add it by default to the administration menu.
    $this->addLink('navigation.version', $linkSettings, $links);
  }

  /**
   * {@inheritdoc}
   */
  public function pageAttachments(&$page): void {
    $page['#attached']['library'][] = 'navigation_extra/navigation_extra_version';

    $environment = $this->getEnvironment();
    $page['#attached']['drupalSettings']['navigation_extra']['environment'] = $environment;
  }

}

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

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