doghouse_menu-3.0.x-dev/src/Plugin/Block/VerticalMenu.php

src/Plugin/Block/VerticalMenu.php
<?php

namespace Drupal\doghouse_menu\Plugin\Block;

use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Access\AccessResultInterface;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Menu\MenuLinkTreeInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Template\Attribute;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Menu\MenuLinkManagerInterface;

/**
 * Provides a 'VerticalMenu' block.
 *
 * @Block(
 *  id = "doghouse_vertical_menu",
 *  admin_label = @Translation("Doghouse Vertical Menu"),
 * )
 */
class VerticalMenu extends BlockBase implements ContainerFactoryPluginInterface {

  /**
   * Drupal\Core\Menu\MenuLinkTreeInterface definition.
   *
   * @var \Drupal\Core\Menu\MenuLinkTreeInterface
   */
  protected $menuLinkTree;

  /**
   * Drupal\Core\Menu\MenuLinkManagerInterface definition.
   *
   * @var \Drupal\Core\Menu\MenuLinkManagerInterface
   */
  protected $menuLinkManager;

  /**
   * Constructs a new VerticalMenu 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 string $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\Core\Menu\MenuLinkTreeInterface $menu_link_tree
   * @param \Drupal\Core\Menu\MenuLinkManagerInterface $menuLinkManager
   */
  public function __construct(
    array $configuration,
    $plugin_id,
    $plugin_definition,
    MenuLinkTreeInterface $menu_link_tree,
    MenuLinkManagerInterface $menuLinkManager
  ) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->menuLinkTree = $menu_link_tree;
    $this->menuLinkManager = $menuLinkManager;
  }
  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('menu.link_tree'),
      $container->get('plugin.manager.menu.link')
    );
  }
  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration() {
    return [
        'menu' => '',
        'options' => [
          'menu_type' => 'slide',
        ],
      ] + parent::defaultConfiguration();
  }

  /**
   * Returns a list of theme regions.
   *
   * @return array
   */
  private function getRegionOptions() {
    $default_theme = \Drupal::config('system.theme')->get('default');
    return system_region_list($default_theme);
  }

  /**
   * {@inheritdoc}
   */
  public function blockForm($form, FormStateInterface $form_state) {
    $menuOptions = \Drupal::entityQuery('menu')->execute();
    $form['menu'] = [
      '#type' => 'select',
      '#title' => $this->t('Menu'),
      '#options' => $menuOptions,
      '#default_value' => $this->configuration['menu'],
    ];

    $form['options'] = [
      '#type' => 'fieldset',
      '#title' => $this->t('Style options'),
    ];

    $form['options']['menu_type'] = [
      '#type' => 'select',
      '#title' => $this->t('Menu Type'),
      '#description' => $this->t("Select how you want the sub menu to appear once a parent link has been clicked."),
      '#default_value' => $this->configuration['options']['menu_type'],
      '#options' => [
        'slide' => $this->t('Slide'),
        'accordion' => $this->t('Accordion'),
      ],
    ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function blockSubmit($form, FormStateInterface $form_state) {
    $this->configuration['menu'] = $form_state->getValue('menu');
    $this->configuration['options'] = $form_state->getValue('options');
  }

  /**
   * {@inheritdoc}
   */
  public function build() {
    $id = Html::getUniqueId('doghouse-menu');
    $tree = $this->loadMenuTrue();

    $build = [];

    if (!empty($tree)) {
      $build = [
        '#attributes' => [
          'class' => [
            'doghouse-menu',
            'js-doghouse-menu',
          ],
          'data-menu-type' => $this->configuration['options']['menu_type'],
        ],
        '#attached' => [
          'library' => [
            'doghouse_menu/doghouse_menu',
          ],
          'drupalSettings' => [
            'doghouseMenu' => [
              'id' => $id,
              'options' => $this->configuration['options'],
            ],
          ],
        ],
      ];

      if ($this->configuration['options']['menu_type'] === 'slide') {
        $flattenedTree = $this->flattenMenuTree($tree);
        $builtMenu = $this->buildMenu($flattenedTree);
      } else {
        $builtMenu = $this->menuLinkTree->build($tree);
        $builtMenu['#theme'] = 'doghouse_menu_accordion';
      }
      $build[] = $builtMenu;
    }

    return $build;
  }

  private function loadMenuTrue() {
    $menu_name = $this->configuration['menu'];
    $parameters = $this->menuLinkTree->getCurrentRouteMenuTreeParameters($menu_name);
    $tree = $this->menuLinkTree->load($menu_name, $parameters);
    $manipulators = [
      ['callable' => 'menu.default_tree_manipulators:checkAccess'],
      ['callable' => 'menu.default_tree_manipulators:generateIndexAndSort'],
    ];
    return $this->menuLinkTree->transform($tree, $manipulators);
  }

  /**
   * Builds the menu renderable array.
   *
   * @param array $flattenedTree
   *   The flattened menu tree array
   *
   * @return array
   */
  public function buildMenu(array $flattenedTree) {
    $menu = [
      '#theme' => 'doghouse_menu',
      '#items' => [],
    ];

    foreach ($flattenedTree as $dataMenu => $links) {
      $menu['#items'][$dataMenu]['items'] = $this->buildItems($links['items']);
      $menu['#items'][$dataMenu]['depth'] = $links['depth'];
      $menu['#items'][$dataMenu]['attributes'] = new Attribute();
      $menu['#items'][$dataMenu]['attributes']['data-menu'] = $dataMenu;
      $menu['#items'][$dataMenu]['attributes']['data-depth'] = $links['depth'];
    }

    return $menu;
  }

  /**
   * Builds a list of single menu items for rendering.
   *
   * @param array $submenu
   *   An array of submenu items.
   *
   * @return array
   */
  public function buildItems(array $submenu) {
    $items = [];

    foreach ($submenu as $id => $menuItem) {
      $element = [];
      $link = $menuItem->link;

      if (!$link->isEnabled()) {
        continue;
      }

      if ($menuItem->access !== NULL && !$menuItem->access instanceof AccessResultInterface) {
        throw new \DomainException('MenuLinkTreeElement::access must be either NULL or an AccessResultInterface object.');
      }

      $element['attributes'] = new Attribute();
      $element['title'] = $link->getTitle();
      $element['url'] = $link->getUrlObject();
      $element['url']->getOption('attributes') ?: $element['url']->setOption('attributes', []);
      $element['url']->setOption('set_active_class', TRUE);

      if ($menuItem->subtree) {
        $menuItem->options['attributes']['data-submenu'] = $id;
      }

      if (isset($menuItem->options)) {
        $element['url']->setOptions(NestedArray::mergeDeep($element['url']->getOptions(), $menuItem->options));

        if (isset($menuItem->options['is_heading'])) {
          $element['attributes']->addClass('doghouse-menu__item-heading');
        }

        if (isset($menuItem->options['has_heading'])) {
          $element['attributes']->addClass('doghouse-menu__item-has-heading');
        }

      }
      $element['original_link'] = $link;

      $items[$id] = $element;
    }

    return $items;
  }

  /**
   * Check if user has access to link.
   *
   * @param \Drupal\Core\Menu\MenuLinkTreeElement $item
   *   An element in a menu link tree.
   *
   * @return bool
   *   Weather or not the user is allowed access.
   */
  private function itemAllowedAccess($item) {
    if (!$item->link->isEnabled()) {
      return FALSE;
    }

    if ($item->access !== NULL && !$item->access instanceof AccessResultInterface) {
      throw new \DomainException('MenuLinkTreeElement::access must be either NULL or an AccessResultInterface object.');
    }

    // Only render accessible links.
    if ($item->access instanceof AccessResultInterface && !$item->access->isAllowed()) {
      return FALSE;
    }

    return TRUE;
  }

  /**
   * Flattens a menu tree into a grouped one dimensional array.
   *
   * @param $menu
   * @param string $id
   * @param array $return
   *
   * @return array
   */
  public function flattenMenuTree($menu, $parent = 'main', $depth = 0, $return = []) {
    $return[$parent]['depth'] = $depth;
    foreach ($menu as $itemId => $item) {

      // Check if user is allowed access to this link.
      if (!$this->itemAllowedAccess($item)) {
        continue;
      }

      $return[$parent]['items'][$itemId] = $item;

      // Filter out inaccessible links from subtree.
      if (!empty($item->subtree)) {
        foreach ($item->subtree as $key => $subtree_item) {
          if (!$this->itemAllowedAccess($subtree_item)) {
            unset($item->subtree[$key]);
          }
        }
      }

      if ($item->hasChildren && !empty($item->subtree)) {
        // Add copy of parent link to submenu.
        $new_parent_id = $itemId;
        $return[$new_parent_id]['items'][$itemId] = clone $item;
        $return[$new_parent_id]['items'][$itemId]->subtree = FALSE;
        $return[$new_parent_id]['items'][$itemId]->options['attributes']['class'][] = 'doghouse-menu__parent-link';
        $return = $this->flattenMenuTree($item->subtree, $new_parent_id, $depth + 1, $return);
        $return[$parent]['items'][$itemId]->subtree = TRUE;
      } else {
        $return[$parent]['items'][$itemId]->subtree = FALSE;
      }

      if ($depth == 0) {
        $return[$parent]['items'][$itemId]->options['attributes']['class'][] = 'doghouse-menu__top-level-link';
      }
    }
    return $return;
  }

}

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

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