The menu_link_content entity has only one bundle in drupal core (with the same name as the entity).

During the development cycle before Drupal 8 stable there was an implementation for bundles with this entity but it ended up having one single bundle just like the user entity.

So the idea is that menu_link_content shouldn't be different than user at having a single bundle to play nice with field_ui and also be a good example for other single bundle entities. In the current situation we kind of half-care for contrib modules that might want to implement bundles since they can add the bundle key themselves but also force them to override the entity class to get somehow override the preCreate() method on the current class entity.

Issue fork drupal-2987537

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Chi created an issue. See original summary.

msankhala’s picture

@Chi Do you mean MenuLinkContent class should not have "bundle" key declared in entity_keys?

 *   entity_keys = {
 *     "id" = "id",
 *     "label" = "title",
 *     "langcode" = "langcode",
 *     "uuid" = "uuid",
 *     "bundle" = "bundle",
 *     "published" = "enabled",
 *   },

In https://cgit.drupalcode.org/drupal/tree/core/modules/menu_link_content/s...

Or can you add more information?

Chi’s picture

Yes, bundle key is redundant here I think.

zuhair_ak’s picture

Status: Active » Needs review
FileSize
501 bytes

Let us see what the test-bot say.

Status: Needs review » Needs work

The last submitted patch, 4: custom_menu_link_entiy_type-2987537-4.patch, failed testing. View results

Chi’s picture

I think property definition needs to be removed as well.

msankhala’s picture

Like Drupal 7 even if the content entity does not has any bundle it has one default bundle same as entity name? In this case, shouldn't `bundle` key is supposed to be there?

tstoeckler’s picture

Actually the idea with menu links was to explicitly have a bundle so that contrib could utilize that to e.g. add different fields for different types of menu links. So I'm not sure why this patch wants to remove it.

msankhala’s picture

@tstoeckler As you explained the purpose of `bundle` key for custom menu link entity. Should we add this to documentation?

Chi’s picture

Actually the idea with menu links was to explicitly have a bundle so that contrib could utilize that

@tstoeckler, why does menu link have no "bundle_entity_type" property then?

tstoeckler’s picture

@Chi, so menu link bundles are not controlled by a config entity type. Instead a contrib/custom module could implement hook_entity_bundle_info() to hardcode a new bundle and attach custom logic to that bundle.

Chi’s picture

Title: Custom menu link entity type should not declare "bundle" entity key » Document why custom menu link entity type declares "bundle" entity key
Category: Bug report » Task
Issue tags: +Documentation

Thanks for clarification. I wonder if there are any contributed modules that took advantage of bundle property. We might need to document this.

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

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

rodrigoaguilera’s picture

Title: Document why custom menu link entity type declares "bundle" entity key » Custom menu link entity type should not declare "bundle" entity key
Status: Needs work » Needs review
Issue tags: -Documentation
Related issues: +#2311295: Introduce MenuLinkContent bundles
FileSize
2.54 KB

I think we should go back to the original purpose of removing the bundle key that core does not use at all and fills the database.

The user entity has no bundle key but contrib modules can alter that and it. An example:

https://git.drupalcode.org/project/user_bundle/blob/8.x-1.x/user_bundle....

I wouldn't care about the menu_link_content implementing its own way of being mono bundle but is making more difficult to add fieldable menu items.
This part of field_ui expect mono bundle entities like user to have no bundle key:

https://git.drupalcode.org/project/drupal/blob/8.8.x/core/modules/field_...

So if you want for the field_ui module to automatically ad the proper routes workarounds like this need to be applied.
https://git.drupalcode.org/project/menu_item_fields/blob/8.x-1.x/modules...

I feel we should not change field_ui to support the menu_link_content entity but to be consistent in the way mono bundle entities are implemented in core.

To illustrate more this is the preCreate method on the entity that implements its own way of being mono bundle.
https://git.drupalcode.org/project/drupal/blob/8.8.x/core/modules/menu_l...

As far as I know menu_item_extras is the only contrib module that implements bundles for menu items and for them the disruption would be to add a check for the existence of the bundle key to add it themselves. In fact for menu_item_extras the column they actually use for the bundle is not bundle but menu_name so when we get rid of:

 *   entity_keys = {
...
 *     "bundle" = "bundle",
 *     "published" = "enabled",
 *   },

They can do something like:

 *   entity_keys = {
...
 *     "bundle" = "menu_name",
 *     "published" = "enabled",
 *   },

I am open to the possibility of having bundles for menu_link_content entities in the future but I feel having fields + view modes in core for menu_link_content entities is simpler and will solve many use cases that bundles can also solve. That is why I started the menu_item_fields module.

We discussed a bit also about bundles in menu items on the following issue
#2311295: Introduce MenuLinkContent bundles

