core/lib/Drupal/Core/Cache/MemoryBackend.php | 8 +- .../Core/Menu/DefaultMenuLinkTreeManipulators.php | 80 ++++++------- core/lib/Drupal/Core/Menu/MenuLinkTree.php | 27 ++--- core/lib/Drupal/Core/Menu/MenuLinkTreeElement.php | 124 +++++++++++++++++++++ .../Drupal/Core/Menu/MenuParentFormSelector.php | 10 +- core/lib/Drupal/Core/Menu/MenuTreeStorage.php | 72 ++++++------ core/modules/menu_ui/menu_ui.admin.inc | 2 +- core/modules/menu_ui/src/MenuForm.php | 76 ++++++------- .../system/src/Controller/SystemController.php | 11 +- core/modules/system/src/SystemManager.php | 8 +- .../Cache/GenericCacheBackendUnitTestBase.php | 8 ++ .../system/src/Tests/Menu/MenuLinkTreeTest.php | 31 +++--- .../system/src/Tests/Menu/MenuTreeStorageTest.php | 38 +++---- core/modules/system/src/Tests/System/AdminTest.php | 6 +- core/modules/system/system.module | 12 +- core/modules/toolbar/toolbar.module | 40 +++---- .../Menu/DefaultMenuLinkTreeManipulatorsTest.php | 73 ++++++------ .../Tests/Core/Menu/MenuLinkTreeElementTest.php | 63 +++++++++++ 18 files changed, 442 insertions(+), 247 deletions(-) diff --git a/core/lib/Drupal/Core/Cache/MemoryBackend.php b/core/lib/Drupal/Core/Cache/MemoryBackend.php index 8cd759c..55d9a7b 100644 --- a/core/lib/Drupal/Core/Cache/MemoryBackend.php +++ b/core/lib/Drupal/Core/Cache/MemoryBackend.php @@ -38,7 +38,7 @@ public function __construct($bin) { */ public function get($cid, $allow_invalid = FALSE) { if (isset($this->cache[$cid])) { - return $this->prepareItem($this->cache[$cid], $allow_invalid); + return $this->prepareItem(clone $this->cache[$cid], $allow_invalid); } else { return FALSE; @@ -54,7 +54,7 @@ public function getMultiple(&$cids, $allow_invalid = FALSE) { $items = array_intersect_key($this->cache, array_flip($cids)); foreach ($items as $item) { - $item = $this->prepareItem($item, $allow_invalid); + $item = $this->prepareItem(clone $item, $allow_invalid); if ($item) { $ret[$item->cid] = $item; } @@ -83,6 +83,8 @@ protected function prepareItem($cache, $allow_invalid) { return FALSE; } + $cache->data = unserialize($cache->data); + // Check expire time. $cache->valid = $cache->expire == Cache::PERMANENT || $cache->expire >= REQUEST_TIME; @@ -99,7 +101,7 @@ protected function prepareItem($cache, $allow_invalid) { public function set($cid, $data, $expire = Cache::PERMANENT, array $tags = array()) { $this->cache[$cid] = (object) array( 'cid' => $cid, - 'data' => $data, + 'data' => serialize($data), 'created' => REQUEST_TIME, 'expire' => $expire, 'tags' => $this->flattenTags($tags), diff --git a/core/lib/Drupal/Core/Menu/DefaultMenuLinkTreeManipulators.php b/core/lib/Drupal/Core/Menu/DefaultMenuLinkTreeManipulators.php index 9e3c484..266ee8e 100644 --- a/core/lib/Drupal/Core/Menu/DefaultMenuLinkTreeManipulators.php +++ b/core/lib/Drupal/Core/Menu/DefaultMenuLinkTreeManipulators.php @@ -38,31 +38,31 @@ public function __construct(AccessManager $access_manager, AccountInterface $acc } /** - * Tree manipulator that performs access checks. + * Menu link tree manipulator that performs access checks. * - * Removes menu items from the given menu tree whose links are inaccessible + * Removes menu links from the given menu tree whose links are inaccessible * for the current user, sets the 'access' property to TRUE on tree elements * that are accessible for the current user. * * Makes the resulting menu tree impossible to render cache, unless render * caching per user is acceptable. * - * @param array $tree - * The menu tree to manipulate. + * @param \Drupal\Core\Menu\MenuLinkTreeElement[] $tree + * The menu link tree to manipulate. * - * @return array - * The manipulated menu tree. + * @return \Drupal\Core\Menu\MenuLinkTreeElement[] + * The manipulated menu link tree. */ public function checkAccess(array $tree) { - foreach ($tree as $key => $item) { + foreach ($tree as $key => $element) { // Other menu tree manipulators may already have calculated access, do // not overwrite the existing value in that case. - if (!isset($item['access'])) { - $tree[$key]['access'] = $this->menuLinkCheckAccess($item['link']); + if (!isset($element->access)) { + $tree[$key]->access = $this->menuLinkCheckAccess($element->link); } - if ($tree[$key]['access']) { - if ($tree[$key]['below']) { - $tree[$key]['below'] = $this->checkAccess($tree[$key]['below']); + if ($tree[$key]->access) { + if ($tree[$key]->subtree) { + $tree[$key]->subtree = $this->checkAccess($tree[$key]->subtree); } } else { @@ -96,22 +96,22 @@ protected function menuLinkCheckAccess(MenuLinkInterface $instance) { } /** - * Tree manipulator that generates a unique index, and sorts by it. + * Menu link tree manipulator that generates a unique index, and sorts by it. * - * @param array $tree - * The menu tree to manipulate. + * @param \Drupal\Core\Menu\MenuLinkTreeElement[] $tree + * The menu link tree to manipulate. * - * @return array - * The manipulated menu tree. + * @return \Drupal\Core\Menu\MenuLinkTreeElement[] + * The manipulated menu link tree. */ public function generateIndexAndSort(array $tree) { $new_tree = array(); foreach ($tree as $key => $v) { - if ($tree[$key]['below']) { - $tree[$key]['below'] = $this->generateIndexAndSort($tree[$key]['below']); + if ($tree[$key]->subtree) { + $tree[$key]->subtree = $this->generateIndexAndSort($tree[$key]->subtree); } /** @var \Drupal\Core\Menu\MenuLinkInterface $instance */ - $instance = $tree[$key]['link']; + $instance = $tree[$key]->link; // The weights are made a uniform 5 digits by adding 50000 as an offset. // After $this->menuLinkCheckAccess(), $instance->getTitle() has the // localized or translated title. Adding the plugin id to the end of the @@ -123,44 +123,44 @@ public function generateIndexAndSort(array $tree) { } /** - * Tree manipulator that flattens the tree to a single level. + * Menu link tree manipulator that flattens the tree to a single level. * - * @param array $tree - * The menu tree to manipulate. + * @param \Drupal\Core\Menu\MenuLinkTreeElement[] $tree + * The menu link tree to manipulate. * - * @return array - * The manipulated menu tree. + * @return \Drupal\Core\Menu\MenuLinkTreeElement[] + * The manipulated menu link tree. */ public function flatten(array $tree) { - foreach ($tree as $key => $item) { - if ($tree[$key]['below']) { - $tree += $this->flatten($tree[$key]['below']); + foreach ($tree as $key => $element) { + if ($tree[$key]->subtree) { + $tree += $this->flatten($tree[$key]->subtree); } - $tree[$key]['below'] = array(); + $tree[$key]->subtree = array(); } return $tree; } /** - * Tree manipulator that extracts a subtree of the active trail. + * Menu link tree manipulator that extracts a subtree of the active trail. * - * @param array $tree - * The menu tree to manipulate. + * @param \Drupal\Core\Menu\MenuLinkTreeElement[] $tree + * The menu link tree to manipulate. * @param int $level * The level in the active trail to extract. * - * @return array - * The manipulated menu tree. + * @return \Drupal\Core\Menu\MenuLinkTreeElement[] + * The manipulated menu link tree. */ public function extractSubtreeOfActiveTrail(array $tree, $level) { // Go down the active trail until the right level is reached. while ($level-- > 0 && $tree) { - // Loop through the current level's items until we find one that is in the - // active trail. - while ($item = array_shift($tree)) { - if (isset($item['in_active_trail']) && $item['in_active_trail']) { - // If the item is in the active trail, we continue in the subtree. - $tree = empty($item['below']) ? array() : $item['below']; + // Loop through the current level's elements until we find one that is in + // the active trail. + while ($element = array_shift($tree)) { + if ($element->inActiveTrail) { + // If the element is in the active trail, we continue in the subtree. + $tree = $element->subtree; break; } } diff --git a/core/lib/Drupal/Core/Menu/MenuLinkTree.php b/core/lib/Drupal/Core/Menu/MenuLinkTree.php index 23cdc55..aae8c10 100644 --- a/core/lib/Drupal/Core/Menu/MenuLinkTree.php +++ b/core/lib/Drupal/Core/Menu/MenuLinkTree.php @@ -121,24 +121,24 @@ public function render($tree) { foreach ($tree as $data) { $class = array(); /** @var \Drupal\Core\Menu\MenuLinkInterface $link */ - $link = $data['link']; + $link = $data->link; // Generally we only deal with visible links, but just in case. if ($link->isHidden()) { continue; } // Set a class for the
  • -tag. Only set 'expanded' class if the link // also has visible children within the current tree. - if ($data['has_children'] && $data['below']) { + if ($data->hasChildren && !empty($data->subtree)) { $class[] = 'expanded'; } - elseif ($data['has_children']) { + elseif ($data->hasChildren) { $class[] = 'collapsed'; } else { $class[] = 'leaf'; } // Set a class if the link is in the active trail. - if ($data['in_active_trail']) { + if ($data->inActiveTrail) { $class[] = 'active-trail'; } @@ -147,9 +147,9 @@ public function render($tree) { $element['#attributes']['class'] = $class; $element['#title'] = $link->getTitle(); $element['#url'] = $link->getUrlObject(); - $element['#below'] = $data['below'] ? $this->render($data['below']) : array(); - if (isset($data['options'])) { - $element['#url']->setOptions(NestedArray::mergeDeep($element['#url']->getOptions(), $data['options'])); + $element['#below'] = $data->subtree ? $this->render($data->subtree) : array(); + if (isset($data->options)) { + $element['#url']->setOptions(NestedArray::mergeDeep($element['#url']->getOptions(), $data->options)); } $element['#original_link'] = $link; // Index using the link's unique ID. @@ -283,13 +283,14 @@ public function transform(array $tree, array $manipulators) { * Helper function that recursively instantiates the plugins. */ protected function createInstances(&$tree) { - foreach ($tree as $key => $v) { - if ($tree[$key]['below']) { - $this->createInstances($tree[$key]['below']); + foreach (array_keys($tree) as $id) { + // Upcast the MenuLinkTreeElement's "link" property from a definition to + // an instance. + $tree[$id]->link = $this->menuLinkManager->createInstance($tree[$id]->link['id']); + + if (!empty($tree[$id]->subtree)) { + $this->createInstances($tree[$id]->subtree); } - $tree[$key]['link'] = $this->menuLinkManager->createInstance($tree[$key]['definition']['id']); - $tree[$key]['access'] = NULL; - unset($tree[$key]['definition']); } } diff --git a/core/lib/Drupal/Core/Menu/MenuLinkTreeElement.php b/core/lib/Drupal/Core/Menu/MenuLinkTreeElement.php new file mode 100644 index 0000000..bbafaae --- /dev/null +++ b/core/lib/Drupal/Core/Menu/MenuLinkTreeElement.php @@ -0,0 +1,124 @@ +link = $link; + $this->hasChildren = $has_children; + $this->depth = $depth; + $this->subtree = $subtree; + $this->inActiveTrail = $in_active_trail; + + // Properties that will be updated by menu link tree manipulators. + $this->access = NULL; + $this->options = array(); + } + + /** + * Counts all menu links in the current subtree. + * + * @return int + * The number of menu links in this subtree (one plus the number of menu + * links in all descendants). + */ + public function count() { + $sum = function ($carry, MenuLinkTreeElement $element) { + return $carry + $element->count(); + }; + return 1 + array_reduce($this->subtree, $sum); + } + +} diff --git a/core/lib/Drupal/Core/Menu/MenuParentFormSelector.php b/core/lib/Drupal/Core/Menu/MenuParentFormSelector.php index 322118d..406c6cd 100644 --- a/core/lib/Drupal/Core/Menu/MenuParentFormSelector.php +++ b/core/lib/Drupal/Core/Menu/MenuParentFormSelector.php @@ -116,21 +116,21 @@ protected function getParentDepthLimit($id) { * The maximum depth of menu links considered for the select options. */ protected function parentSelectOptionsTreeWalk(array $tree, $menu_name, $indent, array &$options, $exclude, $depth_limit) { - foreach ($tree as $data) { - if ($data['depth'] > $depth_limit) { + foreach ($tree as $element) { + if ($element->depth > $depth_limit) { // Don't iterate through any links on this level. break; } /** @var \Drupal\Core\Menu\MenuLinkInterface $link */ - $link = $data['link']; + $link = $element->link; if ($link->getPluginId() != $exclude) { $title = $indent . ' ' . Unicode::truncate($link->getTitle(), 30, TRUE, FALSE); if ($link->isHidden()) { $title .= ' (' . t('disabled') . ')'; } $options[$menu_name . ':' . $link->getPluginId()] = $title; - if ($data['below']) { - $this->parentSelectOptionsTreeWalk($data['below'], $menu_name, $indent . '--', $options, $exclude, $depth_limit); + if (!empty($element->subtree)) { + $this->parentSelectOptionsTreeWalk($element->subtree, $menu_name, $indent . '--', $options, $exclude, $depth_limit); } } } diff --git a/core/lib/Drupal/Core/Menu/MenuTreeStorage.php b/core/lib/Drupal/Core/Menu/MenuTreeStorage.php index 2d79383..5f2767b 100644 --- a/core/lib/Drupal/Core/Menu/MenuTreeStorage.php +++ b/core/lib/Drupal/Core/Menu/MenuTreeStorage.php @@ -55,7 +55,7 @@ class MenuTreeStorage implements MenuTreeStorageInterface { protected $options = array(); /** - * Stores the defintions that have already been loaded for better performance.. + * Stores the definitions that have already been loaded for better performance. */ protected $definitions = array(); @@ -805,7 +805,7 @@ public function loadTreeData($menu_name, array $parameters = array()) { } $data['tree'] = $this->doBuildTreeData($links, $active_trail, $min_depth); $data['definitions'] = array(); - $data['route_names'] = $this->collectRoutes($data['tree'], $data['definitions']); + $data['route_names'] = $this->collectRoutesAndDefinitions($data['tree'], $data['definitions']); $this->treeCacheBackend->set($tree_cid, $data, Cache::PERMANENT, array('menu' => $menu_name)); // The definitions were already added to $this->definitions in // $this->doBuildTreeData() @@ -815,7 +815,7 @@ public function loadTreeData($menu_name, array $parameters = array()) { } /** - * Traverses the menu tree and collects all the route names. + * Traverses the menu tree and collects all the route names and definitions. * * @param array $tree * The menu tree you wish to operate on. @@ -825,23 +825,31 @@ public function loadTreeData($menu_name, array $parameters = array()) { * @return array * Array of route names, with all values being unique. */ - protected function collectRoutes(array $tree, array &$definitions) { - return array_values($this->doCollectRoutes($tree, $definitions)); + protected function collectRoutesAndDefinitions(array $tree, array &$definitions) { + return array_values($this->doCollectRoutesAndDefinitions($tree, $definitions)); } /** - * Recursive helper function to collect all the route names and defintions. + * Recursive helper function to collect all the route names and definitions. + * + * @param array $tree + * The menu link tree. + * @param array &$definitions + * The collected definitions. + * + * @return array + * The collected route names. */ - protected function doCollectRoutes(array $tree, array &$definitions) { + protected function doCollectRoutesAndDefinitions(array $tree, array &$definitions) { $route_names = array(); - foreach ($tree as $key => $v) { - $definition = $tree[$key]['definition']; - $definitions[$definition['id']] = $definition; + foreach (array_keys($tree) as $id) { + $definition = $this->definitions[$id]; + $definitions[$id] = $definition; if (!empty($definition['route_name'])) { $route_names[$definition['route_name']] = $definition['route_name']; } - if ($tree[$key]['below']) { - $route_names += $this->doCollectRoutes($tree[$key]['below'], $definitions); + if (!empty($tree[$id]->subtree)) { + $route_names += $this->doCollectRoutesAndDefinitions($tree[$id]->subtree, $definitions); } } return $route_names; @@ -881,11 +889,11 @@ public function loadSubtreeData($id, $max_relative_depth = NULL) { $links = $this->safeExecuteSelect($query)->fetchAll(\PDO::FETCH_ASSOC); $tree = $this->doBuildTreeData($links, array(), $root['depth']); $data['definitions'] = array(); - $data['route_names'] = $this->collectRoutes($tree, $data['definitions']); + $data['route_names'] = $this->collectRoutesAndDefinitions($tree, $data['definitions']); $data['tree'] = $tree; if ($data['tree']) { $top = reset($tree); - $menu_name = $top['definition']['menu_name']; + $menu_name = $top->link['menu_name']; $this->treeCacheBackend->set($tree_cid, $data, Cache::PERMANENT, array('menu' => $menu_name)); } // The definitions were already added to $this->definitions in @@ -992,10 +1000,9 @@ protected function doBuildTreeData(array $links, array $parents = array(), $dept * @param array $links * A flat array of menu links that are part of the menu. Each array element * is an associative array of information about the menu link, containing - * the fields from the {menu_links} table, and optionally additional - * information from the {menu_router} table, if the menu item appears in - * both tables. This array must be ordered depth-first. - * See _menu_build_tree() for a sample query. + * the fields from the {menu_tree} table. This array must be ordered + * depth-first. + * See ::loadTreeData() for a sample query. * @param array $parents * An array of the menu link ID values that are in the path from the current * page to the root of the menu tree. @@ -1003,21 +1010,24 @@ protected function doBuildTreeData(array $links, array $parents = array(), $dept * The minimum depth to include in the returned menu tree. * * @return array - * The fully build tree. + * The fully built tree. */ - protected function treeDataRecursive(&$links, $parents, $depth) { + protected function treeDataRecursive(array &$links, array $parents, $depth) { $tree = array(); - while ($item = array_pop($links)) { - // We need to determine if we're on the path to root so we can later build - // the correct active trail. - // Add the current link to the tree. - $tree[$item['id']] = array( - 'definition' => $this->prepareLink($item, TRUE), - 'has_children' => $item['has_children'], - 'in_active_trail' => in_array($item['id'], $parents), - 'below' => array(), - 'depth' => $item['depth'], + while ($tree_link_definition = array_pop($links)) { + // Build a MenuLinkTreeElement out of the menu link tree definition: + // transform the menu link tree definition into a menu link definition and + // store tree metadata in MenuLinkTreeElement. + $tree[$tree_link_definition['id']] = new MenuLinkTreeElement( + $this->prepareLink($tree_link_definition, TRUE), + (bool) $tree_link_definition['has_children'], + (int) $tree_link_definition['depth'], + // We need to determine if we're on the path to root so we can later build + // the correct active trail. + in_array($tree_link_definition['id'], $parents), + array() ); + // Look ahead to the next link, but leave it on the array so it's // available to other recursive function calls if we return or build a // sub-tree. @@ -1025,7 +1035,7 @@ protected function treeDataRecursive(&$links, $parents, $depth) { // Check whether the next link is the first in a new sub-tree. if ($next && $next['depth'] > $depth) { // Recursively call doBuildTreeData to build the sub-tree. - $tree[$item['id']]['below'] = $this->treeDataRecursive($links, $parents, $next['depth']); + $tree[$tree_link_definition['id']]->subtree = $this->treeDataRecursive($links, $parents, $next['depth']); // Fetch next link after filling the sub-tree. $next = end($links); } diff --git a/core/modules/menu_ui/menu_ui.admin.inc b/core/modules/menu_ui/menu_ui.admin.inc index 00d3e58..b8f0ef6 100644 --- a/core/modules/menu_ui/menu_ui.admin.inc +++ b/core/modules/menu_ui/menu_ui.admin.inc @@ -46,7 +46,7 @@ function theme_menu_overview_form($variables) { $indent = array( '#theme' => 'indentation', - '#size' => $element['#item']['depth'] - 1, + '#size' => $element['#item']->depth - 1, ); $row = array(); diff --git a/core/modules/menu_ui/src/MenuForm.php b/core/modules/menu_ui/src/MenuForm.php index 12d5cec..ceeb501 100644 --- a/core/modules/menu_ui/src/MenuForm.php +++ b/core/modules/menu_ui/src/MenuForm.php @@ -11,6 +11,7 @@ use Drupal\Core\Entity\EntityForm; use Drupal\Core\Entity\Query\QueryFactory; use Drupal\Core\Language\LanguageInterface; +use Drupal\Core\Menu\MenuLinkTreeElement; use Drupal\Core\Menu\MenuLinkTreeInterface; use Drupal\Core\Menu\MenuLinkManagerInterface; use Drupal\Core\Render\Element; @@ -180,19 +181,6 @@ public function save(array $form, array &$form_state) { } /** - * Recursively count the number of menu links in a tree. - */ - protected function countElements($tree, $count = 0) { - foreach ($tree as $element) { - $count++; - if (!empty($element['below'])) { - $this->countElements($element['below'], $count); - } - } - return $count; - } - - /** * Form constructor to edit an entire menu tree at once. * * Shows for one menu the menu links accessible to the current user and @@ -227,8 +215,14 @@ protected function buildOverviewForm(array &$form, array &$form_state) { $tree = $this->menuTree->transform($tree, $manipulators); $this->getRequest()->attributes->set('_menu_admin', FALSE); - $count = $this->countElements($tree); - $delta = max($count, 50); + // Determine the delta; the number of weights to be made available. + $count = function(array $tree) { + $sum = function ($carry, MenuLinkTreeElement $item) { + return $carry + $item->count(); + }; + return array_reduce($tree, $sum); + }; + $delta = max($count($tree), 50); $form = array_merge($form, $this->buildOverviewTreeForm($tree, $delta)); $form['#empty_text'] = $this->t('There are no menu links yet. Add link.', array('@link' => url('admin/structure/menu/manage/' . $this->entity->id() .'/add'))); @@ -249,41 +243,41 @@ protected function buildOverviewForm(array &$form, array &$form_state) { */ protected function buildOverviewTreeForm($tree, $delta) { $form = &$this->overviewTreeForm; - foreach ($tree as $data) { - /** @var \Drupal\Core\Menu\MenuLinkInterface $item */ - $item = $data['link']; - if ($item) { - $id = 'menu_plugin_id:' . $item->getPluginId(); - $form[$id]['#item'] = $data; - $form[$id]['#attributes'] = $item->isHidden() ? array('class' => array('menu-disabled')) : array('class' => array('menu-enabled')); - $form[$id]['title']['#markup'] = \Drupal::linkGenerator()->generateFromUrl($item->getTitle(), $item->getUrlObject(), $item->getOptions()); - if ($item->isHidden()) { + foreach ($tree as $element) { + /** @var \Drupal\Core\Menu\MenuLinkInterface $link */ + $link = $element->link; + if ($link) { + $id = 'menu_plugin_id:' . $link->getPluginId(); + $form[$id]['#item'] = $element; + $form[$id]['#attributes'] = $link->isHidden() ? array('class' => array('menu-disabled')) : array('class' => array('menu-enabled')); + $form[$id]['title']['#markup'] = \Drupal::linkGenerator()->generateFromUrl($link->getTitle(), $link->getUrlObject(), $link->getOptions()); + if ($link->isHidden()) { $form[$id]['title']['#markup'] .= ' (' . $this->t('disabled') . ')'; } - elseif (($url = $item->getUrlObject()) && !$url->isExternal() && $url->getRouteName() == 'user.page') { + elseif (($url = $link->getUrlObject()) && !$url->isExternal() && $url->getRouteName() == 'user.page') { $form[$id]['title']['#markup'] .= ' (' . $this->t('logged in users only') . ')'; } $form[$id]['enabled'] = array( '#type' => 'checkbox', - '#title' => $this->t('Enable @title menu link', array('@title' => $item->getTitle())), + '#title' => $this->t('Enable @title menu link', array('@title' => $link->getTitle())), '#title_display' => 'invisible', - '#default_value' => !$item->isHidden(), + '#default_value' => !$link->isHidden(), ); $form[$id]['weight'] = array( '#type' => 'weight', '#delta' => $delta, - '#default_value' => $item->getWeight(), - '#title' => $this->t('Weight for @title', array('@title' => $item->getTitle())), + '#default_value' => $link->getWeight(), + '#title' => $this->t('Weight for @title', array('@title' => $link->getTitle())), '#title_display' => 'invisible', ); $form[$id]['id'] = array( '#type' => 'hidden', - '#value' => $item->getPluginId(), + '#value' => $link->getPluginId(), ); $form[$id]['parent'] = array( '#type' => 'hidden', - '#default_value' => $item->getParent(), + '#default_value' => $link->getParent(), ); // Build a list of operations. $operations = array(); @@ -291,7 +285,7 @@ protected function buildOverviewTreeForm($tree, $delta) { 'title' => $this->t('Edit'), ); // Allow for a custom edit link per plugin. - $edit_route = $item->getEditRoute(); + $edit_route = $link->getEditRoute(); if ($edit_route) { $operations['edit'] += $edit_route; // Bring the user back to the menu overview. @@ -301,26 +295,26 @@ protected function buildOverviewTreeForm($tree, $delta) { // Fall back to the standard edit link. $operations['edit'] += array( 'route_name' => 'menu_ui.link_edit', - 'route_parameters' => array('menu_link_plugin' => $item->getPluginId()), + 'route_parameters' => array('menu_link_plugin' => $link->getPluginId()), ); } // Links can either be reset or deleted, not both. - if ($item->isResetable()) { + if ($link->isResetable()) { $operations['reset'] = array( 'title' => $this->t('Reset'), 'route_name' => 'menu_ui.link_reset', - 'route_parameters' => array('menu_link_plugin' => $item->getPluginId()), + 'route_parameters' => array('menu_link_plugin' => $link->getPluginId()), ); } - elseif ($delete_link = $item->getDeleteRoute()) { + elseif ($delete_link = $link->getDeleteRoute()) { $operations['delete'] = $delete_link; $operations['delete']['query']['destination'] = $this->entity->url(); $operations['delete']['title'] = $this->t('Delete'); } - if ($item->isTranslatable()) { + if ($link->isTranslatable()) { $operations['translate'] = array( 'title' => $this->t('Translate'), - ) + (array) $item->getTranslateRoute(); + ) + (array) $link->getTranslateRoute(); } $form[$id]['operations'] = array( '#type' => 'operations', @@ -328,8 +322,8 @@ protected function buildOverviewTreeForm($tree, $delta) { ); } - if ($data['below']) { - $this->buildOverviewTreeForm($data['below'], $delta); + if ($element->subtree) { + $this->buildOverviewTreeForm($element->subtree, $delta); } } return $form; @@ -380,7 +374,7 @@ protected function submitOverviewForm(array $complete_form, array &$form_state) if ($updated_values) { // Use the ID from the actual plugin instance since the hidden value // in the form could be tampered with. - $this->menuLinkManager->updateLink($element['#item']['link']->getPLuginId(), $updated_values); + $this->menuLinkManager->updateLink($element['#item']->link->getPLuginId(), $updated_values); } } } diff --git a/core/modules/system/src/Controller/SystemController.php b/core/modules/system/src/Controller/SystemController.php index 61fe270..95725c4 100644 --- a/core/modules/system/src/Controller/SystemController.php +++ b/core/modules/system/src/Controller/SystemController.php @@ -118,7 +118,7 @@ public function overview($link_id) { drupal_set_message($this->t('One or more problems were detected with your Drupal installation. Check the status report for more information.', array('@status' => url('admin/reports/status'))), 'error'); } $top_tree = $this->menuLinkTree->buildSubtree($link_id, 1); - $tree = !empty($top_tree[$link_id]['below']) ? $top_tree[$link_id]['below'] : array(); + $tree = $top_tree[$link_id]->subtree; $manipulators = array( array('callable' => 'menu.default_tree_manipulators:checkAccess'), array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'), @@ -126,12 +126,13 @@ public function overview($link_id) { $tree = $this->menuLinkTree->transform($tree, $manipulators); $blocks = array(); // Load all menu links below it. - foreach ($tree as $key => $item) { - $block['title'] = $item['link']->getTitle(); - $block['description'] = $item['link']->getDescription(); + foreach ($tree as $key => $element) { + $link = $element->link; + $block['title'] = $link->getTitle(); + $block['description'] = $link->getDescription(); $block['content'] = array( '#theme' => 'admin_block_content', - '#content' => $this->systemManager->getAdminBlock($item['link']), + '#content' => $this->systemManager->getAdminBlock($link), ); if (!empty($block['content']['#content'])) { diff --git a/core/modules/system/src/SystemManager.php b/core/modules/system/src/SystemManager.php index 5d54692..2b9108a 100644 --- a/core/modules/system/src/SystemManager.php +++ b/core/modules/system/src/SystemManager.php @@ -185,8 +185,8 @@ public function getMaxSeverity(&$requirements) { * A render array suitable for drupal_render. */ public function getBlockContents() { - $instance = $this->menuActiveTrail->getActiveLink(); - if ($instance && $content = $this->getAdminBlock($instance)) { + $link = $this->menuActiveTrail->getActiveLink(); + if ($link && $content = $this->getAdminBlock($link)) { $output = array( '#theme' => 'admin_block_content', '#content' => $content, @@ -220,9 +220,9 @@ public function getAdminBlock(MenuLinkInterface $instance) { array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'), ); $tree = $this->menuTree->transform($tree, $manipulators); - foreach ($tree as $key => $item) { + foreach ($tree as $key => $element) { /** @var $link \Drupal\Core\Menu\MenuLinkInterface */ - $link = $item['link']; + $link = $element->link; $content[$key]['title'] = $link->getTitle(); $content[$key]['options'] = $link->getOptions(); $content[$key]['description'] = $link->getDescription(); diff --git a/core/modules/system/src/Tests/Cache/GenericCacheBackendUnitTestBase.php b/core/modules/system/src/Tests/Cache/GenericCacheBackendUnitTestBase.php index f6ae8f8..ff1e098 100644 --- a/core/modules/system/src/Tests/Cache/GenericCacheBackendUnitTestBase.php +++ b/core/modules/system/src/Tests/Cache/GenericCacheBackendUnitTestBase.php @@ -188,6 +188,14 @@ public function testSetGet() { $cached = $backend->get('test6'); $this->assert(is_object($cached), "Backend returned an object for cache id test6."); $this->assertIdentical($with_variable, $cached->data); + + $data = new \stdClass(); + $backend->set('test7', $data); + $expected_data = clone $data; + $data->this_should_not_be_in_the_cache = TRUE; + $cached = $backend->get('test7'); + $this->assert(is_object($cached), "Backend returned an object for cache id test7."); + $this->assertEqual($expected_data, $cached->data); } /** diff --git a/core/modules/system/src/Tests/Menu/MenuLinkTreeTest.php b/core/modules/system/src/Tests/Menu/MenuLinkTreeTest.php index 5216a01..92099ba 100644 --- a/core/modules/system/src/Tests/Menu/MenuLinkTreeTest.php +++ b/core/modules/system/src/Tests/Menu/MenuLinkTreeTest.php @@ -7,6 +7,7 @@ namespace Drupal\system\Tests\Menu; +use Drupal\Core\Menu\MenuLinkTreeElement; use Drupal\simpletest\KernelTestBase; use Drupal\Tests\Core\Menu\MenuLinkMock; @@ -116,28 +117,22 @@ public function testCreateLinksInMenu() { $this->menuLinkManager->createLink($instance->getPluginId(), $instance->getPluginDefinition()); } $tree = $this->linkTree->buildTree('mock'); - $this->assertEqual(count($tree), 5); - $this->assertEqual(count($this->flatten($tree)), 8); + + $count = function(array $tree) { + $sum = function ($carry, MenuLinkTreeElement $item) { + return $carry + $item->count(); + }; + return array_reduce($tree, $sum); + }; + + $this->assertEqual($count($tree), 8); $tree = $this->linkTree->buildSubtree('test.example2'); $top_link = reset($tree); - $this->assertEqual(count($top_link['below']), 1); - $child = reset($top_link['below']); - $this->assertEqual($child['link']->getPluginId(), $links[3]->getPluginId()); + $this->assertEqual(count($top_link->subtree), 1); + $child = reset($top_link->subtree); + $this->assertEqual($child->link->getPluginId(), $links[3]->getPluginId()); $height = $this->linkTree->getSubtreeHeight('test.example2'); $this->assertEqual($height, 3); } - /** - * Flatten a menu tree. - */ - public function flatten($tree) { - foreach ($tree as $key => $item) { - if ($tree[$key]['below']) { - $tree += $this->flatten($tree[$key]['below']); - } - unset($tree[$key]['below']); - } - return $tree; - } - } diff --git a/core/modules/system/src/Tests/Menu/MenuTreeStorageTest.php b/core/modules/system/src/Tests/Menu/MenuTreeStorageTest.php index d31707e..6d25768 100644 --- a/core/modules/system/src/Tests/Menu/MenuTreeStorageTest.php +++ b/core/modules/system/src/Tests/Menu/MenuTreeStorageTest.php @@ -255,32 +255,32 @@ public function testLoadTree() { $data = $this->treeStorage->loadTreeData('tools'); $tree = $data['tree']; - $this->assertEqual(count($tree['test1']['below']), 1); - $this->assertEqual(count($tree['test1']['below']['test2']['below']), 1); - $this->assertEqual(count($tree['test1']['below']['test2']['below']['test3']['below']), 0); - $this->assertEqual(count($tree['test4']['below']), 1); - $this->assertEqual(count($tree['test4']['below']['test5']['below']), 0); + $this->assertEqual(count($tree['test1']->subtree), 1); + $this->assertEqual(count($tree['test1']->subtree['test2']->subtree), 1); + $this->assertEqual(count($tree['test1']->subtree['test2']->subtree['test3']->subtree), 0); + $this->assertEqual(count($tree['test4']->subtree), 1); + $this->assertEqual(count($tree['test4']->subtree['test5']->subtree), 0); $data = $this->treeStorage->loadTreeData('tools', array('active_trail' => array('test4', 'test5'))); $tree = $data['tree']; - $this->assertEqual(count($tree['test1']['below']), 1); - $this->assertFalse($tree['test1']['in_active_trail']); - $this->assertEqual(count($tree['test1']['below']['test2']['below']), 1); - $this->assertFalse($tree['test1']['below']['test2']['in_active_trail']); - $this->assertEqual(count($tree['test1']['below']['test2']['below']['test3']['below']), 0); - $this->assertFalse($tree['test1']['below']['test2']['below']['test3']['in_active_trail']); - $this->assertEqual(count($tree['test4']['below']), 1); - $this->assertTrue($tree['test4']['in_active_trail']); - $this->assertEqual(count($tree['test4']['below']['test5']['below']), 0); - $this->assertTrue($tree['test4']['below']['test5']['in_active_trail']); + $this->assertEqual(count($tree['test1']->subtree), 1); + $this->assertFalse($tree['test1']->inActiveTrail); + $this->assertEqual(count($tree['test1']->subtree['test2']->subtree), 1); + $this->assertFalse($tree['test1']->subtree['test2']->inActiveTrail); + $this->assertEqual(count($tree['test1']->subtree['test2']->subtree['test3']->subtree), 0); + $this->assertFalse($tree['test1']->subtree['test2']->subtree['test3']->inActiveTrail); + $this->assertEqual(count($tree['test4']->subtree), 1); + $this->assertTrue($tree['test4']->inActiveTrail); + $this->assertEqual(count($tree['test4']->subtree['test5']->subtree), 0); + $this->assertTrue($tree['test4']->subtree['test5']->inActiveTrail); $data = $this->treeStorage->loadTreeData('tools', array('active_trail' => array('test4', 'test5'), 'only_active_trail' => TRUE)); $tree = $data['tree']; $this->assertTrue(empty($tree['test1'])); - $this->assertEqual(count($tree['test4']['below']), 1); - $this->assertTrue($tree['test4']['in_active_trail']); - $this->assertEqual(count($tree['test4']['below']['test5']['below']), 0); - $this->assertTrue($tree['test4']['below']['test5']['in_active_trail']); + $this->assertEqual(count($tree['test4']->subtree), 1); + $this->assertTrue($tree['test4']->inActiveTrail); + $this->assertEqual(count($tree['test4']->subtree['test5']->subtree), 0); + $this->assertTrue($tree['test4']->subtree['test5']->inActiveTrail); } /** diff --git a/core/modules/system/src/Tests/System/AdminTest.php b/core/modules/system/src/Tests/System/AdminTest.php index 3a15495..7b40c07 100644 --- a/core/modules/system/src/Tests/System/AdminTest.php +++ b/core/modules/system/src/Tests/System/AdminTest.php @@ -135,7 +135,7 @@ protected function getTopLevelMenuLinks() { // The system.admin link is normally the parent of all top-level admin links. $link_id = 'system.admin'; $top_tree = $menu_tree->buildSubtree($link_id, 1); - $tree = !empty($top_tree[$link_id]['below']) ? $top_tree[$link_id]['below'] : array(); + $tree = $top_tree[$link_id]->subtree; $manipulators = array( array('callable' => 'menu.default_tree_manipulators:checkAccess'), array('callable' => 'menu.default_tree_manipulators:flatten'), @@ -144,8 +144,8 @@ protected function getTopLevelMenuLinks() { // Transform the tree to a list of menu links. $menu_links = array(); - foreach ($tree as $item) { - $menu_links[] = $item['link']; + foreach ($tree as $element) { + $menu_links[] = $element->link; } return $menu_links; diff --git a/core/modules/system/system.module b/core/modules/system/system.module index 9fd85f4..230e596 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -1470,15 +1470,15 @@ function system_get_module_admin_tasks($module, array $info) { } $admin_tasks = array(); - foreach ($tree as $item) { - $instance = $item['link']; - if ($instance->getProvider() != $module) { + foreach ($tree as $element) { + $link = $element->link; + if ($link->getProvider() != $module) { continue; } $admin_tasks[] = array( - 'title' => $instance->getTitle(), - 'description' => $instance->getDescription(), - 'url' => $instance->getUrlObject(), + 'title' => $link->getTitle(), + 'description' => $link->getDescription(), + 'url' => $link->getUrlObject(), ); } diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module index 267ab3e..aa7eae9 100644 --- a/core/modules/toolbar/toolbar.module +++ b/core/modules/toolbar/toolbar.module @@ -427,23 +427,23 @@ function toolbar_prerender_toolbar_administration_tray(array $element) { } /** - * Tree manipulator that adds toolbar-specific attributes. + * Menu link tree manipulator that adds toolbar-specific attributes. * - * @param array $tree - * The menu tree to manipulate. + * @param \Drupal\Core\Menu\MenuLinkTreeElement[] $tree + * The menu link tree to manipulate. * - * @return array - * The manipulated menu tree. + * @return \Drupal\Core\Menu\MenuLinkTreeElement[] + * The manipulated menu link tree. */ -function toolbar_menu_navigation_links($tree) { - foreach ($tree as $key => $item) { - if (!empty($item['below'])) { - toolbar_menu_navigation_links($tree[$key]['below']); +function toolbar_menu_navigation_links(array $tree) { + foreach ($tree as $key => $element) { + if (!empty($element->subtree)) { + toolbar_menu_navigation_links($tree[$key]->subtree); } // Make sure we have a path specific ID in place, so we can attach icons // and behaviors to the menu links. - $link = $item['link']; + $link = $element->link; $url = $link->getUrlObject(); if ($url->isExternal()) { // This is an unusual case, so just get a distinct, safe string. @@ -456,10 +456,10 @@ function toolbar_menu_navigation_links($tree) { // Get the non-localized title to make the icon class. $definition = $link->getPluginDefinition(); - $tree[$key]['options']['attributes']['id'] = 'toolbar-link-' . $id; - $tree[$key]['options']['attributes']['class'][] = 'toolbar-icon'; - $tree[$key]['options']['attributes']['class'][] = 'toolbar-icon-' . strtolower(str_replace(' ', '-', $definition['title'])); - $tree[$key]['options']['attributes']['title'] = String::checkPlain($link->getDescription()); + $tree[$key]->options['attributes']['id'] = 'toolbar-link-' . $id; + $tree[$key]->options['attributes']['class'][] = 'toolbar-icon'; + $tree[$key]->options['attributes']['class'][] = 'toolbar-icon-' . strtolower(str_replace(' ', '-', $definition['title'])); + $tree[$key]->options['attributes']['title'] = String::checkPlain($link->getDescription()); } return $tree; } @@ -472,7 +472,7 @@ function toolbar_get_rendered_subtrees() { $menu_tree = \Drupal::service('menu.link_tree'); $link_id = 'system.admin'; $top_tree = $menu_tree->buildSubtree($link_id, 3); - $tree = !empty($top_tree[$link_id]['below']) ? $top_tree[$link_id]['below'] : array(); + $tree = $top_tree[$link_id]->subtree; $manipulators = array( array('callable' => 'menu.default_tree_manipulators:checkAccess'), array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'), @@ -480,17 +480,17 @@ function toolbar_get_rendered_subtrees() { ); $tree = $menu_tree->transform($tree, $manipulators); $subtrees = array(); - foreach ($tree as $tree_item) { + foreach ($tree as $element) { /** @var \Drupal\Core\Menu\MenuLinkInterface $item */ - $item = $tree_item['link']; - if ($tree_item['below']) { - $subtree = $menu_tree->render($tree_item['below']); + $link = $element->link; + if (!empty($element->subtree)) { + $subtree = $menu_tree->render($element->subtree); $output = drupal_render($subtree); } else { $output = ''; } - $id = str_replace(array('.', '<', '>'), array('-', '', '' ), $item->getUrlObject()->getRouteName()); + $id = str_replace(array('.', '<', '>'), array('-', '', '' ), $link->getUrlObject()->getRouteName()); $subtrees[$id] = $output; } diff --git a/core/tests/Drupal/Tests/Core/Menu/DefaultMenuLinkTreeManipulatorsTest.php b/core/tests/Drupal/Tests/Core/Menu/DefaultMenuLinkTreeManipulatorsTest.php index 88068c7..8962271 100644 --- a/core/tests/Drupal/Tests/Core/Menu/DefaultMenuLinkTreeManipulatorsTest.php +++ b/core/tests/Drupal/Tests/Core/Menu/DefaultMenuLinkTreeManipulatorsTest.php @@ -8,6 +8,7 @@ namespace Drupal\Tests\Core\Menu; use Drupal\Core\Menu\DefaultMenuLinkTreeManipulators; +use Drupal\Core\Menu\MenuLinkTreeElement; use Drupal\Tests\UnitTestCase; /** @@ -102,17 +103,17 @@ protected function mockTree() { 8 => MenuLinkMock::create(array('id' => 'test.example8', 'route_name' => 'example8', 'title' => 'quxqux', 'parent' => '')), ); $this->originalTree = array(); - $this->originalTree[1] = array('link' => $this->links[1], 'below' => array()); - $this->originalTree[2] = array('link' => $this->links[2], 'below' => array( - 3 => array('link' => $this->links[3], 'below' => array( - 4 => array('link' => $this->links[4], 'below' => array()), + $this->originalTree[1] = new MenuLinkTreeElement($this->links[1], FALSE, 1, FALSE, array()); + $this->originalTree[2] = new MenuLinkTreeElement($this->links[2], TRUE, 1, FALSE, array( + 3 => new MenuLinkTreeElement($this->links[3], TRUE, 2, FALSE, array( + 4 => new MenuLinkTreeElement($this->links[4], FALSE, 3, FALSE, array()), )), )); - $this->originalTree[5] = array('link' => $this->links[5], 'below' => array( - 7 => array('link' => $this->links[7], 'below' => array()), + $this->originalTree[5] = new MenuLinkTreeElement($this->links[5], TRUE, 1, FALSE, array( + 7 => new MenuLinkTreeElement($this->links[7], FALSE, 2, FALSE, array()), )); - $this->originalTree[6] = array('link' => $this->links[6], 'below' => array()); - $this->originalTree[8] = array('link' => $this->links[8], 'below' => array()); + $this->originalTree[6] = new MenuLinkTreeElement($this->links[6], FALSE, 1, FALSE, array()); + $this->originalTree[8] = new MenuLinkTreeElement($this->links[8], FALSE, 1, FALSE, array()); } /** @@ -125,17 +126,17 @@ public function testGenerateIndexAndSort() { $tree = $this->originalTree; $tree = $this->defaultMenuTreeManipulators->generateIndexAndSort($tree); - // Validate that parent items #1, #2, #5 and #6 exist on the root level. - $this->assertEquals($this->links[1]->getPluginId(), $tree['50000 foo test.example1']['link']->getPluginId()); - $this->assertEquals($this->links[2]->getPluginId(), $tree['50000 bar test.example2']['link']->getPluginId()); - $this->assertEquals($this->links[5]->getPluginId(), $tree['50000 foofoo test.example5']['link']->getPluginId()); - $this->assertEquals($this->links[6]->getPluginId(), $tree['50000 barbar test.example6']['link']->getPluginId()); - $this->assertEquals($this->links[8]->getPluginId(), $tree['50000 quxqux test.example8']['link']->getPluginId()); + // Validate that parent elements #1, #2, #5 and #6 exist on the root level. + $this->assertEquals($this->links[1]->getPluginId(), $tree['50000 foo test.example1']->link->getPluginId()); + $this->assertEquals($this->links[2]->getPluginId(), $tree['50000 bar test.example2']->link->getPluginId()); + $this->assertEquals($this->links[5]->getPluginId(), $tree['50000 foofoo test.example5']->link->getPluginId()); + $this->assertEquals($this->links[6]->getPluginId(), $tree['50000 barbar test.example6']->link->getPluginId()); + $this->assertEquals($this->links[8]->getPluginId(), $tree['50000 quxqux test.example8']->link->getPluginId()); - // Validate that child item #4 exists at the correct location in the hierarchy. - $this->assertEquals($this->links[4]->getPluginId(), $tree['50000 bar test.example2']['below']['50000 baz test.example3']['below']['50000 qux test.example4']['link']->getPluginId()); - // Validate that child item #7 exists at the correct location in the hierarchy. - $this->assertEquals($this->links[7]->getPluginId(), $tree['50000 foofoo test.example5']['below']['50000 bazbaz test.example7']['link']->getPluginId()); + // Validate that child element #4 exists at the correct location in the hierarchy. + $this->assertEquals($this->links[4]->getPluginId(), $tree['50000 bar test.example2']->subtree['50000 baz test.example3']->subtree['50000 qux test.example4']->link->getPluginId()); + // Validate that child element #7 exists at the correct location in the hierarchy. + $this->assertEquals($this->links[7]->getPluginId(), $tree['50000 foofoo test.example5']->subtree['50000 bazbaz test.example7']->link->getPluginId()); } /** @@ -158,34 +159,30 @@ public function testCheckAccess() { ))); $this->mockTree(); - $this->originalTree[5]['below'][7]['access'] = TRUE; - $this->originalTree[8]['access'] = FALSE; + $this->originalTree[5]->subtree[7]->access = TRUE; + $this->originalTree[8]->access = FALSE; $tree = $this->defaultMenuTreeManipulators->checkAccess($this->originalTree); // Menu link 1: route without parameters, access forbidden, hence removed. $this->assertFalse(array_key_exists(1, $tree)); // Menu link 2: route with parameters, access granted. - $item = $tree[2]; - $this->assertTrue(array_key_exists('access', $item)); - $this->assertTrue($item['access']); + $element = $tree[2]; + $this->assertTrue($element->access); // Menu link 3: route with parameters, access forbidden, hence removed, // including its children. - $this->assertFalse(array_key_exists(3, $tree[2]['below'])); + $this->assertFalse(array_key_exists(3, $tree[2]->subtree)); // Menu link 4: child of menu link 3, which already is removed. - $this->assertSame(array(), $tree[2]['below']); + $this->assertSame(array(), $tree[2]->subtree); // Menu link 5: no route name, treated as external, hence access granted. - $item = $tree[5]; - $this->assertTrue(array_key_exists('access', $item)); - $this->assertTrue($item['access']); + $element = $tree[5]; + $this->assertTrue($element->access); // Menu link 6: external URL, hence access granted. - $item = $tree[6]; - $this->assertTrue(array_key_exists('access', $item)); - $this->assertTrue($item['access']); + $element = $tree[6]; + $this->assertTrue($element->access); // Menu link 7: 'access' already set. - $item = $tree[5]['below'][7]; - $this->assertTrue(array_key_exists('access', $item)); - $this->assertTrue($item['access']); + $element = $tree[5]->subtree[7]; + $this->assertTrue($element->access); // Menu link 8: 'access' already set, to FALSE, hence removed. $this->assertFalse(array_key_exists(8, $tree)); } @@ -222,7 +219,7 @@ public function testExtractSubtreeOfActiveTrail() { // Link 5 in the active trail. $this->mockTree(); - $this->originalTree[5]['in_active_trail'] = TRUE; + $this->originalTree[5]->inActiveTrail = TRUE; // Get level 0. $tree = $this->defaultMenuTreeManipulators->extractSubtreeOfActiveTrail($this->originalTree, 0); $this->assertEquals(array(1, 2, 5, 6, 8), array_keys($tree)); @@ -235,7 +232,7 @@ public function testExtractSubtreeOfActiveTrail() { // Link 2 in the active trail. $this->mockTree(); - $this->originalTree[2]['in_active_trail'] = TRUE; + $this->originalTree[2]->inActiveTrail = TRUE; // Get level 0. $tree = $this->defaultMenuTreeManipulators->extractSubtreeOfActiveTrail($this->originalTree, 0); $this->assertEquals(array(1, 2, 5, 6, 8), array_keys($tree)); @@ -248,8 +245,8 @@ public function testExtractSubtreeOfActiveTrail() { // Links 2 and 3 in the active trail. $this->mockTree(); - $this->originalTree[2]['in_active_trail'] = TRUE; - $this->originalTree[2]['below'][3]['in_active_trail'] = TRUE; + $this->originalTree[2]->inActiveTrail = TRUE; + $this->originalTree[2]->subtree[3]->inActiveTrail = TRUE; // Get level 0. $tree = $this->defaultMenuTreeManipulators->extractSubtreeOfActiveTrail($this->originalTree, 0); $this->assertEquals(array(1, 2, 5, 6, 8), array_keys($tree)); diff --git a/core/tests/Drupal/Tests/Core/Menu/MenuLinkTreeElementTest.php b/core/tests/Drupal/Tests/Core/Menu/MenuLinkTreeElementTest.php new file mode 100644 index 0000000..39cda99 --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Menu/MenuLinkTreeElementTest.php @@ -0,0 +1,63 @@ + 'Tests \Drupal\Core\Menu\MenuLinkTreeElement', + 'description' => '', + 'group' => 'Menu', + ); + } + + /** + * Tests construction. + * + * @covers ::__construct + */ + public function testConstruction() { + $link = array(); + $item = new MenuLinkTreeElement($link, FALSE, 3, FALSE, array()); + $this->assertSame($link, $item->link); + $this->assertSame(FALSE, $item->hasChildren); + $this->assertSame(3, $item->depth); + $this->assertSame(FALSE, $item->inActiveTrail); + $this->assertSame(array(), $item->subtree); + } + + /** + * Tests count(). + * + * @covers ::count + */ + public function testCount() { + $link_1 = array(); + $link_2 = array(); + $child_item = new MenuLinkTreeElement($link_2, FALSE, 2, FALSE, array()); + $parent_item = new MenuLinkTreeElement($link_1, FALSE, 2, FALSE, array($child_item)); + $this->assertSame(1, $child_item->count()); + $this->assertSame(2, $parent_item->count()); + } + +}