Problem/Motivation

When dealing with Menu Link plugins programmatically, a developer might need to retrieve the content entity to access their fields or translations, at the moment the current best way to do this, seems to load the the entity using the uuid.

Steps to reproduce

N/A

Proposed resolution

Make the getEntity method public so it can be used from the \Drupal\menu_link_content\Plugin\Menu\MenuLinkContent plugin.

Remaining tasks

- Approve the change
- Find a suitable test.
- Create a Change Record.

User interface changes

N/A

API changes

Visibility of MenuLinkContent::getEntity changed to public.

Data model changes

N/A

Release notes snippet

Before the change (extracted from) https://drupal.stackexchange.com/questions/235754/get-menu-link-item-fro...

if ($link instanceof \Drupal\menu_link_content\Plugin\Menu\MenuLinkContent) {
  $uuid = $link->getDerivativeId();
  $entity = \Drupal::service('entity.repository')
    ->loadEntityByUuid('menu_link_content', $uuid);
  $field_value = $entity->field_example->value;
}

After:

if ($link instanceof \Drupal\menu_link_content\Plugin\Menu\MenuLinkContent) {
  $entity = $link->getEntity();
  $field_value = $entity->field_example->value;
}

Original report by Grimreaper

Hello,

When manipulating menu, it would be convenient to be able to access the menu link content entity easily.

Setting the visibility of the getEntity method would help.

I will upload a patch.

Comments

Grimreaper created an issue. See original summary.

grimreaper’s picture

Status: Active » Needs review
StatusFileSize
new1.15 KB

Here is a patch.

Thanks for the review.

webapp's’s picture

Looks great!

stijnstroobants’s picture

Status: Needs review » Reviewed & tested by the community

Patch works as expected!
Thanks!

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 2: drupal-menulinkcontent_get_entity-2997790-2.patch, failed testing. View results

stijnstroobants’s picture

StatusFileSize
new759 bytes

Sorry, my patch was not necessary.
I recreated the patch because the original failed, but the fail was not related to the patch.

brentg’s picture

Status: Needs work » Reviewed & tested by the community

Seems to be working, removing the duplicate patch from @StijnStroobants and making the original one from @Grimreaper the default one.

Putting it back to reviewed and tested since it's still working

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 6: core-menulinkcontent-2997790-6.patch, failed testing. View results

webapp's’s picture

webapp's’s picture

grimreaper’s picture

Status: Needs work » Reviewed & tested by the community

Back to RTBC as the fail was not related to the patch.

larowlan’s picture

Status: Reviewed & tested by the community » Needs work

Can you elaborate on what the use-case is here? We like to limit the API we expose so want to make sure there is a genuine need for this.

Also, if we're making it public - having at least one usage of it in core would be useful - so a test would probably be the easist thing there, because otherwise, someone might change it back without realising

grimreaper’s picture

Hello,

On the project I am currently working on and for which the original patch has been made, we use it in several times.

  • We have added a custom boolean in the menu link content entity definition and in a custom menu tree manipulator we use "->getEntity()" on the menu link content plugin instance to get the menu link content to get access to the value of this boolean
  • We have made a custom breadcrumb builder on top of menu breadcrumb. In the building of the breadcrumb we have menu link content plugin instances and we need to access the menu link content entity:
foreach (array_reverse($this->getMenuTrail()) as $id) {
      /** @var \Drupal\menu_link_content\Plugin\Menu\MenuLinkContent $plugin */
      $plugin = $this->menuLinkManager->createInstance($id);
      $link_title = $plugin->getTitle();

      $entity = $plugin->getEntity();
grimreaper’s picture

Hello,

Also found out that this feature would be useful in the "menu per role" module: https://git.drupalcode.org/project/menu_per_role/blob/8.x-1.x/src/MenuPe...

// Sadly ::getEntity() is protected at the moment.
      $function = function () {
        return $this->getEntity();
      };
      $function = \Closure::bind($function, $instance, get_class($instance));
      /** @var \Drupal\menu_link_content\Entity\MenuLinkContent $entity */
      $entity = $function();

lozsmile’s picture

Version: 8.6.x-dev » 8.8.x-dev
Status: Needs work » Needs review
Issue tags: +Smile Drupal contribution tour 2019
StatusFileSize
new1.96 KB

Hello,

here's an updated patch for an automated test, thanks for review!

grimreaper’s picture

Queeing on 8.8.x branch.

grimreaper’s picture

Status: Needs review » Reviewed & tested by the community

Tests are green on the right branch :)

