Follow-up to #2406749: Use a link field for custom menu link

Problem/Motivation

Postponed on #2416955: Convert MenuLinkContent to use a link widget

In the prior issue we are storing the user input by using a link field. The link field itself just has a URI, title and options stored.

However, for menu links referencing a node or other entity we should use a entity: URI. We don't need to do discovery and re-resolve those paths.

For links using a user-path: scheme we need to resolve the path every time we do menu rebuild - probably via plugin discovery as a way to re-process them

Steps to manual test the patch

Apply patch on local instance
Create a page views
Create menu link pointing to page views
check menu_tree table for route_name
Delete page views
Recreate page view - with different views name and same path
check menu_tree table again and look for route_name (It should have different route_name in the menu_tree table then before deleting views)

Proposed resolution

make these plugins participate in discovery and resolve the route then.

Remaining tasks

Decide on implementation, do it.

User interface changes

N/A

API changes

None

Comments

pwolanin’s picture

Title: Use a link field for custom menu link » Re-process the user-entered-paths for custom menu links when there is a menu rebuild
yesct’s picture

Issue summary: View changes

small nit to clarify.

yesct’s picture

Issue tags: -Triaged D8 critical
tim.plunkett’s picture

Status: Needs review » Active
tim.plunkett’s picture

Issue summary: View changes
dawehner’s picture

Status: Active » Postponed

Note, without #2416955: Convert MenuLinkContent to use a link widget we can't distinct between entity URIs and user-path URIs.

yesct’s picture

Issue summary: View changes
yesct’s picture

Status: Postponed » Active
dawehner’s picture

Assigned: Unassigned » dawehner

I'll try to tackle it now.

pwolanin’s picture

Discussing with dawehner, let's use a deriver class so we stay fully within the plugin framework.

dawehner’s picture

StatusFileSize
new11.38 KB

WIP

dawehner’s picture

Status: Active » Needs review
StatusFileSize
new11.95 KB

Alright, there we go.

Status: Needs review » Needs work

The last submitted patch, 13: 2417423-13.patch, failed testing.

pwolanin’s picture

Status: Needs work » Needs review
StatusFileSize
new10.47 KB

Status: Needs review » Needs work

The last submitted patch, 15: 2417423-15.patch, failed testing.

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new795 bytes
new759 bytes

This could be it, as always, this is also part of some of the other patches.

almaudoh’s picture

Status: Needs review » Needs work

@dawehner looks like you uploaded the interdiff twice :)

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new10.36 KB

Ha, good catch! Here is the actual patch.

pwolanin’s picture

  1. +++ b/core/modules/menu_link_content/src/Plugin/Deriver/UserPathMenuLinkContentDeriver.php
    @@ -0,0 +1,90 @@
    +      $plugin_definitions[explode(':', $menu_link_content->getPluginId())[1]] = $menu_link_content->getPluginDefinition();
    

    I think this could use getDerivativeId()

  2. +++ b/core/modules/menu_link_content/src/Tests/TreeRediscoverSubscriberIntegrationTest.php
    @@ -0,0 +1,72 @@
    +    //\Drupal::service('cache.menu')->deleteAll();
    

    This isn't triggered by the rebuild?

dawehner’s picture

StatusFileSize
new10.29 KB
new1.76 KB

Fair!

