class MenuTreeStorage in Colossal Menu 2.x
Same name and namespace in other branches
- 8 src/Menu/MenuTreeStorage.php \Drupal\colossal_menu\Menu\MenuTreeStorage
Provides a menu tree storage using the database.
Hierarchy
- class \Drupal\colossal_menu\Menu\MenuTreeStorage implements MenuTreeStorageInterface
Expanded class hierarchy of MenuTreeStorage
1 string reference to 'MenuTreeStorage'
1 service uses MenuTreeStorage
File
- src/
Menu/ MenuTreeStorage.php, line 15
Namespace
Drupal\colossal_menu\MenuView source
class MenuTreeStorage implements MenuTreeStorageInterface {
/**
* The maximum depth of a menu links tree.
*
* This storage has no theoretical limit, but we'll set a reasonable limit.
*/
const MAX_DEPTH = 20;
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $connection;
/**
* The entity manager.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $storage;
/**
* The current route match.
*
* @var \Drupal\Core\Routing\RouteMatchInterface
*/
protected $currentRouteMatch;
/**
* The database table name.
*
* @var string
*/
protected $table;
/**
* Constructs a new \Drupal\Core\Menu\MenuTreeStorage.
*
* @param \Drupal\Core\Database\Connection $connection
* A Database connection to use for reading and writing configuration data.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The EntityTypeManager service.
* @param \Drupal\Core\Routing\RouteMatchInterface $current_route_match
* The currently active route match object.
* @param string $entity_type
* The entity type name.
* @param string $table
* A database table name to store configuration data in.
*/
public function __construct(Connection $connection, EntityTypeManagerInterface $entity_type_manager, RouteMatchInterface $current_route_match, string $entity_type, string $table) {
$this->connection = $connection;
$this->storage = $entity_type_manager
->getStorage($entity_type);
$this->currentRouteMatch = $current_route_match;
$this->table = $table;
}
/**
* {@inheritdoc}
*/
public function maxDepth() {
return self::MAX_DEPTH;
}
/**
* {@inheritdoc}
*
* Allow the entity system to cache the results.
*/
public function resetDefinitions() {
}
/**
* {@inheritdoc}
*
* Allow the entity system to cache the results.
*/
public function rebuild(array $definitions) {
}
/**
* {@inheritdoc}
*/
public function load($id) {
return $this->storage
->load($id);
}
/**
* {@inheritdoc}
*/
public function loadMultiple(array $ids) {
return $this->storage
->loadMultiple($ids);
}
/**
* {@inheritdoc}
*/
public function loadByProperties(array $properties) {
return $this->storage
->loadByProperties($properties);
}
/**
* {@inheritdoc}
*/
public function loadByRoute($route_name, array $route_parameters = [], $menu_name = NULL) {
$url = new Url($route_name, $route_parameters);
$query = $this->storage
->getQuery();
$query
->condition('link__uri', $url
->getUri());
if ($menu_name) {
$query
->condition('menu', $menu_name);
}
return $query
->execute();
}
/**
* {@inheritdoc}
*/
public function save(array $definition) {
return $this->storage
->create($definition);
}
/**
* {@inheritdoc}
*/
public function delete($id) {
return $this->storage
->delete($this->storage
->load($id));
}
/**
* {@inheritdoc}
*/
public function loadTreeData($menu_name, MenuTreeParameters $parameters) {
$query = $this->connection
->select($this->table, 't')
->fields('t', [
'ancestor',
'descendant',
'depth',
])
->condition('e.menu', $menu_name)
->orderBy('t.depth', 'ASC')
->orderBy('e.weight', 'ASC');
$query
->innerJoin($this->storage
->getEntityType()
->get('base_table'), 'e', 't.ancestor = e.id');
if ($parameters->root) {
$query
->condition('t.ancestor', $parameters->root);
}
if ($parameters->minDepth > 1) {
// Since the default depth is 1, and in our storage it's 0, we'll
// decrement the minimum depth.
$query
->condition('t.depth', $parameters->minDepth - 1, '>=');
}
if ($parameters->maxDepth) {
$query
->condition('t.depth', $parameters->maxDepth, '<=');
}
$result = $query
->execute();
$flat = [];
$depth = [];
while ($row = $result
->fetchObject()) {
$flat[$row->ancestor][] = $row->descendant;
if (isset($depth[$row->descendant]) && $row->depth > $depth[$row->descendant]) {
$depth[$row->descendant] = $row->depth;
}
elseif (!isset($depth[$row->descendant])) {
$depth[$row->descendant] = $row->depth;
}
}
$links = $this
->loadMultiple(array_keys($flat));
$routes = [];
foreach ($links as $link) {
if (!$link
->isExternal() && ($name = $link
->getRouteName())) {
$routes[$link
->id()] = $name;
}
}
$tree = $this
->treeDataRecursive($flat, $links, $depth, $routes);
return [
'tree' => $tree,
'route_names' => $routes,
];
}
/**
* Build the tree from the closure table.
*
* @param array $flat
* A flat tree returned from the database.
* @param array $links
* An array of Link objects.
* @param array $depth
* An array of depth values.
* @param array $routes
* An array of route names.
*
* @return array
* A fully-formed link tree.
*/
protected function treeDataRecursive(array $flat, array $links, array $depth, array $routes) {
uasort($flat, function ($a, $b) {
return count($a) - count($b);
});
$tree = [];
foreach ($flat as $id => $decendents) {
foreach ($decendents as $decendent) {
if ($id == $decendent) {
$active = FALSE;
if (isset($routes[$id]) && $this->currentRouteMatch
->getRouteName() == $routes[$id]) {
$active = TRUE;
}
$tree[$id] = [
'link' => $links[$id],
'has_children' => FALSE,
'subtree' => [],
'depth' => $depth[$id] + 1,
'in_active_trail' => $active,
];
}
else {
if (isset($tree[$decendent])) {
$tree[$id]['has_children'] = TRUE;
$tree[$id]['in_active_trail'] = $tree[$decendent]['in_active_trail'];
$tree[$id]['subtree'][$decendent] = $tree[$decendent];
unset($tree[$decendent]);
if (count($tree[$id]['subtree']) > 1) {
uasort($tree[$id]['subtree'], function ($a, $b) {
return $a['link']
->getWeight() < $b['link']
->getWeight() ? -1 : 1;
});
}
}
}
}
}
if (count($tree) > 1) {
uasort($tree, function ($a, $b) {
return $a['link']
->getWeight() < $b['link']
->getWeight() ? -1 : 1;
});
}
return $tree;
}
/**
* {@inheritdoc}
*/
public function loadAllChildren($id, $max_relative_depth = NULL) {
$query = $this->connection
->select($this->table, 't');
$query
->fields('t', [
'descendant',
]);
$query
->condition('t.ancestor', $id);
if ($max_relative_depth) {
$query
->condition('t.depth', '<=', $max_relative_depth);
}
$query
->orderBy('t.depth', 'ASC');
$ids = $query
->execute()
->fetchCol();
return $this->storage
->getQuery()
->condition('id', $ids)
->orderBy('weight', 'ASC');
}
/**
* {@inheritdoc}
*/
public function getAllChildIds($id) {
return $this->connection
->select($this->table, 't')
->fields('t', [
'descendant',
])
->condition('t.ancestor', $id)
->execute()
->fetchCol();
}
/**
* {@inheritdoc}
*/
public function loadSubtreeData($id, $max_relative_depth = NULL) {
$link = $this
->load($id);
$params = new MenuTreeParameters();
$params->root = $id;
$params
->setMaxDepth($max_relative_depth);
return $this
->loadTreeData($link
->getMenuName(), $params);
}
/**
* {@inheritdoc}
*/
public function getRootPathIds($id) {
return $this->connection
->select($this->table, 't')
->fields('t', [
'ancestor',
])
->condition('t.descendant', $id)
->orderBy('t.depth', 'DESC')
->execute()
->fetchCol();
}
/**
* {@inheritdoc}
*/
public function getExpanded($menu_name, array $parents) {
$query = $this->connection
->select($this->table, 't')
->fields('t', [
'descendant',
])
->condition('t.ancestor', $parents)
->condition('e.menu', $menu_name)
->orderBy('t.depth', 'ASC')
->orderBy('e.weight', 'ASC');
$query
->innerJoin($this->storage
->getEntityType()
->get('base_table'), 'e', 't.ancestor = e.id');
return $query
->execute()
->fetchCol();
}
/**
* {@inheritdoc}
*/
public function getSubtreeHeight($id) {
return $this->conneciton
->select($this->table, 't')
->fields('t', [
'depth',
])
->condition('t.descendant', $id)
->orderBy('t.depth', 'DESC')
->limit(0, 1)
->execute()
->fetchField();
}
/**
* {@inheritdoc}
*/
public function menuNameInUse($menu_name) {
$links = $this->storage
->loadByProperties([
'menu' => $menu_name,
]);
return empty($links);
}
/**
* {@inheritdoc}
*/
public function getMenuNames() {
return $this->connection
->select($this->storage
->getEntityType()
->get('base_table'), 'e')
->distinct()
->fields('e', [
'menu',
])
->execute()
->fetchCol();
}
/**
* {@inheritdoc}
*/
public function countMenuLinks($menu_name = NULL) {
$query = $this->connection
->select($this->storage
->getEntityType()
->get('base_table'), 'e')
->count();
if ($menu_name) {
$query
->condition('e.menu', $menu_name);
}
return $query
->execute();
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
MenuTreeStorage:: |
protected | property | The database connection. | |
MenuTreeStorage:: |
protected | property | The current route match. | |
MenuTreeStorage:: |
protected | property | The entity manager. | |
MenuTreeStorage:: |
protected | property | The database table name. | |
MenuTreeStorage:: |
public | function |
Counts the total number of menu links in one menu or all menus. Overrides MenuTreeStorageInterface:: |
|
MenuTreeStorage:: |
public | function |
Deletes a menu link definition from the storage. Overrides MenuTreeStorageInterface:: |
|
MenuTreeStorage:: |
public | function |
Loads all the IDs for menu links that are below the given ID. Overrides MenuTreeStorageInterface:: |
|
MenuTreeStorage:: |
public | function |
Finds expanded links in a menu given a set of possible parents. Overrides MenuTreeStorageInterface:: |
|
MenuTreeStorage:: |
public | function |
Returns the used menu names in the tree storage. Overrides MenuTreeStorageInterface:: |
|
MenuTreeStorage:: |
public | function |
Returns all the IDs that represent the path to the root of the tree. Overrides MenuTreeStorageInterface:: |
|
MenuTreeStorage:: |
public | function |
Finds the height of a subtree rooted by the given ID. Overrides MenuTreeStorageInterface:: |
|
MenuTreeStorage:: |
public | function |
Loads a menu link plugin definition from the storage. Overrides MenuTreeStorageInterface:: |
|
MenuTreeStorage:: |
public | function |
Loads all the enabled menu links that are below the given ID. Overrides MenuTreeStorageInterface:: |
|
MenuTreeStorage:: |
public | function |
Loads multiple plugin definitions from the storage based on properties. Overrides MenuTreeStorageInterface:: |
|
MenuTreeStorage:: |
public | function |
Loads multiple plugin definitions from the storage based on route. Overrides MenuTreeStorageInterface:: |
|
MenuTreeStorage:: |
public | function |
Loads multiple plugin definitions from the storage. Overrides MenuTreeStorageInterface:: |
|
MenuTreeStorage:: |
public | function |
Loads a subtree rooted by the given ID. Overrides MenuTreeStorageInterface:: |
|
MenuTreeStorage:: |
public | function |
Loads a menu link tree from the storage. Overrides MenuTreeStorageInterface:: |
|
MenuTreeStorage:: |
public | function |
The maximum depth of tree the storage implementation supports. Overrides MenuTreeStorageInterface:: |
|
MenuTreeStorage:: |
constant | The maximum depth of a menu links tree. | ||
MenuTreeStorage:: |
public | function |
Determines whether a specific menu name is used in the tree. Overrides MenuTreeStorageInterface:: |
|
MenuTreeStorage:: |
public | function |
Allow the entity system to cache the results. Overrides MenuTreeStorageInterface:: |
|
MenuTreeStorage:: |
public | function |
Allow the entity system to cache the results. Overrides MenuTreeStorageInterface:: |
|
MenuTreeStorage:: |
public | function |
Saves a plugin definition to the storage. Overrides MenuTreeStorageInterface:: |
|
MenuTreeStorage:: |
protected | function | Build the tree from the closure table. | |
MenuTreeStorage:: |
public | function | Constructs a new \Drupal\Core\Menu\MenuTreeStorage. |