delivery-8.x-1.x-dev/src/MenuTreeStorage.php

src/MenuTreeStorage.php
<?php

namespace Drupal\delivery;

use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Cache\CacheTagsInvalidatorInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Database\Query\SelectInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Menu\MenuTreeParameters;
use Drupal\Core\Menu\MenuTreeStorage as CoreMenuTreeStorage;
use Drupal\menu_link_content\Entity\MenuLinkContent;
use Drupal\workspaces\WorkspaceAssociationInterface;
use Drupal\workspaces\WorkspaceManagerInterface;

/**
 * Overrides the default menu storage to provide workspace-specific menu links.
 */
class MenuTreeStorage extends CoreMenuTreeStorage {

  /**
   * The workspace manager service.
   *
   * @var \Drupal\workspaces\WorkspaceManagerInterface
   */
  protected $workspaceManager;

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

  /**
   * The workspace association service.
   *
   * @var \Drupal\workspaces\WorkspaceAssociationInterface
   */
  protected $workspaceAssociation;

  /**
   * MenuTreeStorage constructor.
   *
   * @param \Drupal\workspaces\WorkspaceManagerInterface $workspace_manager
   *   The workspace manager service.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\Core\Database\Connection $connection
   *   A Database connection to use for reading and writing configuration data.
   * @param \Drupal\Core\Cache\CacheBackendInterface $menu_cache_backend
   *   Cache backend instance for the extracted tree data.
   * @param \Drupal\Core\Cache\CacheTagsInvalidatorInterface $cache_tags_invalidator
   *   The cache tags invalidator.
   * @param \Drupal\workspaces\WorkspaceAssociationInterface $workspace_association
   *   The workspace association service.
   * @param string $table
   *   A database table name to store configuration data in.
   * @param array $options
   *   (optional) Any additional database connection options to use in queries.
   */
  public function __construct(
    WorkspaceManagerInterface $workspace_manager,
    EntityTypeManagerInterface $entity_type_manager,
    Connection $connection,
    CacheBackendInterface $menu_cache_backend,
    CacheTagsInvalidatorInterface $cache_tags_invalidator,
    WorkspaceAssociationInterface $workspace_association,
    string $table,
    array $options = []
  ) {
    parent::__construct($connection, $menu_cache_backend, $cache_tags_invalidator, $table, $options);

    $this->workspaceAssociation = $workspace_association;
    $this->workspaceManager = $workspace_manager;
    $this->entityTypeManager = $entity_type_manager;
  }

  /**
   * {@inheritdoc}
   */
  public function loadTreeData($menu_name, MenuTreeParameters $parameters) {
    // Add any non-default workspace as a menu tree condition parameter so it is
    // included in the cache ID.
    $active_workspace = $this->workspaceManager->getActiveWorkspace();
    if ($active_workspace && !$active_workspace->isDefaultWorkspace()) {
      $parameters->conditions['workspace'] = $active_workspace->id();
    }
    return parent::loadTreeData($menu_name, $parameters);
  }

  /**
   * {@inheritdoc}
   */
  protected function loadLinks($menu_name, MenuTreeParameters $parameters) {
    $links = parent::loadLinks($menu_name, $parameters);

    $all_menu_content_ids = array_filter(array_keys($links), function ($id) use ($links) {
      return $links[$id]['provider'] === 'menu_link_content';
    });

    // Replace the menu link plugin definitions with workspace-specific ones.
    $active_workspace = $this->workspaceManager->getActiveWorkspace();
    if ($active_workspace && !$active_workspace->isDefaultWorkspace()) {
      $tracked_revisions = $this->workspaceAssociation->getTrackedEntities($active_workspace->id(), 'menu_link_content');
      $this->currentWorkspace = $active_workspace->id();
      $localLinks = parent::loadLinks($menu_name, $parameters);
      $this->currentWorkspace = NULL;

      /** @var \Drupal\menu_link_content\MenuLinkContentInterface[] $workspace_revisions */
      $workspace_revisions = isset($tracked_revisions['menu_link_content'])
        ? $this->entityTypeManager
          ->getStorage('menu_link_content')
          ->loadMultipleRevisions(array_keys($tracked_revisions['menu_link_content']))
        : [];

      $workspace_plugin_ids = array_map(function (MenuLinkContent $menuLinkContent) {
        return $menuLinkContent->getPluginId();
      }, $workspace_revisions);

      $recheckParenthood = [];

      foreach (array_diff($all_menu_content_ids, $workspace_plugin_ids) as $removable) {
        if ($links[$removable]['parent']) {
          $recheckParenthood[] = $links[$removable]['parent'];
        }
        unset($links[$removable]);
      }

      foreach ($workspace_revisions as $workspace_revision) {
        if (isset($links[$workspace_revision->getPluginId()])) {
          $links[$workspace_revision->getPluginId()] = $localLinks[$workspace_revision->getPluginId()] ?? [] + $links[$workspace_revision->getPluginId()];
        }
      }

      foreach ($recheckParenthood as $parentId) {
        if (isset($links[$parentId])) {
          $links[$parentId]['has_children'] = count(array_filter($links, function ($link) use ($parentId) {
            return $link['parent'] === $parentId;
          })) > 0 ? '1' : '0';
        }
      }
    }

    return $links;
  }

  protected static function schemaDefinition() {
    $schema = parent::schemaDefinition();
    $schema['fields']['workspace'] = [
      'type' => 'varchar_ascii',
      'length' => 128,
      'not null' => FALSE,
      'description' => 'The workspace ID.',
    ];
    $schema['indexes']['workspace'] = ['workspace'];
    $schema['unique keys']['id'] = ['id', 'workspace'];
    return $schema;
  }

  protected $currentWorkspace = NULL;

  protected function doSave(array $link) {
    $affected_menus = parent::doSave($link);
    if ($link['provider'] === 'menu_link_content') {
      $entityId = $link['metadata']['entity_id'];
      /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
      $storage = $this->entityTypeManager->getStorage('menu_link_content');
      // TODO: Integrate this into WorkspaceAssociation.
      $result = \Drupal::database()->select('workspace_association', 'wa')
        ->fields('wa', ['workspace', 'target_entity_revision_id'])
        ->condition('target_entity_type_id', 'menu_link_content')
        ->condition('target_entity_id', $entityId)
        ->execute();
      while($row = $result->fetch()) {
        $this->currentWorkspace = $row->workspace;
        /** @var \Drupal\menu_link_content\MenuLinkContentInterface $localLinkEntity */
        $localLinkEntity = $storage->loadRevision($row->target_entity_revision_id);
        $pluginDefinition = $localLinkEntity->getPluginDefinition();
        $pluginDefinition['workspace'] = $row->workspace;
        $affected_menus += parent::doSave($pluginDefinition);
      }
      $this->currentWorkspace = NULL;
    }
    return $affected_menus;
  }

  protected function safeExecuteSelect(SelectInterface $query) {
    if ($this->currentWorkspace) {
      $query->condition('workspace', $this->currentWorkspace);
    }
    else {
      $query->isNull('workspace');
    }
    return parent::safeExecuteSelect($query);
  }

  protected function preSave(array &$link, array $original) {
    $fields = parent::preSave($link, $original);
    if (isset($link['workspace'])) {
      $fields['workspace'] = $link['workspace'];
    }
    return $fields;
  }

}

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

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