larowlan’s picture

  1. +++ b/core/modules/menu_link_content/src/Entity/MenuLinkContent.php
    @@ -179,6 +180,17 @@ public static function preCreate(EntityStorageInterface $storage, array &$values
    +      $this->rediscover->value = TRUE;
    
    @@ -294,6 +306,10 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
    +    $fields['rediscover'] = BaseFieldDefinition::create('boolean')
    +      ->setLabel(t('Indicates whether the menu link should be rediscovered'))
    +      ->setSetting('default_value', FALSE);
    

    Can we add methods to MenuLinkContentInterface for this - and use that instead - makes the code more readable.

    ::setRequiresRediscovery()
    ::requiresRediscovery()?

  2. +++ b/core/modules/menu_link_content/src/Plugin/Deriver/UserPathMenuLinkContentDeriver.php
    @@ -0,0 +1,90 @@
    +   * @param \Drupal\Core\Entity\Query\QueryFactory $query_factory
    +   *   The query factory.
    ...
    +    $this->queryFactory = $query_factory;
    

    #2389335: Deprecate entity.query service and replace with using the entity storage's getQuery() method is trying to remove the entity.query service, can we use EntityManger->getStorage($entity_type_id)->getQuery() instead - we already have the entity manager for storage sake.

  3. +++ b/core/modules/menu_link_content/src/Plugin/Menu/MenuLinkContent.php
    @@ -17,6 +17,7 @@
    + *
    

    Not needed?

berdir’s picture

+++ b/core/modules/menu_link_content/src/Entity/MenuLinkContent.php
@@ -294,6 +306,10 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
       ->setSetting('default_value', FALSE);
 
+    $fields['rediscover'] = BaseFieldDefinition::create('boolean')
+      ->setLabel(t('Indicates whether the menu link should be rediscovered'))
+      ->setSetting('default_value', FALSE);
+

This apparently re-introduced incorrect default value settings, I think YesCT already openend an issue for the existing ones. there is no such setting, use is setDefaultValue() instead.

dawehner’s picture

StatusFileSize
new4.87 KB
new7.7 KB

Can we add methods to MenuLinkContentInterface for this - and use that instead - makes the code more readable.

::setRequiresRediscovery()
::requiresRediscovery()?

Realized that we can also just adapt the entity query.

#2389335: Remove entity.query service and replace with using the entity storage's getQuery() method is trying to remove the entity.query service, can we use EntityManger->getStorage($entity_type_id)->getQuery() instead - we already have the entity manager for storage sake.

Good point.

Not needed?

Fixed

This apparently re-introduced incorrect default value settings, I think YesCT already openend an issue for the existing ones. there is no such setting, use is setDefaultValue() instead.

Fixed my no longer using it.

dawehner’s picture

Assigned: dawehner » Unassigned

.

yched’s picture

About 'default_value' : found a couple more in current MenuLinkContent::baseFieldDefinitions()
Patch in #2418117: MenuLinkContent::baseFieldDefinitions() wrongly passes default values as a field setting

kgoel’s picture

Issue summary: View changes
dawehner’s picture

Thank you kalpana to manual test it AND add the manual instructions.

kgoel’s picture

I have manually tested the patch and menu_tree table does store different route_name after deleting the views. Reviewing the code and working on patch.

kgoel’s picture

Issue summary: View changes
Issue tags: -Needs change record updates
StatusFileSize
new7.66 KB
new1.13 KB

There is no API changes so it doesn't need change records.

wim leers’s picture

The patch is looking wonderfully simple :)

  1. +++ b/core/modules/menu_link_content/src/Plugin/Deriver/UserPathMenuLinkContentDeriver.php
    @@ -17,8 +16,8 @@
    + * compare to entity referenced ones.
    

    s/compare/compared/

  2. +++ b/core/modules/menu_link_content/src/Plugin/Deriver/UserPathMenuLinkContentDeriver.php
    @@ -0,0 +1,78 @@
    +   * Constructs a TreeRediscoverSubscriber instance.
    

    The class name is wrong; copy/paste remnant.

  3. +++ b/core/modules/menu_link_content/src/Tests/TreeRediscoverSubscriberIntegrationTest.php
    @@ -0,0 +1,71 @@
    +    // Ensure that the new route name / parameters are caught up by the tree.
    

    "are caught up" sounds a bit strange.

larowlan’s picture

Also should we be adding an index for the new field for performance sake?

dawehner’s picture

Also should we be adding an index for the new field for performance sake?

I would like to do that, but I could not figure out how to add an index to a base field ... given that the indexes seemed to live on the field type instead.

