diff --git a/core/core.services.yml b/core/core.services.yml index 9291712..2cd7c30 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -780,7 +780,7 @@ services: arguments: ['@language_manager', '@config.factory', '@page_cache_request_policy', '@page_cache_response_policy'] redirect_response_subscriber: class: Drupal\Core\EventSubscriber\RedirectResponseSubscriber - arguments: ['@url_generator'] + arguments: ['@url_generator', '@router.request_context'] tags: - { name: event_subscriber } request_close_subscriber: diff --git a/core/lib/Drupal/Core/EventSubscriber/RedirectResponseSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/RedirectResponseSubscriber.php index c67fbf5..4fdb59f 100644 --- a/core/lib/Drupal/Core/EventSubscriber/RedirectResponseSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/RedirectResponseSubscriber.php @@ -8,6 +8,7 @@ namespace Drupal\Core\EventSubscriber; use Drupal\Component\Utility\UrlHelper; +use Drupal\Core\Routing\RequestContext; use Drupal\Core\Routing\UrlGeneratorInterface; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\Event\FilterResponseEvent; @@ -32,9 +33,12 @@ class RedirectResponseSubscriber implements EventSubscriberInterface { * * @param \Drupal\Core\Routing\UrlGeneratorInterface $url_generator * The url generator service. + * @param \Drupal\Core\Routing\RequestContext $request_context + * The request context. */ - public function __construct(UrlGeneratorInterface $url_generator) { + public function __construct(UrlGeneratorInterface $url_generator, RequestContext $request_context) { $this->urlGenerator = $url_generator; + $this->requestContext = $request_context; } /** @@ -55,16 +59,21 @@ public function checkRedirectUrl(FilterResponseEvent $event) { // the following exception: // - Absolute URLs that point to this site (i.e. same base URL and // base path) are allowed. - if ($destination && (!UrlHelper::isExternal($destination) || UrlHelper::externalIsLocal($destination, $GLOBALS['base_url']))) { - $destination = UrlHelper::parse($destination); + if ($destination) { + if (!UrlHelper::isExternal($destination)) { + $destination = UrlHelper::parse($destination); - $path = $destination['path']; - $options['query'] = $destination['query']; - $options['fragment'] = $destination['fragment']; - // The 'Location' HTTP header must always be absolute. - $options['absolute'] = TRUE; + $path = $destination['path']; + $options['query'] = $destination['query']; + $options['fragment'] = $destination['fragment']; + // The 'Location' HTTP header must always be absolute. + $options['absolute'] = TRUE; - $response->setTargetUrl($this->urlGenerator->generateFromPath($path, $options)); + $response->setTargetUrl($this->urlGenerator->generateFromPath($path, $options)); + } + elseif (UrlHelper::externalIsLocal($destination, $this->requestContext->getCompleteBaseUrl())) { + $response->setTargetUrl($destination); + } } } } diff --git a/core/lib/Drupal/Core/Routing/RequestContext.php b/core/lib/Drupal/Core/Routing/RequestContext.php index 2b2df99..60a2749 100644 --- a/core/lib/Drupal/Core/Routing/RequestContext.php +++ b/core/lib/Drupal/Core/Routing/RequestContext.php @@ -7,6 +7,7 @@ namespace Drupal\Core\Routing; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Routing\RequestContext as SymfonyRequestContext; @@ -19,6 +20,13 @@ class RequestContext extends SymfonyRequestContext { /** + * The scheme, host and base URL, for example "http://example.com/d8". + * + * @var string + */ + protected $completeBaseUrl; + + /** * Populates the context from the current request from the request stack. * * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack @@ -27,4 +35,30 @@ public function fromRequestStack(RequestStack $request_stack) { $this->fromRequest($request_stack->getCurrentRequest()); } + /** + * {@inheritdoc} + */ + public function fromRequest(Request $request) { + parent::fromRequest($request); + + // @todo Extract the code in DrupalKerne::initializeRequestGlobals. + if (isset($GLOBALS['base_url'])) { + $this->setCompleteBaseUrl($GLOBALS['base_url']); + } + } + + /** + * Gets the scheme, host and base URL. + * + * For example on a subdir installation "d8" it should be + * "https://example.com/d8". + */ + public function getCompleteBaseUrl() { + return $this->completeBaseUrl; + } + + public function setCompleteBaseUrl($complete_base_url) { + $this->completeBaseUrl = $complete_base_url; + } + } diff --git a/core/modules/comment/src/CommentManager.php b/core/modules/comment/src/CommentManager.php index c905a23..afab74b 100644 --- a/core/modules/comment/src/CommentManager.php +++ b/core/modules/comment/src/CommentManager.php @@ -263,7 +263,7 @@ public function forbiddenMessage(EntityInterface $entity, $field_name) { $destination = array('destination' => 'comment/reply/' . $entity->getEntityTypeId() . '/' . $entity->id() . '/' . $field_name . '#comment-form'); } else { - $destination = array('destination' => $entity->getSystemPath() . '#comment-form'); + $destination = array('destination' => $entity->url('canonical', array('absolute' => TRUE)) . '#comment-form'); } if ($this->userConfig->get('register') != USER_REGISTER_ADMINISTRATORS_ONLY) { diff --git a/core/modules/comment/src/Controller/CommentController.php b/core/modules/comment/src/Controller/CommentController.php index 4af3f05..84fbf72 100644 --- a/core/modules/comment/src/Controller/CommentController.php +++ b/core/modules/comment/src/Controller/CommentController.php @@ -128,7 +128,7 @@ public function commentPermalink(Request $request, CommentInterface $comment) { // Find the current display page for this comment. $page = $this->entityManager()->getStorage('comment')->getDisplayOrdinal($comment, $field_definition->getSetting('default_mode'), $field_definition->getSetting('per_page')); // @todo: Cleaner sub request handling. - $redirect_request = Request::create($entity->getSystemPath(), 'GET', $request->query->all(), $request->cookies->all(), array(), $request->server->all()); + $redirect_request = Request::create($entity->url(), 'GET', $request->query->all(), $request->cookies->all(), array(), $request->server->all()); $redirect_request->query->set('page', $page); // @todo: Convert the pager to use the request object. $request->query->set('page', $page); diff --git a/core/modules/comment/src/Tests/CommentTranslationUITest.php b/core/modules/comment/src/Tests/CommentTranslationUITest.php index 64afbd7..6d253d8 100644 --- a/core/modules/comment/src/Tests/CommentTranslationUITest.php +++ b/core/modules/comment/src/Tests/CommentTranslationUITest.php @@ -129,7 +129,7 @@ protected function assertPublishedStatus() { $languages = $this->container->get('language_manager')->getLanguages(); // Check that simple users cannot see unpublished field translations. - $path = $entity->getSystemPath(); + $path = $entity->url(); foreach ($this->langcodes as $index => $langcode) { $translation = $this->getTranslation($entity, $langcode); $value = $this->getValue($translation, 'comment_body', $langcode); diff --git a/core/modules/config/src/Tests/ConfigEntityStatusUITest.php b/core/modules/config/src/Tests/ConfigEntityStatusUITest.php index 32065cf..4fc7735 100644 --- a/core/modules/config/src/Tests/ConfigEntityStatusUITest.php +++ b/core/modules/config/src/Tests/ConfigEntityStatusUITest.php @@ -38,14 +38,14 @@ function testCRUD() { $entity = entity_load('config_test', $id); // Disable an entity. - $disable_path = $entity->getSystemPath('disable'); + $disable_path = $entity->url('disable'); $this->assertLinkByHref($disable_path); $this->drupalGet($disable_path); $this->assertResponse(200); $this->assertNoLinkByHref($disable_path); // Enable an entity. - $enable_path = $entity->getSystemPath('enable'); + $enable_path = $entity->url('enable'); $this->assertLinkByHref($enable_path); $this->drupalGet($enable_path); $this->assertResponse(200); diff --git a/core/modules/config/src/Tests/ConfigEntityTest.php b/core/modules/config/src/Tests/ConfigEntityTest.php index 4bdbe25..2bf47f5 100644 --- a/core/modules/config/src/Tests/ConfigEntityTest.php +++ b/core/modules/config/src/Tests/ConfigEntityTest.php @@ -12,6 +12,7 @@ use Drupal\Core\Entity\EntityStorageException; use Drupal\Core\Config\Entity\ConfigEntityStorage; use Drupal\Core\Config\Entity\Exception\ConfigEntityIdLengthException; +use Drupal\Core\Url; use Drupal\simpletest\WebTestBase; /** @@ -122,7 +123,7 @@ function testCRUD() { } // The entity path can only be checked after saving. - $this->assertIdentical($config_test->getSystemPath(), 'admin/structure/config_test/manage/' . $expected['id']); + $this->assertIdentical($config_test->url(), Url::fromRoute('entity.config_test.edit_form', ['config_test' => $expected['id']])->toString()); // Verify that the correct status is returned and properties did not change. $this->assertIdentical($status, SAVED_NEW); diff --git a/core/modules/config/src/Tests/ConfigSingleImportExportTest.php b/core/modules/config/src/Tests/ConfigSingleImportExportTest.php index 8fc7e6a..b92e164 100644 --- a/core/modules/config/src/Tests/ConfigSingleImportExportTest.php +++ b/core/modules/config/src/Tests/ConfigSingleImportExportTest.php @@ -134,7 +134,7 @@ public function testImportSimpleConfiguration() { $this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import')); $this->assertRaw(t('Are you sure you want to update the %name @type?', array('%name' => $config->getName(), '@type' => 'simple configuration'))); $this->drupalPostForm(NULL, array(), t('Confirm')); - $this->drupalGet('/'); + $this->drupalGet(''); $this->assertText('Test simple import'); } diff --git a/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php b/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php index 3d0741b..645ca44 100644 --- a/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php +++ b/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php @@ -326,7 +326,7 @@ public function testContactConfigEntityTranslation() { foreach ($this->langcodes as $langcode) { $langcode_prefixes = array_merge(array(''), $this->langcodes); foreach ($langcode_prefixes as $langcode_prefix) { - $this->drupalGet(ltrim("$langcode_prefix/$translation_base_url/$langcode/edit")); + $this->drupalGet(ltrim("$langcode_prefix/$translation_base_url/$langcode/edit", ' /')); $this->assertFieldByName('translation[config_names][contact.form.feedback][label]', 'Website feedback - ' . $langcode); $this->assertText($label); } diff --git a/core/modules/contact/src/Tests/ContactPersonalTest.php b/core/modules/contact/src/Tests/ContactPersonalTest.php index 94ce04d..f6c58ea 100644 --- a/core/modules/contact/src/Tests/ContactPersonalTest.php +++ b/core/modules/contact/src/Tests/ContactPersonalTest.php @@ -86,7 +86,7 @@ function testSendPersonalContactMessage() { $this->drupalLogout(); $this->drupalLogin($this->adminUser); // Verify that the correct watchdog message has been logged. - $this->drupalGet('/admin/reports/dblog'); + $this->drupalGet('admin/reports/dblog'); $placeholders = array( '@sender_name' => $this->webUser->username, '@sender_email' => $this->webUser->getEmail(), diff --git a/core/modules/content_translation/src/Tests/ContentTranslationUITest.php b/core/modules/content_translation/src/Tests/ContentTranslationUITest.php index 0581893..a1a8eab 100644 --- a/core/modules/content_translation/src/Tests/ContentTranslationUITest.php +++ b/core/modules/content_translation/src/Tests/ContentTranslationUITest.php @@ -10,6 +10,7 @@ use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Language\Language; use Drupal\Core\Language\LanguageInterface; +use Drupal\language\Entity\ConfigurableLanguage; /** * Tests the Content Translation UI. @@ -52,9 +53,9 @@ protected function doTestBasicTranslation() { $this->entityId = $this->createEntity($values[$default_langcode], $default_langcode); $entity = entity_load($this->entityTypeId, $this->entityId, TRUE); $this->assertTrue($entity, 'Entity found in the database.'); - $this->drupalGet($entity->getSystemPath()); + $this->drupalGet($entity->url()); $this->assertResponse(200, 'Entity URL is valid.'); - $this->drupalGet($entity->getSystemPath('drupal:content-translation-overview')); + $this->drupalGet($entity->url('drupal:content-translation-overview')); $this->assertNoText('Source language', 'Source language column correctly hidden.'); $translation = $this->getTranslation($entity, $default_langcode); @@ -67,23 +68,26 @@ protected function doTestBasicTranslation() { // Add a content translation. $langcode = 'it'; + $language = ConfigurableLanguage::load($langcode); $values[$langcode] = $this->getNewEntityValues($langcode); - $content_translation_path = $entity->getSystemPath('drupal:content-translation-overview'); - $path = $langcode . '/' . $content_translation_path . '/add/' . $default_langcode . '/' . $langcode; + $content_translation_path = $entity->url('drupal:content-translation-overview', array('language' => $language)); + $path = $content_translation_path . '/add/' . $default_langcode . '/' . $langcode; $this->drupalPostForm($path, $this->getEditValues($values, $langcode), $this->getFormSubmitActionForNewTranslation($entity, $langcode)); if ($this->testLanguageSelector) { $this->assertNoFieldByXPath('//select[@id="edit-langcode-0-value"]', NULL, 'Language selector correctly disabled on translations.'); } $entity = entity_load($this->entityTypeId, $this->entityId, TRUE); - $this->drupalGet($entity->getSystemPath('drupal:content-translation-overview')); + $this->drupalGet($entity->url('drupal:content-translation-overview')); $this->assertNoText('Source language', 'Source language column correctly hidden.'); // Switch the source language. $langcode = 'fr'; + $language = ConfigurableLanguage::load($langcode); $source_langcode = 'it'; $edit = array('source_langcode[source]' => $source_langcode); - $path = $langcode . '/' . $content_translation_path . '/add/' . $default_langcode . '/' . $langcode; + $content_translation_path = $entity->url('drupal:content-translation-overview', array('language' => $language)); + $path = $content_translation_path . '/add/' . $default_langcode . '/' . $langcode; // This does not save anything, it merely reloads the form and fills in the // fields with the values from the different source language. $this->drupalPostForm($path, $edit, t('Change')); @@ -92,10 +96,10 @@ protected function doTestBasicTranslation() { // Add another translation and mark the other ones as outdated. $values[$langcode] = $this->getNewEntityValues($langcode); $edit = $this->getEditValues($values, $langcode) + array('content_translation[retranslate]' => TRUE); - $path = $langcode . '/' . $content_translation_path . '/add/' . $source_langcode . '/' . $langcode; + $path = $content_translation_path . '/add/' . $source_langcode . '/' . $langcode; $this->drupalPostForm($path, $edit, $this->getFormSubmitActionForNewTranslation($entity, $langcode)); $entity = entity_load($this->entityTypeId, $this->entityId, TRUE); - $this->drupalGet($entity->getSystemPath('drupal:content-translation-overview')); + $this->drupalGet($entity->url('drupal:content-translation-overview')); $this->assertText('Source language', 'Source language column correctly shown.'); // Check that the entered values have been correctly stored. @@ -115,15 +119,15 @@ protected function doTestBasicTranslation() { */ protected function doTestTranslationOverview() { $entity = entity_load($this->entityTypeId, $this->entityId, TRUE); - $this->drupalGet($entity->getSystemPath('drupal:content-translation-overview')); + $this->drupalGet($entity->url('drupal:content-translation-overview')); foreach ($this->langcodes as $langcode) { if ($entity->hasTranslation($langcode)) { $language = new Language(array('id' => $langcode)); - $view_path = \Drupal::urlGenerator()->generateFromPath($entity->getSystemPath(), array('language' => $language)); + $view_path = $entity->url('canonical', array('language' => $language)); $elements = $this->xpath('//table//a[@href=:href]', array(':href' => $view_path)); $this->assertEqual((string) $elements[0], $entity->getTranslation($langcode)->label(), format_string('Label correctly shown for %language translation.', array('%language' => $langcode))); - $edit_path = \Drupal::urlGenerator()->generateFromPath($entity->getSystemPath('edit-form'), array('language' => $language)); + $edit_path = $entity->url('edit-form', array('language' => $language)); $elements = $this->xpath('//table//ul[@class="dropbutton"]/li/a[@href=:href]', array(':href' => $edit_path)); $this->assertEqual((string) $elements[0], t('Edit'), format_string('Edit link correct for %language translation.', array('%language' => $langcode))); } @@ -140,15 +144,15 @@ protected function doTestOutdatedStatus() { // Mark translations as outdated. $edit = array('content_translation[retranslate]' => TRUE); - $path = $entity->getSystemPath('edit-form'); - $this->drupalPostForm($path, $edit, $this->getFormSubmitAction($entity, $langcode), array('language' => $languages[$langcode])); + $edit_path = $entity->url('edit-form', array('language' => $languages[$langcode])); + $this->drupalPostForm($edit_path, $edit, $this->getFormSubmitAction($entity, $langcode)); $entity = entity_load($this->entityTypeId, $this->entityId, TRUE); // Check that every translation has the correct "outdated" status, and that // the Translation fieldset is open if the translation is "outdated". foreach ($this->langcodes as $added_langcode) { - $options = array('language' => $languages[$added_langcode]); - $this->drupalGet($path, $options); + $path = $entity->url('edit-form', array('language' => ConfigurableLanguage::load($added_langcode))); + $this->drupalGet($path); if ($added_langcode == $langcode) { $this->assertFieldByXPath('//input[@name="content_translation[retranslate]"]', FALSE, 'The retranslate flag is not checked by default.'); $this->assertFalse($this->xpath('//details[@id="edit-content-translation" and @open="open"]'), 'The translation tab should be collapsed by default.'); @@ -157,8 +161,8 @@ protected function doTestOutdatedStatus() { $this->assertFieldByXPath('//input[@name="content_translation[outdated]"]', TRUE, 'The translate flag is checked by default.'); $this->assertTrue($this->xpath('//details[@id="edit-content-translation" and @open="open"]'), 'The translation tab is correctly expanded when the translation is outdated.'); $edit = array('content_translation[outdated]' => FALSE); - $this->drupalPostForm($path, $edit, $this->getFormSubmitAction($entity, $added_langcode), $options); - $this->drupalGet($path, $options); + $this->drupalPostForm($path, $edit, $this->getFormSubmitAction($entity, $added_langcode)); + $this->drupalGet($path); $this->assertFieldByXPath('//input[@name="content_translation[retranslate]"]', FALSE, 'The retranslate flag is now shown.'); $entity = entity_load($this->entityTypeId, $this->entityId, TRUE); $this->assertFalse($entity->translation[$added_langcode]['outdated'], 'The "outdated" status has been correctly stored.'); @@ -171,20 +175,20 @@ protected function doTestOutdatedStatus() { */ protected function doTestPublishedStatus() { $entity = entity_load($this->entityTypeId, $this->entityId, TRUE); - $path = $entity->getSystemPath('edit-form'); // Unpublish translations. foreach ($this->langcodes as $index => $langcode) { if ($index > 0) { + $path = $entity->url('edit-form', array('language' => ConfigurableLanguage::load($langcode))); $edit = array('content_translation[status]' => FALSE); - $this->drupalPostForm($langcode . '/' . $path, $edit, $this->getFormSubmitAction($entity, $langcode)); + $this->drupalPostForm($path, $edit, $this->getFormSubmitAction($entity, $langcode)); $entity = entity_load($this->entityTypeId, $this->entityId, TRUE); $this->assertFalse($entity->translation[$langcode]['status'], 'The translation has been correctly unpublished.'); } } // Check that the last published translation cannot be unpublished. - $this->drupalGet($path); + $this->drupalGet($entity->url('edit-form')); $this->assertFieldByXPath('//input[@name="content_translation[status]" and @disabled="disabled"]', TRUE, 'The last translation is published and cannot be unpublished.'); } @@ -193,7 +197,6 @@ protected function doTestPublishedStatus() { */ protected function doTestAuthoringInfo() { $entity = entity_load($this->entityTypeId, $this->entityId, TRUE); - $path = $entity->getSystemPath('edit-form'); $values = array(); // Post different authoring information for each translation. @@ -207,8 +210,8 @@ protected function doTestAuthoringInfo() { 'content_translation[name]' => $user->getUsername(), 'content_translation[created]' => format_date($values[$langcode]['created'], 'custom', 'Y-m-d H:i:s O'), ); - $prefix = $index > 0 ? $langcode . '/' : ''; - $this->drupalPostForm($prefix . $path, $edit, $this->getFormSubmitAction($entity, $langcode)); + $path = $entity->url('edit-form', array('language' => ConfigurableLanguage::load($langcode))); + $this->drupalPostForm($path, $edit, $this->getFormSubmitAction($entity, $langcode)); } $entity = entity_load($this->entityTypeId, $this->entityId, TRUE); @@ -237,8 +240,8 @@ protected function doTestTranslationDeletion() { // Confirm and delete a translation. $langcode = 'fr'; $entity = entity_load($this->entityTypeId, $this->entityId, TRUE); - $path = $entity->getSystemPath('edit-form'); - $this->drupalPostForm($langcode . '/' . $path, array(), t('Delete translation')); + $path = $entity->url('edit-form', array('language' => ConfigurableLanguage::load($langcode))); + $this->drupalPostForm($path, array(), t('Delete translation')); $this->drupalPostForm(NULL, array(), t('Delete')); $entity = entity_load($this->entityTypeId, $this->entityId, TRUE); if ($this->assertTrue(is_object($entity), 'Entity found')) { diff --git a/core/modules/content_translation/src/Tests/ContentTranslationWorkflowsTest.php b/core/modules/content_translation/src/Tests/ContentTranslationWorkflowsTest.php index 1c6ff21..69d564e 100644 --- a/core/modules/content_translation/src/Tests/ContentTranslationWorkflowsTest.php +++ b/core/modules/content_translation/src/Tests/ContentTranslationWorkflowsTest.php @@ -8,6 +8,7 @@ namespace Drupal\content_translation\Tests; use Drupal\Core\Language\LanguageInterface; +use Drupal\Core\Url; use Drupal\user\UserInterface; /** @@ -61,7 +62,7 @@ protected function setupEntity() { // Create a translation. $this->drupalLogin($this->translator); - $path = $this->entity->getSystemPath('drupal:content-translation-overview'); + $path = $this->entity->url('drupal:content-translation-overview'); $add_translation_path = $path . "/add/$default_langcode/{$this->langcodes[2]}"; $this->drupalPostForm($add_translation_path, array(), t('Save')); $this->rebuildContainer(); @@ -85,7 +86,7 @@ function testWorkflows() { // Check that translation permissions governate the associated operations. $ops = array('create' => t('Add'), 'update' => t('Edit'), 'delete' => t('Delete')); - $translations_path = $this->entity->getSystemPath('drupal:content-translation-overview'); + $translations_path = $this->entity->url('drupal:content-translation-overview'); foreach ($ops as $current_op => $item) { $user = $this->drupalCreateUser(array($this->getTranslatePermission(), "$current_op content translations")); $this->drupalLogin($user); @@ -118,23 +119,23 @@ protected function assertWorkflows(UserInterface $user, $expected_status) { $this->drupalLogin($user); // Check whether the user is allowed to access the entity form in edit mode. - $edit_path = $this->entity->getSystemPath('edit-form'); - $options = array('language' => $languages[$default_langcode]); + $options = array('language' => $languages[$default_langcode], 'absolute' => TRUE); + $edit_path = $this->entity->url('edit-form', $options); $this->drupalGet($edit_path, $options); $this->assertResponse($expected_status['edit'], format_string('The @user_label has the expected edit access.', $args)); // Check whether the user is allowed to access the translation overview. $langcode = $this->langcodes[1]; - $translations_path = $this->entity->getSystemPath('drupal:content-translation-overview'); - $options = array('language' => $languages[$langcode]); - $this->drupalGet($translations_path, $options); + $options = array('language' => $languages[$langcode], 'absolute' => TRUE); + $translations_path = $this->entity->url('drupal:content-translation-overview', $options); + $this->drupalGet($translations_path); $this->assertResponse($expected_status['overview'], format_string('The @user_label has the expected translation overview access.', $args)); // Check whether the user is allowed to create a translation. - $add_translation_path = $translations_path . "/add/$default_langcode/$langcode"; + $add_translation_path = Url::fromRoute('content_translation.translation_add_' . $this->entityTypeId, [$this->entityTypeId => $this->entity->id(), 'source' => $default_langcode, 'target' => $langcode], $options)->toString(); if ($expected_status['add_translation'] == 200) { $this->clickLink('Add'); - $this->assertUrl($add_translation_path, $options, 'The translation overview points to the translation form when creating translations.'); + $this->assertUrl($add_translation_path, array(), 'The translation overview points to the translation form when creating translations.'); // Check that the translation form does not contain shared elements for // translators. if ($expected_status['edit'] == 403) { @@ -142,33 +143,37 @@ protected function assertWorkflows(UserInterface $user, $expected_status) { } } else { - $this->drupalGet($add_translation_path, $options); + $this->drupalGet($add_translation_path); } $this->assertResponse($expected_status['add_translation'], format_string('The @user_label has the expected translation creation access.', $args)); // Check whether the user is allowed to edit a translation. $langcode = $this->langcodes[2]; - $edit_translation_path = $translations_path . "/edit/$langcode"; - $options = array('language' => $languages[$langcode]); + $options['language'] = $languages[$langcode]; + $edit_translation_path = Url::fromRoute('content_translation.translation_edit_' . $this->entityTypeId, [$this->entityTypeId => $this->entity->id(), 'language' => $langcode], $options)->toString(); + $options = ['language' => $languages[$langcode], 'absolute' => TRUE]; if ($expected_status['edit_translation'] == 200) { - $this->drupalGet($translations_path, $options); + $this->drupalGet($translations_path); $editor = $expected_status['edit'] == 200; if ($editor) { $this->clickLink('Edit', 2); // An editor should be pointed to the entity form in multilingual mode. - $this->assertUrl($edit_path, $options, 'The translation overview points to the edit form for editors when editing translations.'); + + // We need a new expected edit path with a new language. + $expected_edit_path = $this->entity->url('edit-form', $options); + $this->assertUrl($expected_edit_path, [], 'The translation overview points to the edit form for editors when editing translations.'); } else { $this->clickLink('Edit'); // While a translator should be pointed to the translation form. - $this->assertUrl($edit_translation_path, $options, 'The translation overview points to the translation form for translators when editing translations.'); + $this->assertUrl($edit_translation_path, array(), 'The translation overview points to the translation form for translators when editing translations.'); // Check that the translation form does not contain shared elements. $this->assertNoSharedElements(); } } else { - $this->drupalGet($edit_translation_path, $options); + $this->drupalGet($edit_translation_path, array()); } $this->assertResponse($expected_status['edit_translation'], format_string('The @user_label has the expected translation creation access.', $args)); } diff --git a/core/modules/entity_reference/src/Tests/EntityReferenceFieldTranslatedReferenceViewTest.php b/core/modules/entity_reference/src/Tests/EntityReferenceFieldTranslatedReferenceViewTest.php index 8480073..afb8045 100644 --- a/core/modules/entity_reference/src/Tests/EntityReferenceFieldTranslatedReferenceViewTest.php +++ b/core/modules/entity_reference/src/Tests/EntityReferenceFieldTranslatedReferenceViewTest.php @@ -121,6 +121,7 @@ protected function setUp() { $this->translatedLabel = $this->randomMachineName(); $this->setUpLanguages(); + $this->rebuildContainer(); $this->setUpContentTypes(); $this->enableTranslation(); $this->setUpEntityReferenceField(); @@ -131,8 +132,8 @@ protected function setUp() { * Tests if the translated entity is displayed in an entity reference field. */ public function testTranslatedEntityReferenceDisplay() { - $path = $this->referrerEntity->getSystemPath(); - $translation_path = $this->translateToLangcode . '/' . $path; + $path = $this->referrerEntity->url(); + $translation_path = $this->referrerEntity->url('canonical', ['language' => ConfigurableLanguage::load($this->translateToLangcode)]); $this->drupalGet($path); $this->assertText($this->labelOfNotTranslatedReference, 'The label of not translated reference is displayed.'); diff --git a/core/modules/forum/src/Tests/ForumTest.php b/core/modules/forum/src/Tests/ForumTest.php index dbd72b8..dae7883 100644 --- a/core/modules/forum/src/Tests/ForumTest.php +++ b/core/modules/forum/src/Tests/ForumTest.php @@ -108,7 +108,7 @@ protected function setUp() { */ function testForum() { //Check that the basic forum install creates a default forum topic - $this->drupalGet('/forum'); + $this->drupalGet('forum'); // Look for the "General discussion" default forum $this->assertRaw(t('General discussion'), "Found the default forum at the /forum listing"); diff --git a/core/modules/image/image.field.inc b/core/modules/image/image.field.inc index 3f44993..dbdbcc8 100644 --- a/core/modules/image/image.field.inc +++ b/core/modules/image/image.field.inc @@ -46,7 +46,7 @@ function template_preprocess_image_widget(&$variables) { * - item_attributes: An optional associative array of html attributes to be * placed in the img tag. * - image_style: An optional image style. - * - path: An optional array containing the link 'path' and link 'options'. + * - url: An optional \Drupal\Core\Url object. */ function template_preprocess_image_formatter(&$variables) { if ($variables['image_style']) { @@ -79,14 +79,4 @@ function template_preprocess_image_formatter(&$variables) { foreach (array('width', 'height', 'alt') as $key) { $variables['image']["#$key"] = $item->$key; } - - // The link path and link options are both optional, but for the options to be - // processed, the link path must at least be an empty string. - // @todo Add support for route names. - $variables['url'] = NULL; - if (isset($variables['path']['path'])) { - $path = $variables['path']['path']; - $options = isset($variables['path']['options']) ? $variables['path']['options'] : array(); - $variables['url'] = _url($path, $options); - } } diff --git a/core/modules/image/image.module b/core/modules/image/image.module index f1faacb..622af62 100644 --- a/core/modules/image/image.module +++ b/core/modules/image/image.module @@ -139,7 +139,7 @@ function image_theme() { 'file' => 'image.field.inc', ), 'image_formatter' => array( - 'variables' => array('item' => NULL, 'item_attributes' => NULL, 'path' => NULL, 'image_style' => NULL), + 'variables' => array('item' => NULL, 'item_attributes' => NULL, 'url' => NULL, 'image_style' => NULL), 'file' => 'image.field.inc', ), ); diff --git a/core/modules/image/src/Plugin/Field/FieldFormatter/ImageFormatter.php b/core/modules/image/src/Plugin/Field/FieldFormatter/ImageFormatter.php index e9ab03e..3b47a3b 100644 --- a/core/modules/image/src/Plugin/Field/FieldFormatter/ImageFormatter.php +++ b/core/modules/image/src/Plugin/Field/FieldFormatter/ImageFormatter.php @@ -178,15 +178,14 @@ public function settingsSummary() { */ public function viewElements(FieldItemListInterface $items) { $elements = array(); + $url = NULL; $image_link_setting = $this->getSetting('image_link'); // Check if the formatter involves a link. if ($image_link_setting == 'content') { $entity = $items->getEntity(); if (!$entity->isNew()) { - // @todo Remove when theme_image_formatter() has support for route name. - $uri['path'] = $entity->getSystemPath(); - $uri['options'] = $entity->urlInfo()->getOptions(); + $url = $entity->urlInfo(); } } elseif ($image_link_setting == 'file') { @@ -206,10 +205,7 @@ public function viewElements(FieldItemListInterface $items) { if ($item->entity) { if (isset($link_file)) { $image_uri = $item->entity->getFileUri(); - $uri = array( - 'path' => file_create_url($image_uri), - 'options' => array(), - ); + $url = Url::fromUri(file_create_url($image_uri)); } // Extract field item attributes for the theme function, and unset them @@ -222,7 +218,7 @@ public function viewElements(FieldItemListInterface $items) { '#item' => $item, '#item_attributes' => $item_attributes, '#image_style' => $image_style_setting, - '#path' => isset($uri) ? $uri : '', + '#url' => $url, '#cache' => array( 'tags' => $cache_tags, ), diff --git a/core/modules/image/src/Tests/ImageThemeFunctionTest.php b/core/modules/image/src/Tests/ImageThemeFunctionTest.php index 06e9710..d1c371a 100644 --- a/core/modules/image/src/Tests/ImageThemeFunctionTest.php +++ b/core/modules/image/src/Tests/ImageThemeFunctionTest.php @@ -8,6 +8,7 @@ namespace Drupal\image\Tests; use Drupal\Core\Field\FieldStorageDefinitionInterface; +use Drupal\Core\Url; use Drupal\simpletest\WebTestBase; /** @@ -86,9 +87,7 @@ function testImageFormatterTheme() { '#theme' => 'image_formatter', '#image_style' => 'test', '#item' => $entity->image_test, - '#path' => array( - 'path' => $path, - ), + '#url' => Url::fromUri('base://' . $path), ); // Test using theme_image_formatter() with a NULL value for the alt option. @@ -104,18 +103,6 @@ function testImageFormatterTheme() { $this->drupalSetContent(drupal_render($element)); $elements = $this->xpath('//a[@href=:path]/img[@class="image-style-test" and @src=:url and @width=:width and @height=:height and @alt=""]', array(':path' => base_path() . $path, ':url' => $url, ':width' => $image->getWidth(), ':height' => $image->getHeight())); $this->assertEqual(count($elements), 1, 'theme_image_formatter() correctly renders without title, alt, or path options.'); - - // Link the image to a fragment on the page, and not a full URL. - $fragment = $this->randomMachineName(); - $element = $base_element; - $element['#path']['path'] = ''; - $element['#path']['options'] = array( - 'external' => TRUE, - 'fragment' => $fragment, - ); - $this->drupalSetContent(drupal_render($element)); - $elements = $this->xpath('//a[@href=:fragment]/img[@class="image-style-test" and @src=:url and @width=:width and @height=:height and @alt=""]', array(':fragment' => '#' . $fragment, ':url' => $url, ':width' => $image->getWidth(), ':height' => $image->getHeight())); - $this->assertEqual(count($elements), 1, 'theme_image_formatter() correctly renders a link fragment.'); } /** diff --git a/core/modules/node/src/Tests/NodeTranslationUITest.php b/core/modules/node/src/Tests/NodeTranslationUITest.php index 153e87c..01bd5e9 100644 --- a/core/modules/node/src/Tests/NodeTranslationUITest.php +++ b/core/modules/node/src/Tests/NodeTranslationUITest.php @@ -92,7 +92,6 @@ protected function getFormSubmitAction(EntityInterface $entity, $langcode) { */ protected function doTestPublishedStatus() { $entity = entity_load($this->entityTypeId, $this->entityId, TRUE); - $path = $entity->getSystemPath('edit-form'); $languages = $this->container->get('language_manager')->getLanguages(); $actions = array( @@ -104,7 +103,9 @@ protected function doTestPublishedStatus() { // (Un)publish the node translations and check that the translation // statuses are (un)published accordingly. foreach ($this->langcodes as $langcode) { - $this->drupalPostForm($path, array(), $action . $this->getFormSubmitSuffix($entity, $langcode), array('language' => $languages[$langcode])); + $options = array('language' => $languages[$langcode]); + $path = $entity->url('edit-form', $options); + $this->drupalPostForm($path, array(), $action . $this->getFormSubmitSuffix($entity, $langcode), $options); } $entity = entity_load($this->entityTypeId, $this->entityId, TRUE); foreach ($this->langcodes as $langcode) { @@ -123,7 +124,6 @@ protected function doTestPublishedStatus() { */ protected function doTestAuthoringInfo() { $entity = entity_load($this->entityTypeId, $this->entityId, TRUE); - $path = $entity->getSystemPath('edit-form'); $languages = $this->container->get('language_manager')->getLanguages(); $values = array(); @@ -143,7 +143,9 @@ protected function doTestAuthoringInfo() { 'sticky[value]' => $values[$langcode]['sticky'], 'promote[value]' => $values[$langcode]['promote'], ); - $this->drupalPostForm($path, $edit, $this->getFormSubmitAction($entity, $langcode), array('language' => $languages[$langcode])); + $options = array('language' => $languages[$langcode]); + $path = $entity->url('edit-form', $options); + $this->drupalPostForm($path, $edit, $this->getFormSubmitAction($entity, $langcode), $options); } $entity = entity_load($this->entityTypeId, $this->entityId, TRUE); diff --git a/core/modules/node/src/Tests/NodeViewLanguageTest.php b/core/modules/node/src/Tests/NodeViewLanguageTest.php index 733b10d..2f5e37d 100644 --- a/core/modules/node/src/Tests/NodeViewLanguageTest.php +++ b/core/modules/node/src/Tests/NodeViewLanguageTest.php @@ -38,7 +38,7 @@ public function testViewLanguage() { // Create a node in Spanish. $node = $this->drupalCreateNode(array('langcode' => 'es')); - $this->drupalGet($node->getSystemPath()); + $this->drupalGet($node->url()); $this->assertText('Spanish','The language field is displayed properly.'); } diff --git a/core/modules/node/src/Tests/NodeViewTest.php b/core/modules/node/src/Tests/NodeViewTest.php index 426fec1..2d0c5ac 100644 --- a/core/modules/node/src/Tests/NodeViewTest.php +++ b/core/modules/node/src/Tests/NodeViewTest.php @@ -21,16 +21,16 @@ class NodeViewTest extends NodeTestBase { public function testHtmlHeadLinks() { $node = $this->drupalCreateNode(); - $this->drupalGet($node->getSystemPath()); + $this->drupalGet($node->url()); $result = $this->xpath('//link[@rel = "version-history"]'); - $this->assertEqual($result[0]['href'], _url("node/{$node->id()}/revisions")); + $this->assertEqual($result[0]['href'], $node->url('version-history')); $result = $this->xpath('//link[@rel = "edit-form"]'); - $this->assertEqual($result[0]['href'], _url("node/{$node->id()}/edit")); + $this->assertEqual($result[0]['href'], $node->url('edit-form')); $result = $this->xpath('//link[@rel = "canonical"]'); - $this->assertEqual($result[0]['href'], _url("node/{$node->id()}")); + $this->assertEqual($result[0]['href'], $node->url()); } } diff --git a/core/modules/rdf/src/Tests/StandardProfileTest.php b/core/modules/rdf/src/Tests/StandardProfileTest.php index 092cd5d..9d0738b 100644 --- a/core/modules/rdf/src/Tests/StandardProfileTest.php +++ b/core/modules/rdf/src/Tests/StandardProfileTest.php @@ -240,7 +240,7 @@ protected function doFrontPageRdfaTests() { */ protected function doArticleRdfaTests() { // Feed the HTML into the parser. - $graph = $this->getRdfGraph($this->article->getSystemPath()); + $graph = $this->getRdfGraph($this->article->url()); // Type. $this->assertEqual($graph->type($this->articleUri), 'schema:Article', 'Article type was found (schema:Article).'); @@ -277,7 +277,7 @@ protected function doPageRdfaTests() { $node_type->save(); // Feed the HTML into the parser. - $graph = $this->getRdfGraph($this->page->getSystemPath()); + $graph = $this->getRdfGraph($this->page->url()); // Type. $this->assertEqual($graph->type($this->pageUri), 'schema:WebPage', 'Page type was found (schema:WebPage).'); @@ -293,7 +293,7 @@ protected function doUserRdfaTests() { $this->drupalLogin($this->root_user); // Feed the HTML into the parser. - $graph = $this->getRdfGraph($this->adminUser->getSystemPath()); + $graph = $this->getRdfGraph($this->adminUser->url()); // User type. $this->assertEqual($graph->type($this->authorUri), 'schema:Person', "User type was found (schema:Person) on user page."); @@ -313,7 +313,7 @@ protected function doUserRdfaTests() { */ protected function doTermRdfaTests() { // Feed the HTML into the parser. - $graph = $this->getRdfGraph($this->term->getSystemPath()); + $graph = $this->getRdfGraph($this->term->url()); // Term type. $this->assertEqual($graph->type($this->termUri), 'schema:Thing', "Term type was found (schema:Thing) on term page."); diff --git a/core/modules/responsive_image/responsive_image.module b/core/modules/responsive_image/responsive_image.module index 600ce73..b735f03 100644 --- a/core/modules/responsive_image/responsive_image.module +++ b/core/modules/responsive_image/responsive_image.module @@ -88,7 +88,7 @@ function responsive_image_theme() { 'responsive_image_formatter' => array( 'variables' => array( 'item' => NULL, - 'path' => NULL, + 'url' => NULL, 'image_style' => NULL, 'mapping_id' => array(), ), @@ -125,7 +125,7 @@ function theme_responsive_image_formatter($variables) { '#theme' => 'image_formatter', '#item' => $item, '#image_style' => $variables['image_style'], - '#path' => $variables['path'], + '#url' => $variables['url'], ); return drupal_render($image_formatter); } diff --git a/core/modules/responsive_image/src/Plugin/Field/FieldFormatter/ResponsiveImageFormatter.php b/core/modules/responsive_image/src/Plugin/Field/FieldFormatter/ResponsiveImageFormatter.php index a1308e9..ed6bcf0 100644 --- a/core/modules/responsive_image/src/Plugin/Field/FieldFormatter/ResponsiveImageFormatter.php +++ b/core/modules/responsive_image/src/Plugin/Field/FieldFormatter/ResponsiveImageFormatter.php @@ -13,6 +13,7 @@ use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; +use Drupal\Core\Url; use Drupal\image\Plugin\Field\FieldFormatter\ImageFormatterBase; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -173,11 +174,10 @@ public function settingsSummary() { */ public function viewElements(FieldItemListInterface $items) { $elements = array(); + $url = NULL; // Check if the formatter involves a link. if ($this->getSetting('image_link') == 'content') { - $uri = $items->getEntity()->urlInfo(); - // @todo Remove when theme_responsive_image_formatter() has support for route name. - $uri['path'] = $items->getEntity()->getSystemPath(); + $url = $items->getEntity()->urlInfo(); } elseif ($this->getSetting('image_link') == 'file') { $link_file = TRUE; @@ -214,10 +214,7 @@ public function viewElements(FieldItemListInterface $items) { foreach ($items as $delta => $item) { if (isset($link_file)) { - $uri = array( - 'path' => file_create_url($item->entity->getFileUri()), - 'options' => array(), - ); + $url = Url::fromUri(file_create_url($item->entity->getFileUri())); } $elements[$delta] = array( '#theme' => 'responsive_image_formatter', @@ -229,7 +226,7 @@ public function viewElements(FieldItemListInterface $items) { '#item' => $item, '#image_style' => $fallback_image_style, '#mapping_id' => $responsive_image_mapping ? $responsive_image_mapping->id() : '', - '#path' => isset($uri) ? $uri : '', + '#url' => $url, '#cache' => array( 'tags' => $cache_tags, ) diff --git a/core/modules/rest/src/Tests/AuthTest.php b/core/modules/rest/src/Tests/AuthTest.php index bf51c00..c8a8e3b 100644 --- a/core/modules/rest/src/Tests/AuthTest.php +++ b/core/modules/rest/src/Tests/AuthTest.php @@ -7,6 +7,7 @@ namespace Drupal\rest\Tests; +use Drupal\Core\Url; use Drupal\rest\Tests\RESTTestBase; /** @@ -37,7 +38,7 @@ public function testRead() { $entity->save(); // Try to read the resource as an anonymous user, which should not work. - $this->httpRequest($entity->getSystemPath(), 'GET', NULL, $this->defaultMimeType); + $this->httpRequest($entity->urlInfo(), 'GET', NULL, $this->defaultMimeType); $this->assertResponse('401', 'HTTP response code is 401 when the request is not authenticated and the user is anonymous.'); $this->assertRaw(json_encode(['error' => 'A fatal error occurred: No authentication credentials provided.'])); @@ -54,7 +55,7 @@ public function testRead() { // Try to read the resource with session cookie authentication, which is // not enabled and should not work. - $this->httpRequest($entity->getSystemPath(), 'GET', NULL, $this->defaultMimeType); + $this->httpRequest($entity->urlInfo(), 'GET', NULL, $this->defaultMimeType); $this->assertResponse('401', 'HTTP response code is 401 when the request is authenticated but not authorized.'); // Ensure that cURL settings/headers aren't carried over to next request. @@ -62,7 +63,7 @@ public function testRead() { // Now read it with the Basic authentication which is enabled and should // work. - $this->basicAuthGet($entity->getSystemPath(), $account->getUsername(), $account->pass_raw); + $this->basicAuthGet($entity->urlInfo(), $account->getUsername(), $account->pass_raw); $this->assertResponse('200', 'HTTP response code is 200 for successfully authorized requests.'); $this->curlClose(); } @@ -73,8 +74,8 @@ public function testRead() { * We do not use \Drupal\simpletest\WebTestBase::drupalGet because we need to * set curl settings for basic authentication. * - * @param string $path - * The request path. + * @param \Drupal\Core\Url $url + * An Url object. * @param string $username * The user name to authenticate with. * @param string $password @@ -83,18 +84,18 @@ public function testRead() { * @return string * Curl output. */ - protected function basicAuthGet($path, $username, $password) { + protected function basicAuthGet(Url $url, $username, $password) { $out = $this->curlExec( array( CURLOPT_HTTPGET => TRUE, - CURLOPT_URL => _url($path, array('absolute' => TRUE)), + CURLOPT_URL => $url->setAbsolute()->toString(), CURLOPT_NOBODY => FALSE, CURLOPT_HTTPAUTH => CURLAUTH_BASIC, CURLOPT_USERPWD => $username . ':' . $password, ) ); - $this->verbose('GET request to: ' . $path . + $this->verbose('GET request to: ' . $url->toString() . '