catch’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/modules/menu_link_content/tests/src/Unit/MenuLinkPluginTest.php
@@ -28,4 +28,13 @@ public function testGetInstanceReflection() {
 
+  /**
+   * @covers ::getEntity
+   */
+  public function testVisibilityGetEntity() {
+    $class = new \ReflectionClass(MenuLinkContent::class);
+    $instance_method = $class->getMethod('getEntity');
+    $this->assertEquals(true, $instance_method->isPublic());
+  }
+

This test isn't necessary, we know PHP visibility works. Do we have an existing test in core that checks that this actually returns an entity already?

Also if the method is going to be public it should probably be added to MenuLinkContentInterface.

Tagging for issue summary update too, and Needs Change Record because this is an API addition - the change record should include an example use-case.

catch’s picture

This time with the tags.

keenegan’s picture

Status: Needs work » Needs review
StatusFileSize
new1.72 KB

This could be very usefull. Here is the patch with the method added in the interface and the comments

keenegan’s picture

StatusFileSize
new1.59 KB

And here is the same patch that should work for 8.6.x

Edit : woops, not the right interface

The last submitted patch, 20: core-menulinkcontent-2997790-20.patch, failed testing. View results

keenegan’s picture

Status: Needs review » Needs work
keenegan’s picture

keenegan’s picture

Status: Needs work » Needs review
StatusFileSize
new759 bytes

Here is the patch for Drupal 8.6.x (without the interface changes, I needed it for a project)

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

jhedstrom’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests

This is still at NW for all the reasons mentioned above.

ravi.shankar’s picture

StatusFileSize
new769 bytes

I have re-rolled the patch #25

nterbogt’s picture

+1

The translatable_menu_link_url module could also use this to reduce a bunch of entity loads they've manually coded.
We would also use it for some custom menu rendering.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

matthieuscarset’s picture

In a project of mine, menu link content should not be visible if $entity->access('view') is not allowed. Therefore, I needed to access the menu link content's entity.

+1 for opening this issue and thank you for the work.

I confirm patch works as expected.

nterbogt’s picture

Status: Needs work » Reviewed & tested by the community
xjm’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs subsystem maintainer review

Thanks for proposing this issue!

This still needs a change record and an issue summary update. It may also need automated tests to confirm the method works properly when called externally. We should check for existing test coverage of the method and document what already exists. If the method doesn't already have test coverage, then we need to add a simple test for it.

Finally, we probably want subsystem maintainer approval to increase the visibility of this part of the API, so tagging for that. (If we don't receive subsystem maintainer review in a timely fashion, the framework managers can evaluate it instead.)

Thanks!

xjm’s picture

Also see #18 and #12. Three committers have now requested these things. :) Let's not mark it RTBC again until those things are addressed. Thanks!

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

pcambra’s picture

Not sure why the interface changes got removed, but I've added it back.

I'm tagging this as DX because it is a bit weird that you need to load the entity when needed (i.e. how do you retrieve a translated title of a menu from the plugin?) when it is already on the object.

I've tried to find a good usage for core so we can add a ad-hoc test, but haven't been able to find any, however, as some have pointed out, contrib modules could benefit of this visibility increase.

pcambra’s picture

Status: Needs work » Needs review
StatusFileSize
new1.76 KB

Wrong, patch, this is the right one.

Updating the summary shortly.

pcambra’s picture

Issue summary: View changes
Issue tags: -Needs issue summary update
pcambra’s picture

StatusFileSize
new2.49 KB

Ah wrong interface, we need to create one I think

matthieuscarset’s picture

Replying to @pcambra for a real use case in core is, for instance, if you want to check access by language.

joachim’s picture

+++ b/core/modules/menu_link_content/src/Plugin/Menu/MenuLinkContentInterface.php
@@ -0,0 +1,24 @@
+interface MenuLinkContentInterface extends MenuLinkInterface, ContainerFactoryPluginInterface {

A bit of a nitpick, but I don't think CFPI should be on here. It should stay on the class.

If a plugin class has DI, then that's an implementation detail of that particular class. It's not a behaviour we expect menu link plugins to have in general.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

samirmtl’s picture

StatusFileSize
new1.64 KB

Hi
I was faced this issue, in our context, we are using graphql-4.x producers to fetch the menu via GraphQl calls, in a multilanguale website, we must return the current language of the menu_link_content properties, and in a decouled Drupal website the language context is not easy to deal with, the graphQl Producer method had to access to the menu_link_content entity to be able to get correct field languages.
Now our problem and after updating to last Drupal Core 9.4.8, the pathes here, are not applied any more onour Drupal Deployement pipeline (that uses composer install)
I agree with @joachim, " I don't think CFPI should be on here. It should stay on the class."

ravi.shankar’s picture

StatusFileSize
new1.64 KB
new998 bytes

Added reroll of patch #46.

anchal_gupta’s picture

StatusFileSize
new3.13 KB
new4.77 KB

I have fixed CS error.

pooja saraah’s picture

StatusFileSize
new7.04 KB
new1.69 KB

Fixed failed commands on #48
Attached interdiff patch

shubham chandra’s picture

StatusFileSize
new1.76 KB

Re-rolled patch against #41 in drupal 10.1.x

gaurav-mathur’s picture

StatusFileSize
new1.49 KB

Re-rolled patch against #41 in drupal 10.1.x-dev

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new1.7 KB

The Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

angrytoast’s picture

Question: Per #18

Also if the method is going to be public it should probably be added to MenuLinkContentInterface.

Is this accurate? We're looking at the menu link plugin class, which extends MenuLinkBase which implements MenuLinkInterface

MenuLinkContentInterface is about a content entity class interface.

Should it be on MenuLinkInterface or MenuLinkContentInterface?

mohit_aghera’s picture

Status: Needs work » Needs review
Issue tags: -Needs change record, -Needs tests
StatusFileSize
new4.43 KB
new4.43 KB

I think the patch in #46 #47 #48 #49 #50 #51 seems incorrect re-rolls.
All are missing the new interface added in patch #40
Hiding all 5 patches.

- Adding a new test case to validate the getEntity method and validate the return value.
- CR added here https://www.drupal.org/node/3361300

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

smustgrave’s picture

Been 3 years without submaintainer review so moving to framework.

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

To get this in front of a committer for their thoughts.

catch’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/modules/menu_link_content/src/Plugin/Menu/MenuLinkContent.php
@@ -9,11 +9,12 @@
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
+use Drupal\menu_link_content\MenuLinkContentInterface as MenuLinkContentEntityInterface;
 
 /**
  * Provides the menu link plugin for content menu links.
  */
-class MenuLinkContent extends MenuLinkBase implements ContainerFactoryPluginInterface {
+class MenuLinkContent extends MenuLinkBase implements MenuLinkContentInterface, ContainerFactoryPluginInterface {
 

It's a bit confusing having two classes called MenuLinkContentEntityInterface. I don't think I realised this would happen when I asked for the method to be added to the interface.

Sorry to contradict myself from 2019, but I think we should not add this interface and just make the method on the plugin class public instead.

I checked for duplicate test coverage and couldn't find any, so that bit is fine.

mohit_aghera’s picture

Status: Needs work » Needs review
StatusFileSize
new3.02 KB
new2.58 KB

Done, removed the additional interface and test is passing on local.

mohit_aghera’s picture

StatusFileSize
new2.91 KB
new2.71 KB

Oops, accidentally removed keyword.
Putting back.
Interdiff is against #54
Hiding #59

catch’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs framework manager review

OK this looks good.

It just being a public method on a plugin means there's no official bc guarantee, but in practice unless we do a major reworking of the menu links system again I can't see this changing dramatically, and for core I think it makes more sense than adding an interface for a plugin implementation.

  • lauriii committed 7961aba4 on 11.x
    Issue #2997790 by mohit_aghera, Keenegan, Grimreaper, lozsmile, catch,...
lauriii’s picture

Status: Reviewed & tested by the community » Fixed

Committed 7961aba and pushed to 11.x. Thanks!

grimreaper’s picture

Hi,

Thanks for the merge!

I think some info in the change record are wrong:
- Introduced in branch should be 11.x, not 10.2.x
- Introduced in version should be 11.0.0, not 10.2.0

Or am I confused with https://www.drupal.org/about/core/blog/new-drupal-core-branching-scheme-...?

lauriii’s picture

10.2.x will be branched from 11.x later this year. I’m not sure if the introduced in branch should 11.x or 10.2.x but the version is correct.

grimreaper’s picture

Thanks for the quick reply!

So I was confused :)

I also searched for a 10.2.x branch in Gitlab in the meantime and did not find one, so this is the explanation.

As Drupal 10.1.0 was out, I thought a 10.2.x branch would already exist.

Sorry!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.