kgoel’s picture

working on this.

berdir’s picture

There is no API right now to add indexes for base fields or indexes that span multiple fields. The best you can do right now is visible in FileStorageSchema.

pwolanin’s picture

Status: Needs review » Needs work

I think the boolean field is really the right solution since it's more extensible by contrib or if we add other schemes later that need to be rediscovered.

@Bardir - can we index the boolean field?

kgoel’s picture

Status: Needs work » Needs review
StatusFileSize
new10.01 KB
new10.47 KB
larowlan’s picture

+++ b/core/modules/menu_link_content/src/Entity/MenuLinkContent.php
@@ -182,6 +182,16 @@ public static function preCreate(EntityStorageInterface $storage, array &$values
+      $this->rediscover->value = TRUE;

Would still like to see a method for this added to MenuLinkContentInterface, with a setter too

larowlan’s picture

Assigned: Unassigned » larowlan

working on #38 and #32

larowlan’s picture

Assigned: larowlan » Unassigned
Issue tags: +CriticalADay
StatusFileSize
new4.21 KB
new13.63 KB

Fixes #38 and #32
Hope I don't break anything

effulgentsia’s picture

Such a nice, clean, and direct way of solving this!

  1. +++ b/core/modules/menu_link_content/menu_link_content.links.menu.yml
    @@ -0,0 +1,4 @@
    +  deriver: \Drupal\menu_link_content\Plugin\Deriver\UserPathMenuLinkContentDeriver
    

    This class has nothing directly to do with user paths. It uses the rediscover field, which contrib can repurpose to cover other use cases too without needing to change the deriver, which is awesome. So, let's name it more generically, like simply MenuLinkContentDeriver. I don't think we even need to prefix with Rediscoverable or anything like that, since that's implicit to what a deriver is.

  2. +++ b/core/modules/menu_link_content/src/Entity/MenuLinkContent.php
    @@ -182,6 +183,16 @@ public static function preCreate(EntityStorageInterface $storage, array &$values
    +    if (parse_url($this->link->uri, PHP_URL_SCHEME) === 'user-path') {
    +      $this->setRequiresRediscovery(TRUE);
    +    }
    

    What if a path changes from user-path to not (e.g., link is edited and changed from custom path to an entity that was autocompleted)? Should we add a setRequiresRediscovery(FALSE) for that? I think that's only needed when the scheme changes, not every time there's a save.

  3. +++ b/core/modules/menu_link_content/src/MenuLinkContentInterface.php
    @@ -102,4 +102,35 @@ public function getWeight();
    +   * provided by a route in views module, but later this path may be served by
    +   * the panels module. Flagging a link as requiring rediscovery ensures that if
    

    Capitalize Views and Panels?

I haven't followed all the comments here. Is there any other unaddressed feedback? If not, I think this is ready once at least item 1 from this comment is done. The other items could be followups if needed.

pwolanin’s picture

StatusFileSize
new13.6 KB
new4.66 KB

ok, I think this addresses effulgentsia's feedback

larowlan’s picture

Status: Needs review » Reviewed & tested by the community

I think we're ready here - thanks all

The last submitted patch, 12: 2417423-12.patch, failed testing.

webchick’s picture

Status: Reviewed & tested by the community » Fixed

Ok great. This looks like what we talked about. Thanks for all the great testing in this issue! Bummer about the index thing, but that's a pre-existing condition.

Committed and pushed to 8.0.x. Thanks so much!!!

  • webchick committed a2ad348 on 8.0.x
    Issue #2417423 by dawehner, kgoel, pwolanin, larowlan: Re-process the...
yched’s picture

+++ b/core/modules/menu_link_content/src/Entity/MenuLinkContent.php
@@ -297,6 +311,10 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
+      ->setSetting('default_value', FALSE);

This re-reintroduced the wrong syntax for default values :-p
See #23 and #26

yched’s picture

Status: Fixed » Closed (fixed)

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