countdown-8.x-1.8/src/Controller/CountdownAdminController.php

src/Controller/CountdownAdminController.php
<?php

declare(strict_types=1);

namespace Drupal\countdown\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Link;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Url;
use Drupal\countdown\CountdownConstants;
use Drupal\countdown\CountdownLibraryPluginManager;
use Drupal\countdown\Form\CountdownSettings;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\RequestStack;

/**
 * Controller for the Countdown admin pages.
 *
 * Provides the settings page with library status display
 * and configuration form.
 *
 * @package Drupal\countdown\Controller
 */
class CountdownAdminController extends ControllerBase {

  /**
   * The plugin manager.
   *
   * @var \Drupal\countdown\CountdownLibraryPluginManager
   */
  protected CountdownLibraryPluginManager $pluginManager;

  /**
   * The request stack.
   *
   * @var \Symfony\Component\HttpFoundation\RequestStack
   */
  protected RequestStack $requestStack;

  /**
   * The renderer service.
   *
   * @var \Drupal\Core\Render\RendererInterface
   */
  protected RendererInterface $renderer;

  /**
   * Constructs a CountdownAdminController object.
   *
   * @param \Drupal\countdown\CountdownLibraryPluginManager $plugin_manager
   *   The plugin manager.
   * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
   *   The request stack.
   * @param \Drupal\Core\Render\RendererInterface $renderer
   *   The renderer service.
   */
  public function __construct(CountdownLibraryPluginManager $plugin_manager, RequestStack $request_stack, RendererInterface $renderer) {
    $this->pluginManager = $plugin_manager;
    $this->requestStack = $request_stack;
    $this->renderer = $renderer;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('plugin.manager.countdown_library'),
      $container->get('request_stack'),
      $container->get('renderer')
    );
  }

  /**
   * Settings page: renders library status block and settings form.
   *
   * @return array|\Symfony\Component\HttpFoundation\RedirectResponse
   *   Render array for the settings page or redirect response.
   */
  public function settingsPage() {
    $request = $this->requestStack->getCurrentRequest();

    // Optional refresh functionality.
    if ($request && $request->query->get('refresh') === '1') {
      $this->pluginManager->resetAllCaches();
      $this->messenger()->addStatus($this->t('Library status refreshed.'));

      // Redirect to remove the query parameter.
      $url = Url::fromRoute('countdown.settings');
      return new RedirectResponse($url->toString());
    }

    // Build the page content.
    $build = [];

    // Add page title.
    $build['#title'] = $this->t('Countdown settings');

    // Build status block.
    $build['status'] = $this->buildLibraryStatusBlock();

    // Build the settings form.
    $build['form'] = $this->formBuilder()->getForm(CountdownSettings::class);

    // Attach needed libraries.
    $build['#attached']['library'][] = 'core/drupal.collapse';
    $build['#attached']['library'][] = 'countdown/admin';

    // Add cache contexts and tags.
    $build['#cache'] = [
      'contexts' => ['user.permissions'],
      'tags' => [CountdownConstants::CACHE_TAG_SETTINGS],
    ];

    return $build;
  }

  /**
   * Builds the library status block.
   *
   * @return array
   *   Render array for status block.
   */
  protected function buildLibraryStatusBlock(): array {
    // Get all plugins and their statuses.
    $plugin_statuses = $this->pluginManager->getAllPluginStatuses();
    $config = $this->config('countdown.settings');
    $active_library = $config->get('library');

    $rows = [];

    foreach ($plugin_statuses as $plugin_id => $status_info) {
      /** @var \Drupal\countdown\Plugin\CountdownLibraryPluginInterface $plugin */
      $plugin = $status_info['plugin'];

      // Determine status classes and text.
      $status_class = 'project-update__status--not-supported';
      $gin_status = 'gin-status--danger';
      $status_text = $this->t('Not Installed');

      if ($plugin->isInstalled()) {
        if ($status_info['version_status'] === 'ok') {
          $status_class = 'project-update__status--current';
          $gin_status = 'gin-status--success';
          $status_text = $this->t('Installed');
        }
        elseif ($status_info['version_status'] === 'outdated') {
          $status_class = 'project-update__status--not-current';
          $gin_status = 'gin-status--warning';
          $status_text = $this->t('Outdated');
        }
        else {
          $status_class = 'project-update__status--not-supported';
          $gin_status = 'gin-status--warning';
          $status_text = $this->t('Unknown Version');
        }
      }

      // Add active indicator if this is the active library.
      if ($plugin_id === $active_library) {
        $status_text .= ' (' . $this->t('Active') . ')';
      }

      // Build status pill.
      $status_element = [
        '#type' => 'html_tag',
        '#tag' => 'div',
        '#attributes' => [
          'class' => [
            'project-update__status',
            $status_class,
            'gin-status',
            $gin_status,
          ],
        ],
        '#value' => '<span class="gin-status-icon"></span><span>' . $status_text . '</span>',
        '#allowed_tags' => ['span', 'div'],
      ];

      // Version display.
      $version_display = $this->buildVersionDisplay($plugin, $status_info);

      // Path / Download element.
      $path_element = $this->buildPathElement($plugin);

      // Name cell with metadata.
      $library_cell = $this->buildLibraryCell($plugin, $plugin_id);

      // Version cell with HTML support.
      $version_cell = [
        '#type' => 'html_tag',
        '#tag' => 'div',
        '#value' => $version_display,
        '#allowed_tags' => ['span'],
      ];

      // Build table row.
      $row = [
        'data' => [
          ['data' => $library_cell],
          ['data' => $status_element],
          ['data' => $version_cell, 'class' => ['project-update__title']],
          ['data' => $path_element],
        ],
        'class' => [$this->getRowClass($plugin, $status_info)],
      ];

      // Add row attributes for active library.
      if ($plugin_id === $active_library) {
        $row['class'][] = 'countdown-active-library';
      }

      $rows[] = $row;
    }

    // Build table.
    $table = [
      '#type' => 'table',
      '#header' => [
        $this->t('Library'),
        $this->t('Status'),
        $this->t('Version'),
        $this->t('Path / Installation'),
      ],
      '#rows' => $rows,
      '#empty' => $this->t('No libraries found.'),
      '#attributes' => ['class' => ['countdown-library-status']],
    ];

    // Build refresh link.
    $refresh_url = Url::fromRoute('countdown.settings', [], [
      'query' => ['refresh' => '1'],
      'attributes' => ['class' => ['button', 'button--small']],
    ]);
    $refresh_link = Link::fromTextAndUrl($this->t('Refresh library status'), $refresh_url)->toRenderable();

    // Build statistics summary.
    $summary = $this->buildStatisticsSummary();

    // Assemble the complete status block.
    return [
      '#type' => 'container',
      '#attributes' => ['class' => ['countdown-library-status', 'gin-layer-wrapper']],

      'heading' => [
        '#type' => 'html_tag',
        '#tag' => 'h2',
        '#value' => $this->t('Library Status'),
        '#attributes' => ['class' => ['system-status-general-info__header']],
      ],

      'details' => [
        '#type' => 'details',
        // Use the persisted hide config to determine initial open state.
        '#open' => !$config->get('hide'),
        '#title' => $this->t('Countdown Libraries'),
        '#attributes' => [
          'class' => ['claro-details', 'claro-details--system-status-report', 'countdown-library-status'],
        ],

        'wrapper' => [
          '#type' => 'container',
          '#attributes' => [
            'class' => ['claro-details__wrapper', 'claro-details__wrapper--system-status-report'],
          ],
          'summary' => $summary,
          'table' => $table,
          'refresh' => $refresh_link,
        ],
      ],

      '#attached' => [
        'library' => ['countdown/admin'],
      ],
    ];
  }

  /**
   * Build version display for a library.
   *
   * @param \Drupal\countdown\Plugin\CountdownLibraryPluginInterface $plugin
   *   The plugin instance.
   * @param array $status_info
   *   Status information array.
   *
   * @return string
   *   HTML string for version display.
   */
  protected function buildVersionDisplay($plugin, array $status_info): string {
    if ($plugin->isInstalled()) {
      $installed_version = $plugin->getInstalledVersion();
      $required_version = $plugin->getRequiredVersion();

      if ($installed_version) {
        $version_display = $installed_version;

        // Add comparison with required version if applicable.
        if ($required_version && $installed_version !== $required_version) {
          if (!$plugin->versionMeetsRequirements()) {
            $version_display .= ' <span class="color-error">(' . $this->t('min: @version', ['@version' => $required_version]) . ')</span>';
          }
        }
      }
      else {
        $version_display = '<span class="color-warning">' . $this->t('Unknown') . '</span>';
      }
    }
    else {
      // Not installed - show required version.
      if ($required_version = $plugin->getRequiredVersion()) {
        $version_display = '<span class="color-muted">' . $this->t('Required: @version', ['@version' => $required_version]) . '</span>';
      }
      else {
        $version_display = '<span class="color-muted">' . $this->t('Any version') . '</span>';
      }
    }

    return $version_display;
  }

  /**
   * Build path/download element for a library.
   *
   * @param \Drupal\countdown\Plugin\CountdownLibraryPluginInterface $plugin
   *   The plugin instance.
   *
   * @return array
   *   Render array for path element.
   */
  protected function buildPathElement($plugin): array {
    if ($plugin->isInstalled()) {
      // Show the library path.
      $path = $plugin->getLibraryPath();
      return [
        '#type' => 'html_tag',
        '#tag' => 'code',
        '#value' => $path,
        '#attributes' => ['class' => ['path']],
      ];
    }
    else {
      // Show download/install options.
      $links = [];

      // NPM package info.
      $npm_package = $plugin->getNpmPackage();
      if ($npm_package) {
        $links[] = [
          '#type' => 'html_tag',
          '#tag' => 'code',
          '#value' => 'npm install ' . $npm_package,
        ];
      }

      // Homepage link.
      $homepage = $plugin->getHomepage();
      if ($homepage) {
        $links[] = [
          '#type' => 'link',
          '#title' => $this->t('Download'),
          '#url' => Url::fromUri($homepage),
          '#attributes' => [
            'target' => '_blank',
            'rel' => 'noopener noreferrer',
            'class' => ['button', 'button--small'],
          ],
        ];
      }

      if (empty($links)) {
        return [
          '#markup' => '<em>' . $this->t('Manual installation required') . '</em>',
        ];
      }

      return [
        '#type' => 'container',
        '#attributes' => ['class' => ['install-options']],
        'items' => $links,
      ];
    }
  }

  /**
   * Build library name cell with metadata.
   *
   * @param \Drupal\countdown\Plugin\CountdownLibraryPluginInterface $plugin
   *   The plugin instance.
   * @param string $plugin_id
   *   The plugin ID.
   *
   * @return array
   *   Render array for library cell.
   */
  protected function buildLibraryCell($plugin, string $plugin_id): array {
    // Build type flag.
    $type_flag = $plugin->getType();

    if ($plugin->isExperimental()) {
      $type_flag .= ' | ' . $this->t('experimental');
    }

    // Check if plugin was added by another module.
    $definition = $this->pluginManager->getDefinition($plugin_id, FALSE);
    $provider = $definition['provider'] ?? 'countdown';
    if ($provider !== 'countdown') {
      $type_flag .= ' | ' . $provider;
    }

    $class = $plugin->isInstalled() ? 'countdown-library-status__status-title' : 'countdown-library-status__status-icon--error';

    return [
      '#type' => 'html_tag',
      '#tag' => 'div',
      '#value' =>
      '<strong>' . $plugin->getLabel() . '</strong>' .
      '<span class="gin-experimental-flag">' . $type_flag . '</span>' .
      '<br/><small>' . $plugin->getDescription() . '</small>',
      '#attributes' => ['class' => [$class]],
      '#allowed_tags' => ['div', 'span', 'strong', 'br', 'small'],
    ];
  }

  /**
   * Get row class based on plugin status.
   *
   * @param \Drupal\countdown\Plugin\CountdownLibraryPluginInterface $plugin
   *   The plugin instance.
   * @param array $status_info
   *   Status information array.
   *
   * @return string
   *   CSS class for the row.
   */
  protected function getRowClass($plugin, array $status_info): string {
    if (!$plugin->isInstalled()) {
      return 'color-error';
    }

    if ($status_info['version_status'] === 'ok') {
      return 'color-success';
    }

    return 'color-warning';
  }

  /**
   * Build statistics summary.
   *
   * @return array
   *   Render array for summary.
   */
  protected function buildStatisticsSummary(): array {
    $plugin_statuses = $this->pluginManager->getAllPluginStatuses();
    $total_libraries = count($plugin_statuses);
    $installed_plugins = $this->pluginManager->getInstalledPlugins();
    $installed_count = count($installed_plugins);
    $cdn_capable = count($this->pluginManager->getCdnCapablePlugins());

    return [
      '#type' => 'html_tag',
      '#tag' => 'div',
      '#attributes' => ['class' => ['countdown-summary']],
      '#value' => $this->t('@installed of @total libraries installed (@cdn CDN-capable) <span class="countdown-api-info form-item__description">Developers can add custom countdown libraries using the Plugin API. See countdown.api.php for documentation.</span>', [
        '@installed' => $installed_count,
        '@total' => $total_libraries,
        '@cdn' => $cdn_capable,
      ]),
    ];
  }

}

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

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