Score:1

MenuLink vs MenuLinkContent - what's the point?

in flag

I'm struggling to figure out relationship between MenuLink and MenuLinkContent.

I'm creating new menu item like:

$menuItem = MenuLinkContent::create($params);

I can also query those elements like:

$menuItems = \Drupal::entityTypeManager()->getStorage('menu_link_content')->loadByProperties(['link.uri' => "internal:$path"]);

And that works well. Now if I need one of those object I want to get it's "siblings" - other object that share same parent. I have some weird structure:

$this->menuLinkManager = \Drupal::service('plugin.manager.menu.link');
$parentId = $menuItem->getParentId();
$parent = $this->menuLinkManager->createInstance($this->menuLinkManager->getDefinition($parentId)['id']);

And here I'm getting it's parent, but it's not MenuLinkContent object any more but instance of MenuLinkInterface. It has some fields as MenuLinkContent, but not all. I.e. I don't know how to get link path and similar.

There I can go further:

$siblings = $this->menuLinkManager->getChildIds($parent->getPluginId());

But main question is how to get MenuLinkContent when I have that MenuLinkInterface object?

Sub-question - why oh why is needed this parallel menu system and parallel menu classes?

Jaypan avatar
de flag
Interfaces are not objects, they are the definition of the requirements of the class that implements the interface. MenuLinkContent implements MenuLinkInterface, its likely that the object you are working with is actually a MenuLinkContent object.
4uk4 avatar
cn flag
See https://drupal.stackexchange.com/questions/259739/why-are-methods-for-going-from-the-menulinkcontent-menu-link-plugin-class-to-the
apaderno avatar
us flag
The [`MenuLinkContent`](https://api.drupal.org/api/drupal/core%21modules%21menu_link_content%21src%21Plugin%21Menu%21MenuLinkContent.php/class/MenuLinkContent/8.9.x) class implements [`MenuLinkInterface`](https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Menu%21MenuLinkInterface.php/interface/MenuLinkInterface/8.9.x) and [`ContainerFactoryPluginInterface`](https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Plugin%21ContainerFactoryPluginInterface.php/interface/ContainerFactoryPluginInterface/8.9.x).
apaderno avatar
us flag
Given that the second interface defines only the `create()` method, is there any method you need that isn't defined in the `MenuLinkInterface` interface?
apaderno avatar
us flag
(Also, be careful not to confuse the [`MenuLinkContent`](https://api.drupal.org/api/drupal/core%21modules%21menu_link_content%21src%21Plugin%21Menu%21MenuLinkContent.php/class/MenuLinkContent/8.9.x) class, which implements a plugin, with the [`MenuLinkContent`](https://api.drupal.org/api/drupal/core%21modules%21menu_link_content%21src%21Entity%21MenuLinkContent.php/class/MenuLinkContent/8.9.x) class that is an entity class.)
4uk4 avatar
cn flag
This is the same as block plugins and block_content entities. In both cases the stored entities are used to derive plugins. The topic I've linked and the next topic linked there demonstrate how you can determine the plugin derivative ID which is identical to the entity UUID.
in flag
So I need a way to work with menu items. To create them, set paths, weights, parent, to query their parents and their children. That's all. I believe MenuLinkContent is entity class @apaderno mentioned. But when I that menuLinkManager I get something else.
Score:0
cn flag
$siblings = $this->menuLinkManager->getChildIds($parent->getPluginId());

But main question is how to get MenuLinkContent when I have that MenuLinkInterface object?

There are two types of plugin IDs. Without or with a colon :.

Non-derived plugins

Without they point directly to a single plugin definition.

For example the admin menu

\Drupal::service('plugin.manager.menu.link')->getChildIds('system.admin');

consists mainly of non-derived menu links which IDs you find in *.links.menu.yml files.

Derived plugins

With colon the first part is the base plugin ID and the second part is the derivative ID.

For example, if you have created a multi-level main menu from UI and apply this command on a menu parent

\Drupal::service('plugin.manager.menu.link')->getChildIds('standard.front_page');

You get links like this

menu_link_content:421a421a-cb1d-33e7-a810-1e7341f7906b

for the base plugin MenuLinkContent (BTW also defined in a YAML file) with a deriver for MenuLinkContent entities (identified by UUID).

$entity = \Drupal::service('entity.repository')
  ->loadEntityByUuid('menu_link_content', '421a421a-cb1d-33e7-a810-1e7341f7906b');

If you have already a plugin instance you can get the UUID from the plugin object. See https://drupal.stackexchange.com/a/235769/47547

in flag
Thank you. I figured it out after following link from your comment but it's definitely good to have complete answer. IMHO it's unnecessary complicated: for some queries I need menu link manager, for others entity repository. Sometime id is just a number, like a node id, other time it's content_type:uuid. Some time you can access all the properties, sometime you can't. Again, IMHO having single repository, single id format, single class and always all fields available would make life much more easier. And worse, it's hard to find proper documentation/example. Forgive my naive point of view.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.