wse-1.0.x-dev/modules/wse_menu/src/EventSubscriber/WseMenuRequestSubscriber.php

modules/wse_menu/src/EventSubscriber/WseMenuRequestSubscriber.php
<?php

declare(strict_types=1);

namespace Drupal\wse_menu\EventSubscriber;

use Drupal\Core\Lock\LockBackendInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Utility\Error;
use Drupal\workspaces\WorkspaceManagerInterface;
use Drupal\wse_menu\WseMenuTreeStorageInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;

/**
 * Provides a event subscriber for rebuilding the workspace menu tree.
 */
class WseMenuRequestSubscriber implements EventSubscriberInterface {

  use StringTranslationTrait;

  /**
   * Name of the flags state global lock.
   */
  public const LOCK_REBUILD = 'wse_menu_tree_rebuild';

  /**
   * Name of the flags state.
   */
  public const STATE_REBUILD_FLAGS = 'wse_menu_tree_needs_rebuild';

  public function __construct(
    protected readonly StateInterface $state,
    protected readonly WorkspaceManagerInterface $workspaceManager,
    protected readonly WseMenuTreeStorageInterface $menuTreeStorage,
    protected readonly MessengerInterface $messenger,
    protected readonly LoggerInterface $logger,
    protected readonly LockBackendInterface $lock,
  ) {}

  /**
   * Rebuilds the workspace menu tree if necessary.
   *
   * @param \Symfony\Component\HttpKernel\Event\RequestEvent $event
   *   An event object.
   */
  public function onKernelRequest(RequestEvent $event): void {
    if ($this->workspaceManager->hasActiveWorkspace()) {
      $rebuild_menu = $this->state->get(static::STATE_REBUILD_FLAGS, []);
      $workspace_id = $this->workspaceManager->getActiveWorkspace()->id();
      $workspace_lock_name = 'wse_menu_tree_rebuild_' . $workspace_id;
      // Acquire a ws-specific lock here to avoid performing the rebuild
      // multiple times, and just skip this logic altogether if the lock cannot
      // be acquired, knowing that menu is being rebuilt in another request.
      if (!empty($rebuild_menu[$workspace_id]) && $this->lock->acquire($workspace_lock_name)) {
        try {
          $this->menuTreeStorage->rebuildWorkspaceMenuTree($this->workspaceManager->getActiveWorkspace());
          $this->messenger->addStatus($this->t('The workspace menu tree has been rebuilt.'));

          // Since the state value contains multiple flags, we should wait
          // until we can acquire a global lock, fetch the value from state
          // again, and only then we can safely set it, otherwise we may
          // override other flag values having been updated while rebuilding
          // was happening.
          while (!$this->lock->acquire(static::LOCK_REBUILD)) {
            $this->lock->wait(static::LOCK_REBUILD);
          }

          $rebuild_menu = $this->state->get(static::STATE_REBUILD_FLAGS, []);
          $rebuild_menu[$workspace_id] = FALSE;
          $this->state->set(static::STATE_REBUILD_FLAGS, $rebuild_menu);
        }
        catch (\Exception $e) {
          Error::logException($this->logger, $e);
          $this->messenger->addError($this->t('The workspace menu tree could not be rebuilt. All errors have been logged.'));
        }
      }
      $this->lock->release(static::LOCK_REBUILD);
      $this->lock->release($workspace_lock_name);
    }
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents(): array {
    $events[KernelEvents::REQUEST][] = ['onKernelRequest', 0];
    return $events;
  }

}

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

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