Problem/Motivation

Steps to reproduce:
Install, add a link to Tools menu and go to admin/structure/menu/manage/tools.
There's no link to delete the menu link. There's a reset link, but following that leads to an error:

Recoverable fatal error: Argument 1 passed to Drupal\Core\Menu\MenuTreeStorage::save() must be of the type array, null given, called in /home/sb56c5d1abc73ea6/www/core/lib/Drupal/Core/Menu/MenuLinkManager.php on line 405 and defined in Drupal\Core\Menu\MenuTreeStorage->save() (line 256 of /home/sb56c5d1abc73ea6/www/core/lib/Drupal/Core/Menu/MenuTreeStorage.php).
Notice: Undefined index: menu_link_content:749ebca4-77db-43af-9706-06d286d0479c in Drupal\Core\Menu\MenuLinkManager->resetInstance() (line 403 of /home/sb56c5d1abc73ea6/www/core/lib/Drupal/Core/Menu/MenuLinkManager.php).

Discovered in #2313263: Page not found after adding, editing or deleting a menu link:
In MenuForm.php we have:

        // Links can either be reset or deleted, not both.
        if ($link->isResettable()) {
          $operations['reset'] = array(
            'title' => $this->t('Reset'),
            'url' => Url::fromRoute('menu_ui.link_reset', ['menu_link_plugin' => $link->getPluginId()]),
          );
        }
        elseif ($delete_link = $link->getDeleteRoute()) {

Where isResettable() is:

interface MenuLinkInterface extends PluginInspectionInterface, DerivativeInspectionInterface {
...
  /**
   * Returns whether this link can be reset.
   *
   * In general, only links that store overrides using the
   * menu_link.static.overrides service should return TRUE for this method.
   *
   * @return bool
   *   TRUE if it can be reset, FALSE otherwise.
   */
  public function isResettable();

In MenuLinkBase.php:

abstract class MenuLinkBase extends PluginBase implements MenuLinkInterface {
...
  /**
   * {@inheritdoc}
   */
  public function isResettable() {
    return AccessResult::forbidden();
  }

This makes that if ($link->isResettable()) above always true.

Another usage sample from MenuLinkResetForm.php:

  /**
   * Checks access based on whether the link can be reset.
   *
   * @param \Drupal\Core\Menu\MenuLinkInterface $menu_link_plugin
   *   The menu link plugin being checked.
   *
   * @return \Drupal\Core\Access\AccessResultInterface
   *   The access result.
   */
  public function linkIsResettable(MenuLinkInterface $menu_link_plugin) {
    return AccessResult::allowedIf($menu_link_plugin->isResettable())->setCacheable(FALSE);
  }

Where allowedIf() is:

abstract class AccessResult implements AccessResultInterface, CacheableInterface {
...
  /**
   * Creates an allowed or neutral access result.
   *
   * @param bool $condition
   *   The condition to evaluate.
   *
   * @return \Drupal\Core\Access\AccessResult
   *   If $condition is TRUE, isAllowed() will be TRUE, otherwise isNeutral()
   *   will be TRUE.
   */
  public static function allowedIf($condition) {
    return $condition ? static::allowed() : static::neutral();
  }

Unless I'm missing something this turns AccessResult::forbidden() to AccessResult::allowed().

Proposed resolution

Make isResettable() return bool
or
Rename isResettable() to getSomething() or checkResetAccess() and fix usages?

Remaining tasks

User interface changes

API changes

Beta phase evaluation

Reference: https://www.drupal.org/core/beta-changes
Issue category Clear bug
Issue priority Major because it potentially affects quite some site builders.
Disruption Not disruptive

Comments

olli’s picture

Issue summary: View changes
olli’s picture

StatusFileSize
new1.07 KB
olli’s picture

Status: Active » Needs review

Status: Needs review » Needs work

The last submitted patch, 2: 2373017-2.patch, failed testing.

olli’s picture

Issue summary: View changes
Parent issue: » #2287071: Add cacheability metadata to access checks
StatusFileSize
new2.09 KB
new1.49 KB
olli’s picture

Status: Needs work » Needs review
olli’s picture

Issue summary: View changes
StatusFileSize
new1.07 KB
new3.16 KB

The last submitted patch, 7: 2373017-7-test_only.patch, failed testing.

olli’s picture

Status: Needs review » Needs work
+++ b/core/modules/menu_ui/src/Tests/MenuTest.php
@@ -102,6 +102,16 @@ function testMenu() {
+    $this->assertNoLinkByHref('admin/structure/menu/link/' . $this->items[0]->getPluginId() . '/reset');

This should have failed in test_only patch...

olli’s picture

Status: Needs work » Needs review
StatusFileSize
new1.37 KB
new3.46 KB
new1.17 KB

The last submitted patch, 10: 2373017-10-test_only.patch, failed testing.

olli’s picture

Title: MenuLinkInterface::isResettable() returns AccessResult not bool » No delete link when editing a menu, only reset links
Priority: Normal » Major
Issue summary: View changes
StatusFileSize
new3.45 KB

reroll

+++ b/core/lib/Drupal/Core/Menu/MenuLinkDefault.php
@@ -95,8 +94,7 @@ public function getDescription() {
   public function isResettable() {
     // The link can be reset if it has an override.
-    // @todo This will be cacheable after https://www.drupal.org/node/2040135.
-    return AccessResult::allowedIf($this->staticOverride->loadOverride($this->getPluginId()))->setCacheable(FALSE);
+    return (bool) $this->staticOverride->loadOverride($this->getPluginId());
   }

I wonder if I should move this @todo somewhere else.

olli’s picture

Issue summary: View changes
olli’s picture

Issue summary: View changes
olli’s picture

#12 Just a guess: move it to MenuLinkResetForm::linkIsResettable()?

moonpeak queued 2: 2373017-2.patch for re-testing.

The last submitted patch, 2: 2373017-2.patch, failed testing.

dawehner’s picture

Issue summary: View changes
Status: Needs review » Reviewed & tested by the community
+++ b/core/lib/Drupal/Core/Menu/MenuLinkBase.php
@@ -77,7 +76,7 @@ public function isExpanded() {
   public function isResettable() {
-    return AccessResult::forbidden();
+    return FALSE;
   }
 

+++ b/core/lib/Drupal/Core/Menu/MenuLinkDefault.php
@@ -95,8 +94,7 @@ public function getDescription() {
-    // @todo This will be cacheable after https://www.drupal.org/node/2040135.

... I guess its fine to not pretend to make the admin listing cacheable.

catch’s picture

Status: Reviewed & tested by the community » Fixed

Committed/pushed to 8.0.x, thanks!

  • catch committed f007e49 on 8.0.x
    Issue #2373017 by olli: No delete link when editing a menu, only reset...

Status: Fixed » Closed (fixed)

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