3

Imagine the following menu structure:

  • Page 1 type: article
  • Page 2 comes from a view
    • Page 3 type: desirable < want this
      • Page 4 type: random
        • Page 5 type: random
  • Page 6 type: article

Lets say I'm on Page 5. I want to know if any parent menu item's node has the content type desirable.

I got a menu item id menu_link_content:uuid for Page 5. My current approach is the following:

<?php

$values['menu_parent'] = 'main:menu_link_content:uuid';
list($menuName, $entityName, $uuid) = explode(':', $values['menu_parent'], 3);
$menuLinkManager = \Drupal::service('plugin.manager.menu.link');
$parents = $menuLinkManager->getParentIds($entityName . ':' . $uuid);

foreach ($parents as $parentPluginId) {

  $mlc_ids = \Drupal::database()
    ->select('menu_tree', 'mt')
    ->fields('mt', ['route_param_key'])
    ->condition('route_name', 'entity.node.canonical')
    ->condition('id', $parentPluginId)
    ->execute()
    ->fetchCol();

  // menu_tree gives back node=nid
  if ($mlc_id && strpos($mlc_id, 'node=') !== false) {
    // split node=nid into separate values
    list($entityString, $nid) = explode("=", $mlc_id, 2);

    // load the respective node and see if it is a project
    $parentNode = \Drupal::entityManager()->getStorage('node')->load($nid);

    if ($parentNode) {
      $parentType = $parentNode->getType();

      // we found the parent project node
      if ('project' == $parentType) {
        $node->set('field_project_ref', $nid);
        $node->save();
        drupal_set_message(
          t("The content was automatically added a project reference due to it's parent menu items."),
          'status'
        );

        break;
      }
    }
  }
}

So I would go on and load the node if the database statement found something and check the node type etc. I just wonder if there was a more performant/ better, out of the box way of doing that?

Something like

$menuLinkContent->getTargetEntity()->getType()

or

entityManager()->loadEntityFromMenu()

would be nice.

1 Answer 1

0

I don't think there's anything as simple as $menuLinkContent->getTargetEntity()->getType(). Though that would be nice and I'd love for someone to correct me on that.

Below I wrote a method that loads the menu, loops through the menulink objects, grabs the url objects from them and loads the nodes based on the path of the url object. Once it has the node it gets the content type from it. I doubt it's better performance wise, but it does take advantage of more of the out of the box stuff and might be a bit easier to read.

$menu_tree = \Drupal::menuTree();
$menu = reset(\Drupal::entityTypeManager()->getStorage('menu')->loadByProperties(['uuid' => $uuid]));
$menu_parameters = $menu_tree->getCurrentRouteMenuTreeParameters($menu->id());
$menu_tree_elements = $menu_tree->load($menu->id());

foreach($menu_tree_elements as $menu_tree_element){
    $path = $menu_tree_element->link->getUrlObject()->toString();
    $node = self::nodeFromPath($path);
    $contentType = $node->getType();
    foreach($menu_tree_elements->subtree as $subtree_menu_element){
        $path = $subtree_menu_element->link->getUrlObject()->toString();
        $node = self::nodeFromPath($path);
        $contentType = $node->getType();             
    }
}

function nodeFromPath($path){
        $path = \Drupal::service('path.alias_manager')
            ->getPathByAlias($path);
        preg_match('/node\/(\d+)/', $path, $matches)) {
        $nid = $matches[1];
        return Node::load($nid);
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.