So the general idea is that menu_link_content shouldn't be different than user at having a single bundle to play nice with field_ui and also be a good example for other single bundle entities. In the current situation we kind of half-care for contrib modules that might want to implement bundles since they can add the bundle key themselves but also force them to override the entity class to get rid of that preCreate().

Let see what the testbot thinks about removing the bundle from the module.

Status: Needs review » Needs work

The last submitted patch, 14: 2987537-remove-bundle-menu-link-content-14.patch, failed testing. View results

rodrigoaguilera’s picture

Issue summary: View changes
Status: Needs work » Needs review
FileSize
4.07 KB
1.53 KB

The patch was missing the update of the schema. Let's hope we get less errors.

I also updated the issue summary.

Status: Needs review » Needs work

The last submitted patch, 16: 2987537-remove-bundle-menu-link-content-16.patch, failed testing. View results

rodrigoaguilera’s picture

Status: Needs work » Needs review
FileSize
1.54 KB
5.61 KB

As expected there is more tests that assume there is a bundle

Darren Oh’s picture

Issue tags: +Seattle2019
tstoeckler’s picture

+++ b/core/modules/menu_link_content/menu_link_content.install
@@ -42,3 +44,25 @@ function menu_link_content_update_8601() {
+  if (\Drupal::entityTypeManager()->getStorage('menu_link_content') instanceof SqlEntityStorageInterface) {
+    if ($schema->tableExists($entity_type->getBaseTable())) {
+      $schema->dropField($entity_type->getBaseTable(), 'bundle');
+    }
+  }

So I was wondering why this is necessary. I guess the entity update manager will not uninstall the field if there are existing field values. And I guess we cannot replace the field values with NULL because the column is marked as NOT NULL. Is that the reasoning? Still a bit unfortunate, but I cannot come up with a better solution then, either... :-/

rodrigoaguilera’s picture

@tstoeckler It is necessary to delete the column even when the table is empty. I don't really know why. I expected the column to be deleted without that piece of code you highlight.

This piece of code is based on the function media_update_8700() .

tatarbj’s picture

Issue tags: +DrupalCampBelarus2019
AaronMcHale’s picture

Issue tags: +DCScot19
gambry’s picture

Working on this at DCScot19.

gambry’s picture

So I was wondering why this is necessary. [..] Is that the reasoning?

No. The reason appeared to be the updateEntityType() before the uninstallFieldStorageDefinition(). The update manager needs the right info from the entity type in order to delete its field. And if the field is removed from the entity too early, then the uninstallation (is that a word? :D ) doesn't happen properly.

Also patch doesn't have test coverage for the upgrade path, which I believe is required due the issues we've seen with the 'bundle' db column hanging there at some point during the work.

Tests are still running locally, hopefully testbot will be quicker... and green.

pau1_m’s picture

#25 works for me

pau1_m’s picture

Status: Needs review » Reviewed & tested by the community

^

Confirming bundle references removed on update. Updated test cases look fine.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 25: 2987537-remove-bundle-menu-link-content-25.patch, failed testing. View results

vacho’s picture

Status: Needs work » Reviewed & tested by the community

I review these aspects for the patch:
At new installations:

  • menu_link_content entity doesn't have the bundle field

At d8 instance already installed and working.

  • menu_link_content entity loss the bundle field

Running menu tests:

  • core/modules/menu_link_content/tests/src/Functional/Rest/MenuLinkContentResourceTestBase.php Works fine without bundle field
  • core/modules/jsonapi/tests/src/Functional/MenuLinkContentTest.php Works fine without bundle field
  • core/modules/menu_link_content/tests/src/Functional/Update/MenuLinkContentUpdateTest.php Test correctly if bundle is deleted
  • core/modules/menu_link_content/tests/src/Kernel/MenuLinksTest.php Works fine without bundle field Works fine without bundle field
  • About this point:

    Also patch doesn't have test coverage for the upgrade path, which I believe is required due the issues we've seen with the 'bundle' db column hanging there at some point during the work.

    This patch doesn't work over path value and all incidences at core/modules/menu_link_content/tests/src/Kernel/MenuLinksTest.php for bundle are covered.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 25: 2987537-remove-bundle-menu-link-content-25.patch, failed testing. View results

gambry’s picture

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

Priority: Minor » Normal
Status: Reviewed & tested by the community » Needs review
Issue tags: +Needs change record

Can we get a change record here?

I checked some contrib modules that provide extra entity features such as menu_item_extras, and they won't be disrupted by this change:

https://git.drupalcode.org/project/menu_item_extras/blob/8.x-2.x/menu_it...

rodrigoaguilera’s picture

I started the draft for the change record
https://www.drupal.org/node/3065722

What do you think?

Darren Oh’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs change record

That works. Thank you for keeping this moving.

gambry’s picture

Thanks @rodrigoaguilera . I made some changes on the CR, mainly rephrasing some parts, clearly stating what we are changing and linking some examples and alternatives.

catch’s picture

Does anything need to happen for configurable fields added to the menu link entity?

rodrigoaguilera’s picture

@catch
This issue is not strictly needed for that to happen, it will just make the enabling of field_ui for menu link entities a one-liner and we will clean a core mess.
I proposed the idea for configurable fields here
#3047131: Enable the field interface for creating fields and view modes on content menu items

But there is also a contrib module that demonstrates the workarounds needed to enable field UI without this change.
https://www.drupal.org/project/menu_item_fields

Basically the field_ui routes need to be added explicitly

catch’s picture

Status: Reviewed & tested by the community » Needs review

According to #14 this would disrupt at least one contributed module. Would be good to get feedback from @volega, and that might mean this needs to be a Drupal 9 patch.

catch’s picture

Tagging for explicit sign-off due to the API change.

Berdir’s picture

Technically, changes and update function looks solid, so +1 to that from an entity API maintainer perspective.

That said, agreed about this being tricky to change. One example would be any kind clients using rest/json api to create menu links, AFAIK several if not all normalizers will fail hard if you pass field data for non-existing fields, so it is possible that this would break things.

It would arguably be a bit weird, but one option would be to just stop defining bundle as a bundle key but keeping it as a bogus field, maybe even explicitly deprecating it in some way.

> and that might mean this needs to be a Drupal 9 patch.

So the fun part is that doing it in 9.0 would break another rule that you yourself recently agreed on with @amateescu and others.. that there are no schema changes/entity definition updates between 8.8 (or 8.9?) and 9.0, so how would we remove this in D9?

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.

mradcliffe’s picture

Issue tags: -Novice

Removing the novice tag as there are no longer any novice-related tasks.

quietone’s picture

There is an issue to migrate menu link bundles #3070495: Migration of menu links does not set the appropriate bundle but if they are going to be removed should that be done or not?

Anyone care to comment?

heddn’s picture

I think menu_item_extras does some interesting things with bundles. What does that mean, it means changing the bundle from menu_link_content is troublesome. I've already ran into it because of the use of that module with another little module I write recently: group_content_menu. It would make things a lot easier for group_content_menu if it was removed. But the BC implications are a little complicated and I don't think we can do that until 9.1 for full removal in 10.

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.

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.

rodrigoaguilera’s picture

Rerolled the latest patch as a MR.

From what I understand from the comments Drupal 9.2 is a good moment to do this kind of update.

I am not sure I understand @heddn comment. Can the modules that rely on the bundle field being there can just recreate it in their own update functions?

heddn’s picture

My point in #44 is that removing it from core into contrib is fine. But we'd have to do some fancy BC work around it and probably couldn't fully remove it until 10.0 Because while contrib could take it on, they wouldn't know to do so until they have a lengthy enough BC phase where we tell them to do that via deprecations. And I'm not sure with fields if that is possible. As in, how do we know where the field is created from? Core or contrib? There's not a really good way to deprecate the old data model.

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.

joachim’s picture

Isn't this going to break things (and delete data!!) for any site that has made use of different bundles for menu link entities?

alexverb’s picture

AaronMcHale’s picture

From the IS:

So the idea is that menu_link_content shouldn't be different than user at having a single bundle to play nice with field_ui and also be a good example for other single bundle entities.

For the record, I'm actually a fan of going the other direction and user following this pattern of specifying a bundle key, I have a use case for user bundles and it would mean the user_bundle module wouldn't need to hack the user annotation, giving it a slightly more supported foundation.

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.

Murz’s picture

Together with this, we should also fix the menu_ui module to start filling the value to the bundle property, because without it we have an error on the creation of a new menu item via the Node edit form:

The website encountered an unexpected error. Please try again later.

Drupal\Core\Entity\EntityStorageException: Missing bundle for entity type menu_link_content in Drupal\Core\Entity\ContentEntityStorageBase->doCreate() (line 125 of core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php).

Drupal\Core\Entity\ContentEntityStorageBase->create(Array) (Line: 1143)
Drupal\Core\Entity\ContentEntityBase::create(Array) (Line: 109)
_menu_ui_node_save(Object, Array) (Line: 338)
menu_ui_form_node_form_submit(Array, Object)

How to reproduce:
1. Get the default clean Drupal installation.
2. Apply the patch from this issue.
3. Go to /node/add/page
4. Check the "Provide a menu link".
5. Press "Save" and see the fatal error.

So the fix is to fill the bundle in the submit alter like this:

    // Create a new menu_link_content entity.
    $entity = MenuLinkContent::create([
      'link' => ['uri' => 'entity:node/' . $node->id()],
      'langcode' => $node->language()->getId(),
+     'bundle' => $values['menu_name'],
    ]);

I've updated the MR with this fix, and also have rebased on the fresh 10.1.x branch.

voleger’s picture

Menu Items Extras aims to use menu entities as a bundle for menu_link_content. But there are some historical limitations to that approach:
- fieldable menu items were not possible before drupal:8.4.x due to an issue #2903161: Fix incorrect FieldFormatter id for "weight" field in base field definition in display options.
- in core menu items in menu is portable across menu entities. With an entity bundle, the user can't move the menu_link_content entity across different menus without data loss in custom fields. Menu Item Extras introduce that limitation.
- some code did introduce the hardcoded bundle definition at the creation of menu_link_content entities. But this is redundant and removed where it was possible to do. For example #2923429: Remove 'bundle' key from menu link create method in 'Drupal\menu_link_content\Controller\MenuController' and #3322209: Menu Item Extras adding links integration issue
- the same menu can be rendered multiple times in the blocks in the same page layout. That requires the additional need to handle different view modes usage for menu_link_content entities in other blocks. That situation becomes more complicated if a specific menu block has to render different levels of menu items in different view modes.

Fieldable menu items + layout builder creates a new experience in managing the reach content of menu items without losing integration with sitemap functionality. Just check the usage of the project https://www.drupal.org/project/usage/menu_item_extras .

vigen.epam’s picture

Fill the bundle value on MenuLinkContent creation

Status: Needs review » Needs work

The last submitted patch, 60: 2987537-remove-bundle-menu-link-content-60.patch, failed testing. View results

rodrigoaguilera’s picture

Status: Needs work » Needs review

I added a rebase for Drupal 10.1.x in a new MR although this change will enter into Drupal 11 the earliest.

@murz
looks like you applied the patch and didn't run the database updates. Menu links should be created without bundle with this applied.

@voleger
Thanks for the details about how is to deal with the menu link entity and its weird mono-bundle.

@joachim @alexverb
Yes, the change proposed in its current state can break things for sites that use the bundle column for some purpose, mainly sites with menu_item_extras installed.
For solving that I'm thinking about adding more code to the hook_update_N to check before removing the bundle column if all values in it are "menu_link_content". In this case it should be safe.

For the the sites with menu_item_extras the module can be made responsible for maintaining the entity_keys with the "bundle" in them via hook_entity_type_build or hook_entity_type_alter. When there is a hook that adds back the bundle key to the entity definition the update_N can stop the deleting of the field. This can be achieved getting the entity definition, removing the bundle key, invoking the hooks and when it is not added back then the bundle column can be safely removed. When it is not removed is the responsibility of the hooks in contrib or custom modules to add it back when needed

That is two checks to add before actually running the part of the update that deletes data: All the links have the same bundle and there is no code adding a bundle key to the menu_link_content entity.

There would be two cases in which the update can't perform the delete. We can fail the the update by throwing an exception but I'm not sure that is a possibility.
Or some status variable can be set that enables a special mode in which the bundle is removed from the definition but added back by a hook.
This way we can later check for that special mode in upgrade_status or the status page to inform the user about the actions needed and finally remove that special mode in Drupal 12.

@AaronMcHale
user and menu_link_content being two different kinds of mono-bundle entities is a pattern that leads to many odd situations. I considered the other route of having the user entity have a fake but then the bundle becomes some kind of mandatory thing for any entity with no good examples of mono-bundle entities in core.

The key here is what @heddn wrote

There's not a really good way to deprecate the old data model.

so maybe this issue can pave the way so we are able to remove quirks from Drupal core.

AaronMcHale’s picture

Re #63: I'm not sure I'm comfortable with the idea that it should be left to contrib modules to add the bundle field when needed, I could quickly see that leading to all sorts of conflicts between modules. For instance, if two modules both attempt to add the bundle field/key but take slightly different approaches with that could cause problems with them conflicting. I think it makes more sense for Core to provide the field so that we can facilitate contrib using it and being able to do so consistently and in a reliable way.

When there is a hook that adds back the bundle key to the entity definition the update_N can stop the deleting of the field.

That also seems risky to me, can we really be sure that the field isn't being used on some sites in a way that we are not anticipating. To me it seems that there is a risk that some edge cases could come up and sites may break that we previously relying on this field, there could be sites with custom implementations which we cannot account for here.

pwolanin’s picture

I think the current approach is fine - we don't have to accommodate all possible contirb code that might have used this unintended behavior.

Also - if you want to define a kind of menu link content with bundle you can do that with another entity type - it doesn't have to leverage the core entity. For example: https://www.drupal.org/project/menu_link_config

rodrigoaguilera’s picture

@pwolanin Do you mean the current approach in core or the current approach of the MR ?

smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs Review Queue Initiative

Left some comments on the MR.

Also it had a failure that seems legit.

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.