diff --git a/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php index 8bee9d98064d87fe9b88dbdff8c0929f66e742b2..7452a38eccf3a0980a31b24c4f31fc5691ec62f3 100644 --- a/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php +++ b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php @@ -184,14 +184,28 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen /** @var \Drupal\link\LinkItemInterface $item */ $item = $items[$delta]; + $display_uri = NULL; + if (!$item->isEmpty()) { + try { + // The current field value could have been entered by a different user. + // However, if it is inaccessible to the current user, do not display it + // to them. + if (\Drupal::currentUser()->hasPermission('link to any page') || $item->getUrl()->access()) { + $display_uri = static::getUriAsDisplayableString($item->uri); + } + } + catch (\InvalidArgumentException $e) { + // If $item->uri is invalid, show value as is, so the user can see what + // to edit. + // @todo Add logging here in https://www.drupal.org/project/drupal/issues/3348020 + $display_uri = $item->uri; + } + } $element['uri'] = [ '#type' => 'url', '#title' => $this->t('URL'), '#placeholder' => $this->getSetting('placeholder_url'), - // The current field value could have been entered by a different user. - // However, if it is inaccessible to the current user, do not display it - // to them. - '#default_value' => (!$item->isEmpty() && (\Drupal::currentUser()->hasPermission('link to any page') || $item->getUrl()->access())) ? static::getUriAsDisplayableString($item->uri) : NULL, + '#default_value' => $display_uri, '#element_validate' => [[static::class, 'validateUriElement']], '#maxlength' => 2048, '#required' => $element['#required'], diff --git a/core/modules/link/tests/src/Functional/LinkFieldTest.php b/core/modules/link/tests/src/Functional/LinkFieldTest.php index c6d2be3bd27454487130536c18c71b22144d6a9f..a0b118f65c167f9f6c78724eb00deef32da020ca 100644 --- a/core/modules/link/tests/src/Functional/LinkFieldTest.php +++ b/core/modules/link/tests/src/Functional/LinkFieldTest.php @@ -884,4 +884,72 @@ protected function renderTestEntity($id, $view_mode = 'full', $reset = TRUE) { return (string) $output; } + /** + * Test link widget exception handled if link uri value is invalid. + */ + public function testLinkWidgetCaughtExceptionEditingInvalidUrl(): void { + $field_name = $this->randomMachineName(); + $this->fieldStorage = FieldStorageConfig::create([ + 'field_name' => $field_name, + 'entity_type' => 'entity_test', + 'type' => 'link', + 'cardinality' => 1, + ]); + $this->fieldStorage->save(); + FieldConfig::create([ + 'field_storage' => $this->fieldStorage, + 'label' => 'Link', + 'bundle' => 'entity_test', + 'settings' => [ + 'title' => DRUPAL_OPTIONAL, + 'link_type' => LinkItemInterface::LINK_GENERIC, + ], + ])->save(); + + $entityTypeManager = $this->container->get('entity_type.manager'); + $entityTypeManager + ->getStorage('entity_form_display') + ->load('entity_test.entity_test.default') + ->setComponent($field_name, [ + 'type' => 'link_default', + ]) + ->save(); + + $entityTypeManager + ->getStorage('entity_view_display') + ->create([ + 'targetEntityType' => 'entity_test', + 'bundle' => 'entity_test', + 'mode' => 'full', + 'status' => TRUE, + ]) + ->setComponent($field_name, [ + 'type' => 'link', + ]) + ->save(); + + // Entities can be saved without validation, for example via migration. + // Link fields may contain invalid uris such as external URLs without + // scheme. + $invalidUri = 'www.example.com'; + $invalidLinkUrlEntity = $entityTypeManager + ->getStorage('entity_test') + ->create([ + 'name' => 'Test entity with invalid link URL', + $field_name => ['uri' => $invalidUri], + ]); + $invalidLinkUrlEntity->save(); + + // If a user without 'link to any page' permission edits an entity, widget + // checks access by converting uri to Url object, which will throw an + // InvalidArgumentException if uri is invalid. + $this->drupalLogin($this->drupalCreateUser([ + 'view test entity', + 'administer entity_test content', + ])); + $this->drupalGet("/entity_test/manage/{$invalidLinkUrlEntity->id()}/edit"); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->fieldValueEquals("{$field_name}[0][uri]", $invalidUri); + } + }