View source
<?php
namespace Drupal\tb_megamenu;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Menu\MenuTreeParameters;
use Drupal\Core\Menu\MenuLinkTreeInterface;
use Drupal\Core\Menu\MenuTreeStorageInterface;
use Drupal\Core\Path\PathMatcherInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\tb_megamenu\Entity\MegaMenuConfig;
class TBMegaMenuBuilder implements TBMegaMenuBuilderInterface {
use StringTranslationTrait;
private $logger;
private $menuTree;
private $entityTypeManager;
private $pathMatcher;
private $menuStorage;
public function __construct(LoggerChannelFactoryInterface $logger_factory, MenuLinkTreeInterface $menu_tree, EntityTypeManagerInterface $entity_manager, PathMatcherInterface $path_matcher, MenuTreeStorageInterface $menu_storage) {
$this->logger = $logger_factory
->get('tb_megamenu');
$this->menuTree = $menu_tree;
$this->entityTypeManager = $entity_manager;
$this->pathMatcher = $path_matcher;
$this->menuStorage = $menu_storage;
}
public function getBlockConfig(string $menu_name, string $theme) {
$menu = self::getMenus($menu_name, $theme);
return $menu ? $menu
->getBlockConfig() : [];
}
public function getMenus(string $menu_name, string $theme) {
$config = MegaMenuConfig::loadMenu($menu_name, $theme);
if ($config === NULL) {
$this->logger
->warning("Could not find TB Megamenu configuration for menu: @menu, theme: @theme", [
'@menu' => $menu_name,
'@theme' => $theme,
]);
}
return $config;
}
public function getMenuItem(string $menu_name, string $plugin_id) {
$tree =& drupal_static(__FUNCTION__);
if (is_null($tree)) {
$tree = $this->menuTree
->load($menu_name, (new MenuTreeParameters())
->onlyEnabledLinks());
}
$item = self::findMenuItem($tree, $plugin_id);
return $item;
}
public function findMenuItem(array $tree, string $plugin_id) {
foreach ($tree as $menu_plugin_id => $item) {
if ($menu_plugin_id == $plugin_id) {
return $item;
}
elseif ($result = self::findMenuItem($item->subtree, $plugin_id)) {
return $result;
}
}
return NULL;
}
public function loadEntityBlock(string $block_id) {
return $this->entityTypeManager
->getStorage('block')
->load($block_id);
}
public function getMenuConfig(string $menu_name, string $theme) {
$menu = self::getMenus($menu_name, $theme);
return isset($menu) ? $menu
->getMenuConfig() : [];
}
public function editBlockConfig(array &$block_config) {
$block_config += [
'animation' => 'none',
'style' => '',
'auto-arrow' => TRUE,
'duration' => 400,
'delay' => 200,
'always-show-submenu' => TRUE,
'off-canvas' => 0,
'number-columns' => 0,
];
}
public function editSubMenuConfig(array &$submenu_config) {
$submenu_config += [
'width' => '',
'class' => '',
'group' => '',
];
}
public function editItemConfig(array &$item_config) {
$attributes = [
'xicon' => '',
'class' => '',
'caption' => '',
'alignsub' => '',
'group' => 0,
'hidewcol' => 0,
'hidesub' => 0,
];
foreach ($attributes as $attribute => $value) {
if (!isset($item_config[$attribute])) {
$item_config[$attribute] = $value;
}
}
}
public function editColumnConfig(array &$col_config) {
$attributes = [
'width' => 12,
'class' => '',
'hidewcol' => 0,
'showblocktitle' => 0,
];
foreach ($attributes as $attribute => $value) {
if (!isset($col_config[$attribute])) {
$col_config[$attribute] = $value;
}
}
}
public function renderBlock(string $menu_name, string $theme) {
return [
'#theme' => 'tb_megamenu',
'#menu_name' => $menu_name,
'#block_theme' => $theme,
'#section' => 'backend',
'#post_render' => [
'\\Drupal\\tb_megamenu\\Controller\\TBMegaMenuController::tbMegamenuAttachNumberColumns',
],
];
}
public function getIdColumn(int $number_columns) {
$value =& drupal_static('column');
if (!isset($value)) {
$value = 1;
}
elseif (!$number_columns || $value < $number_columns) {
$value++;
}
return "tb-megamenu-column-{$value}";
}
public function getAllBlocks(string $theme) {
static $_blocks_array = [];
if (empty($_blocks_array)) {
$block_storage = $this->entityTypeManager
->getStorage('block');
$entity_ids = $block_storage
->getQuery()
->condition('theme', $theme)
->execute();
$entities = $block_storage
->loadMultiple($entity_ids);
$_blocks_array = [];
foreach ($entities as $block_id => $block) {
if ($block
->get('settings')['provider'] != 'tb_megamenu') {
$_blocks_array[$block_id] = $block
->label();
}
}
asort($_blocks_array);
}
return $_blocks_array;
}
public function createAnimationOptions(array $block_config) {
return [
'none' => $this
->t('None'),
'fading' => $this
->t('Fading'),
'slide' => $this
->t('Slide'),
'zoom' => $this
->t('Zoom'),
'elastic' => $this
->t('Elastic'),
];
}
public function createStyleOptions(array $block_config) {
return [
'' => $this
->t('Default'),
'black' => $this
->t('Black'),
'blue' => $this
->t('Blue'),
'green' => $this
->t('Green'),
];
}
public function buildPageTrail(array $menu_items) {
$trail = [];
foreach ($menu_items as $pluginId => $item) {
$is_front = $this->pathMatcher
->isFrontPage();
$route_name = $item->link
->getPluginDefinition()['route_name'];
if ($item->inActiveTrail || $route_name == '<front>' && $is_front) {
$trail[$pluginId] = $item;
}
if ($item->subtree) {
$trail += self::buildPageTrail($item->subtree);
}
}
return $trail;
}
public function syncConfigAll(array $menu_items, array &$menu_config, string $section) {
foreach ($menu_items as $id => $menu_item) {
$item_config = isset($menu_config[$id]) ? $menu_config[$id] : [];
if ($menu_item->hasChildren || $item_config) {
self::syncConfig($menu_item->subtree, $item_config, $section);
$menu_config[$id] = $item_config;
self::syncConfigAll($menu_item->subtree, $menu_config, $section);
}
}
}
public function syncConfig(array $items, array &$item_config, string $section) {
if (empty($item_config['rows_content'])) {
$item_config['rows_content'][0][0] = [
'col_content' => [],
'col_config' => [],
];
self::addColContent($items, $item_config);
if (empty($item_config['rows_content'][0][0]['col_content'])) {
unset($item_config['rows_content'][0]);
}
}
else {
$hash = [];
foreach ($item_config['rows_content'] as $row_delta => $row) {
foreach ($row as $col_delta => $col) {
foreach ($col['col_content'] as $item_delta => $tb_item) {
if (!empty($tb_item) && is_array($tb_item)) {
if ($tb_item['type'] == 'menu_item') {
self::syncMenuItem($hash, $tb_item, $row_delta, $col_delta, $item_delta, $items, $item_config);
}
elseif ($tb_item['type'] == 'block' && !empty($tb_item['block_id'])) {
self::syncBlock($tb_item, $row_delta, $col_delta, $item_delta, $section, $item_config);
}
else {
self::removeColumn($tb_item, $row_delta, $col_delta, $item_delta, $item_config);
}
}
}
}
}
self::insertEnabledLinks($items, $hash, $item_config);
}
}
public function addColContent(array $items, array &$item_config) {
foreach ($items as $plugin_id => $item) {
if ($item->link
->isEnabled()) {
$item_config['rows_content'][0][0]['col_content'][] = [
'type' => 'menu_item',
'plugin_id' => $plugin_id,
'tb_item_config' => [],
'weight' => $item->link
->getWeight(),
];
}
}
}
public function syncMenuItem(array &$hash, array $tb_item, $row_delta, $col_delta, $item_delta, array $items, array &$item_config) {
$hash[$tb_item['plugin_id']] = [
'row' => $row_delta,
'col' => $col_delta,
];
$existed = FALSE;
foreach ($items as $plugin_id => $item) {
if ($item->link
->isEnabled() && $tb_item['plugin_id'] == $plugin_id) {
$item_config['rows_content'][$row_delta][$col_delta]['col_content'][$item_delta]['weight'] = $item->link
->getWeight();
$existed = TRUE;
break;
}
}
if (!$existed) {
unset($item_config['rows_content'][$row_delta][$col_delta]['col_content'][$item_delta]);
if (empty($item_config['rows_content'][$row_delta][$col_delta]['col_content'])) {
unset($item_config['rows_content'][$row_delta][$col_delta]);
}
if (empty($item_config['rows_content'][$row_delta])) {
unset($item_config['rows_content'][$row_delta]);
}
}
}
public function syncBlock(array $tb_item, $row_delta, $col_delta, $item_delta, string $section, array &$item_config) {
if (!self::isBlockContentEmpty($tb_item['block_id'], $section)) {
unset($item_config['rows_content'][$row_delta][$col_delta]['col_content'][$item_delta]);
if (empty($item_config['rows_content'][$row_delta][$col_delta]['col_content'])) {
unset($item_config['rows_content'][$row_delta][$col_delta]);
}
if (empty($item_config['rows_content'][$row_delta])) {
unset($item_config['rows_content'][$row_delta]);
}
}
}
public function removeColumn(array $tb_item, $row_delta, $col_delta, $item_delta, array &$item_config) {
if (empty($tb_item)) {
unset($item_config['rows_content'][$row_delta][$col_delta]['col_content'][$item_delta]);
}
$this->logger
->warning("Unknown / invalid column content: <pre>@content</pre>", [
'@content' => print_r($tb_item, TRUE),
]);
}
public function insertEnabledLinks(array $items, array $hash, array &$item_config) {
$row = -1;
$col = -1;
foreach ($items as $plugin_id => $item) {
if ($item->link
->isEnabled()) {
if (isset($hash[$plugin_id])) {
$row = $hash[$plugin_id]['row'];
$col = $hash[$plugin_id]['col'];
continue;
}
if ($row > -1) {
self::insertTbMenuItem($item_config, $row, $col, $item);
}
else {
$row = $col = 0;
while (isset($item_config['rows_content'][$row][$col]['col_content'][0]['type']) && $item_config['rows_content'][$row][$col]['col_content'][0]['type'] == 'block') {
$row++;
}
self::insertTbMenuItem($item_config, $row, $col, $item);
$item_config['rows_content'][$row][$col]['col_config'] = [];
}
}
}
}
public function syncOrderMenus(array &$menu_config) {
foreach ($menu_config as $mlid => $config) {
foreach ($config['rows_content'] as $rows_id => $row) {
$item_sorted = [];
foreach ($row as $col) {
foreach ($col['col_content'] as $menu_item) {
if ($menu_item['type'] == 'menu_item') {
$item_sorted[$menu_item['weight']][] = $menu_item;
}
}
}
$item_sorted = self::sortByWeight($item_sorted);
foreach ($row as $rid => $col) {
foreach ($col['col_content'] as $menu_item_id => $menu_item) {
if ($menu_item['type'] == 'menu_item') {
$menu_config[$mlid]['rows_content'][$rows_id][$rid]['col_content'][$menu_item_id] = array_shift($item_sorted);
}
}
}
}
}
}
public function sortByWeight(array $item_sorted) {
ksort($item_sorted);
$new_list = [];
foreach ($item_sorted as $weight_group) {
foreach ($weight_group as $item) {
$new_list[] = $item;
}
}
return $new_list;
}
public function isBlockContentEmpty(string $block_id, string $section) {
$entity_block = self::loadEntityBlock($block_id);
if ($entity_block && ($entity_block
->getPlugin()
->build() || $section == 'backend')) {
return TRUE;
}
return FALSE;
}
public function insertTbMenuItem(array &$item_config, $row, $col, $item) {
$idx = 0;
$col_content = isset($item_config['rows_content'][$row][$col]['col_content']) ? array_values($item_config['rows_content'][$row][$col]['col_content']) : [];
current($col_content);
foreach ($col_content as $value) {
if (!empty($value['weight']) && $value['weight'] < $item->link
->getWeight()) {
next($col_content);
$idx = key($col_content);
}
}
for ($col = count($col_content); $col > $idx; $col--) {
$col_content[$col] = $col_content[$col - 1];
}
$col_content[$idx] = [
'plugin_id' => $item->link
->getPluginId(),
'type' => 'menu_item',
'weight' => $item->link
->getWeight(),
'tb_item_config' => [],
];
$item_config['rows_content'][$row][$col]['col_content'] = $col_content;
}
}