From 9231c9cf62c101117e17a779d37348d1f5f59bdf Mon Sep 17 00:00:00 2001 From: catch <catch@35733.no-reply.drupal.org> Date: Mon, 12 Feb 2024 16:27:33 +0000 Subject: [PATCH] Issue #3409895 by acbramley, longwave, smustgrave: [regression] toUrl can incorrectly return edit-form url when another link template shares the canonical url --- core/lib/Drupal/Core/Entity/EntityBase.php | 13 ++++---- .../Tests/Core/Entity/EntityUrlTest.php | 32 ++++++++++++++++--- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/core/lib/Drupal/Core/Entity/EntityBase.php b/core/lib/Drupal/Core/Entity/EntityBase.php index 79e61b3e14a4..b05468cdca87 100644 --- a/core/lib/Drupal/Core/Entity/EntityBase.php +++ b/core/lib/Drupal/Core/Entity/EntityBase.php @@ -167,12 +167,13 @@ public function toUrl($rel = NULL, array $options = []) { // Use the canonical link template by default, or edit-form if there is not // a canonical one. if ($rel === NULL) { - $rel_candidates = array_intersect( - ['canonical', 'edit-form'], - array_flip($link_templates), - ); - $rel = array_shift($rel_candidates); - if ($rel === NULL) { + if (isset($link_templates['canonical'])) { + $rel = 'canonical'; + } + elseif (isset($link_templates['edit-form'])) { + $rel = 'edit-form'; + } + else { throw new UndefinedLinkTemplateException("Cannot generate default URL because no link template 'canonical' or 'edit-form' was found for the '{$this->getEntityTypeId()}' entity type"); } } diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityUrlTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityUrlTest.php index 2fc1f84b3f45..8e1bf3b2efaa 100644 --- a/core/tests/Drupal/Tests/Core/Entity/EntityUrlTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/EntityUrlTest.php @@ -110,27 +110,51 @@ public function testToUrlNoId() { } /** - * Tests the toUrl() method without specifying the $rel parameter.. + * Tests the toUrl() method without specifying the $rel parameter. + * + * It should throw an exception when neither canonical and edit-form link + * templates exist if no parameters are passed in. * * @covers ::toUrl */ - public function testToUrlDefault() { + public function testToUrlDefaultException(): void { $values = ['id' => $this->entityId]; $entity = $this->getEntity(UrlTestEntity::class, $values); $this->expectException(UndefinedLinkTemplateException::class); $this->expectExceptionMessage("Cannot generate default URL because no link template 'canonical' or 'edit-form' was found for the '" . $this->entityTypeId . "' entity type"); $entity->toUrl(); + } + /** + * Tests the toUrl() method without specifying the $rel parameter. + * + * It should return the edit-form or canonical link templates by default if + * they are registered. + * + * @covers ::toUrl + */ + public function testToUrlDefaultFallback(): void { + $values = ['id' => $this->entityId, 'langcode' => $this->langcode]; + $entity = $this->getEntity(UrlTestEntity::class, $values); $this->registerLinkTemplate('edit-form'); /** @var \Drupal\Core\Url $url */ $url = $entity->toUrl(); - $this->assertUrl('entity.test_entity.edit_form', ['test_entity' => $this->entityId], $entity, FALSE, $url); + $this->assertUrl('entity.test_entity.edit_form', ['test_entity' => $this->entityId], $entity, TRUE, $url); $this->registerLinkTemplate('canonical'); /** @var \Drupal\Core\Url $url */ $url = $entity->toUrl(); - $this->assertUrl('entity.test_entity.canonical', ['test_entity' => $this->entityId], $entity, FALSE, $url); + $this->assertUrl('entity.test_entity.canonical', ['test_entity' => $this->entityId], $entity, TRUE, $url); + + // Register multiple link templates with 2 that share the same path. + $this->entityType->getLinkTemplates()->willReturn([ + 'canonical' => "/test-entity/{test_entity}/canonical", + 'edit-form' => "/test-entity/{test_entity}/edit-form", + 'foobar' => "/test-entity/{test_entity}/canonical", + ]); + $url = $entity->toUrl(); + $this->assertUrl('entity.test_entity.canonical', ['test_entity' => $this->entityId], $entity, TRUE, $url); } /** -- GitLab