diff --git a/core/includes/batch.inc b/core/includes/batch.inc index 362854d4f16..7d905cdade5 100644 --- a/core/includes/batch.inc +++ b/core/includes/batch.inc @@ -153,10 +153,12 @@ function _batch_progress_page() { // Merge required query parameters for batch processing into those provided by // batch_set() or hook_batch_alter(). - $batch['url_options']['query']['id'] = $batch['id']; - $batch['url_options']['query']['op'] = $new_op; + $query_options = $batch['url']->getOption('query'); + $query_options['id'] = $batch['id']; + $query_options['op'] = $new_op; + $batch['url']->setOption('query', $query_options); - $url = _url($batch['url'], $batch['url_options']); + $url = $batch['url']->toString(); $build = array( '#theme' => 'progress_bar', diff --git a/core/includes/form.inc b/core/includes/form.inc index 659ef5f860a..694fb41610b 100644 --- a/core/includes/form.inc +++ b/core/includes/form.inc @@ -745,9 +745,10 @@ function batch_set($batch_definition) { * This function is generally not needed in form submit handlers; * Form API takes care of batches that were set during form submission. * - * @param $redirect - * (optional) Path to redirect to when the batch has finished processing. - * @param $url + * @param \Drupal\Core\Url|string $redirect + * (optional) Either path or Url object to redirect to when the batch has + * finished processing. + * @param \Drupal\Core\Url $url * (optional - should only be used for separate scripts like update.php) * URL of the batch processing page. * @param $redirect_callback @@ -757,7 +758,7 @@ function batch_set($batch_definition) { * @return \Symfony\Component\HttpFoundation\RedirectResponse|null * A redirect response if the batch is progressive. No return value otherwise. */ -function batch_process($redirect = NULL, $url = 'batch', $redirect_callback = NULL) { +function batch_process($redirect = NULL, Url $url = NULL, $redirect_callback = NULL) { $batch =& batch_get(); if (isset($batch)) { @@ -765,8 +766,7 @@ function batch_process($redirect = NULL, $url = 'batch', $redirect_callback = NU $process_info = array( 'current_set' => 0, 'progressive' => TRUE, - 'url' => $url, - 'url_options' => array(), + 'url' => isset($url) ? $url : Url::fromRoute('system.batch_page.html'), 'source_url' => Url::fromRouteMatch(\Drupal::routeMatch()), 'batch_redirect' => $redirect, 'theme' => \Drupal::theme()->getActiveTheme()->getName(), @@ -793,7 +793,16 @@ function batch_process($redirect = NULL, $url = 'batch', $redirect_callback = NU if ($batch['progressive']) { // Now that we have a batch id, we can generate the redirection link in // the generic error message. - $batch['error_message'] = t('Please continue to the error page', array('@error_url' => _url($url, array('query' => array('id' => $batch['id'], 'op' => 'finished'))))); + /** @var \Drupal\Core\Url $batch_url */ + $batch_url = $batch['url']; + /** @var \Drupal\Core\Url $error_url */ + $error_url = clone $batch_url; + $query_options = $error_url->getOption('query'); + $query_options['id'] = $batch['id']; + $query_options['op'] = 'finished'; + $error_url->setOption('query', $query_options); + + $batch['error_message'] = t('Please continue to the error page', array('@error_url' => $error_url->toString())); // Clear the way for the redirection to the batch processing page, by // saving and unsetting the 'destination', if there is any. @@ -815,13 +824,15 @@ function batch_process($redirect = NULL, $url = 'batch', $redirect_callback = NU $_SESSION['batches'][$batch['id']] = TRUE; // Redirect for processing. - $options = array('query' => array('op' => 'start', 'id' => $batch['id'])); + $query_options = $error_url->getOption('query'); + $query_options['op'] = 'start'; + $query_options['id'] = $batch['id']; + $batch_url->setOption('query', $query_options); if (($function = $batch['redirect_callback']) && function_exists($function)) { - $function($batch['url'], $options); + $function($batch_url->toString(), ['query' => $query_options]); } else { - $options['absolute'] = TRUE; - return new RedirectResponse(_url($batch['url'], $options)); + return new RedirectResponse($batch_url->setAbsolute()->toString()); } } else { diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index d3d7a04cf4d..06b62c5ef38 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -18,6 +18,7 @@ use Drupal\Core\Site\Settings; use Drupal\Core\StringTranslation\Translator\FileTranslation; use Drupal\Core\Extension\ExtensionDiscovery; use Drupal\Core\DependencyInjection\ContainerBuilder; +use Drupal\Core\Url; use Drupal\language\Entity\ConfigurableLanguage; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpFoundation\Request; @@ -581,10 +582,10 @@ function install_run_task($task, &$install_state) { } // Process the batch. For progressive batches, this will redirect. // Otherwise, the batch will complete. - // install_redirect_url() returns core/install.php, so let's ensure to - // drop it from it and use base:// as batch_process() is using the - // unrouted URL assembler, which requires base://. - $response = batch_process(preg_replace('@^core/@', 'base://', install_redirect_url($install_state)), install_full_redirect_url($install_state)); + // Disable the default script for the URL and clone the object, as + // batch_process() will add additional options to the batch URL. + $url = Url::fromUri('base://install.php', ['query' => $install_state['parameters'], 'script' => '']); + $response = batch_process($url, clone $url); if ($response instanceof Response) { // Save $_SESSION data from batch. \Drupal::service('session_manager')->save(); diff --git a/core/lib/Drupal/Component/Utility/UrlHelper.php b/core/lib/Drupal/Component/Utility/UrlHelper.php index 691413e80e6..f1bd611127d 100644 --- a/core/lib/Drupal/Component/Utility/UrlHelper.php +++ b/core/lib/Drupal/Component/Utility/UrlHelper.php @@ -134,7 +134,6 @@ class UrlHelper { * - fragment: The fragment component from $url, if it exists. * * @see \Drupal\Core\Utility\LinkGenerator - * @see _url() * @see http://tools.ietf.org/html/rfc3986 * * @ingroup php_wrappers diff --git a/core/lib/Drupal/Core/Ajax/RedirectCommand.php b/core/lib/Drupal/Core/Ajax/RedirectCommand.php index 4b31e52452a..f7d05e140f8 100644 --- a/core/lib/Drupal/Core/Ajax/RedirectCommand.php +++ b/core/lib/Drupal/Core/Ajax/RedirectCommand.php @@ -28,7 +28,7 @@ class RedirectCommand implements CommandInterface { * * @param string $url * The URL that will be loaded into window.location. This should be a full - * URL, one that has already been run through the _url() function. + * URL. */ public function __construct($url) { $this->url = $url; diff --git a/core/lib/Drupal/Core/Asset/CssOptimizer.php b/core/lib/Drupal/Core/Asset/CssOptimizer.php index baa2de4c370..1090d5aefdd 100644 --- a/core/lib/Drupal/Core/Asset/CssOptimizer.php +++ b/core/lib/Drupal/Core/Asset/CssOptimizer.php @@ -119,7 +119,7 @@ class CssOptimizer implements AssetOptimizerInterface { * Loads stylesheets recursively and returns contents with corrected paths. * * This function is used for recursive loading of stylesheets and - * returns the stylesheet content with all _url() paths corrected. + * returns the stylesheet content with all url() paths corrected. * * @param array $matches * An array of matches by a preg_replace_callback() call that scans for @@ -138,10 +138,10 @@ class CssOptimizer implements AssetOptimizerInterface { // Determine the file's directory. $directory = dirname($filename); // If the file is in the current directory, make sure '.' doesn't appear in - // the _url() path. + // the url() path. $directory = $directory == '.' ? '' : $directory .'/'; - // Alter all internal _url() paths. Leave external paths alone. We don't need + // Alter all internal url() paths. Leave external paths alone. We don't need // to normalize absolute paths here (i.e. remove folder/... segments) // because that will be done later. return preg_replace('/url\(\s*([\'"]?)(?![a-z]+:|\/+)([^\'")]+)([\'"]?)\s*\)/i', 'url(\1' . $directory . '\2\3)', $file); @@ -215,7 +215,7 @@ class CssOptimizer implements AssetOptimizerInterface { * * @param array $matches * An array of matches by a preg_replace_callback() call that scans for - * _url() references in CSS files, except for external or absolute ones. + * url() references in CSS files, except for external or absolute ones. * * Note: the only reason this method is public is so color.module can call it; * it is not on the AssetOptimizerInterface, so future refactorings can make diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php index afdfcb04f1f..5f8483ddda3 100644 --- a/core/lib/Drupal/Core/Entity/Entity.php +++ b/core/lib/Drupal/Core/Entity/Entity.php @@ -193,8 +193,8 @@ abstract class Entity implements EntityInterface { } } - // Pass the entity data to _url() so that alter functions do not need to - // look up this entity again. + // Pass the entity data through as options, so that alter functions do not + // need to look up this entity again. $uri ->setOption('entity_type', $this->getEntityTypeId()) ->setOption('entity', $this); diff --git a/core/lib/Drupal/Core/Menu/MenuTreeStorage.php b/core/lib/Drupal/Core/Menu/MenuTreeStorage.php index 4afd4fddbdb..5d1edb98d35 100644 --- a/core/lib/Drupal/Core/Menu/MenuTreeStorage.php +++ b/core/lib/Drupal/Core/Menu/MenuTreeStorage.php @@ -1273,7 +1273,7 @@ class MenuTreeStorage implements MenuTreeStorageInterface { 'not null' => FALSE, ), 'options' => array( - 'description' => 'A serialized array of options to be passed to the _url() or _l() function, such as a query string or HTML attributes.', + 'description' => 'A serialized array of URL options, such as a query string or HTML attributes.', 'type' => 'blob', 'size' => 'big', 'not null' => FALSE, diff --git a/core/lib/Drupal/Core/Path/AliasWhitelist.php b/core/lib/Drupal/Core/Path/AliasWhitelist.php index 11c68f75f2a..38ace76389a 100644 --- a/core/lib/Drupal/Core/Path/AliasWhitelist.php +++ b/core/lib/Drupal/Core/Path/AliasWhitelist.php @@ -88,7 +88,7 @@ class AliasWhitelist extends CacheCollector implements AliasWhitelistInterface { */ public function get($offset) { $this->lazyLoadCache(); - // _url() may be called with paths that are not represented by menu router + // this may be called with paths that are not represented by menu router // items such as paths that will be rewritten by hook_url_outbound_alter(). // Therefore internally TRUE is used to indicate whitelisted paths. FALSE is // used to indicate paths that have already been checked but are not diff --git a/core/lib/Drupal/Core/Render/Element/RenderElement.php b/core/lib/Drupal/Core/Render/Element/RenderElement.php index c0c982a79f6..0283333b1cd 100644 --- a/core/lib/Drupal/Core/Render/Element/RenderElement.php +++ b/core/lib/Drupal/Core/Render/Element/RenderElement.php @@ -291,9 +291,8 @@ abstract class RenderElement extends PluginBase implements ElementInterface { $settings['progress'] = array('type' => $settings['progress']); } // Change progress path to a full URL. - if (isset($settings['progress']['path'])) { - $settings['progress']['url'] = _url($settings['progress']['path']); - unset($settings['progress']['path']); + if (isset($settings['progress']['url']) && $settings['progress']['url'] instanceof Url) { + $settings['progress']['url'] = $settings['progress']['url']->toString(); } $element['#attached']['drupalSettings']['ajax'][$element['#id']] = $settings; diff --git a/core/lib/Drupal/Core/Routing/UrlGenerator.php b/core/lib/Drupal/Core/Routing/UrlGenerator.php index b964e6d3743..1926d44a5fd 100644 --- a/core/lib/Drupal/Core/Routing/UrlGenerator.php +++ b/core/lib/Drupal/Core/Routing/UrlGenerator.php @@ -251,8 +251,7 @@ class UrlGenerator extends ProviderBasedGenerator implements UrlGeneratorInterfa // \Drupal\Component\Utility\UrlHelper::stripDangerousProtocols() if $path // contains a ':' before any / ? or #. Note: we could use // \Drupal\Component\Utility\UrlHelper::isExternal($path) here, but that - // would require another function call, and performance inside _url() is - // critical. + // would require another function call, and performance here is critical. $colonpos = strpos($path, ':'); $options['external'] = ($colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && UrlHelper::stripDangerousProtocols($path) == $path); } diff --git a/core/lib/Drupal/Core/Utility/UnroutedUrlAssembler.php b/core/lib/Drupal/Core/Utility/UnroutedUrlAssembler.php index c0ce73b0836..612ac8754a1 100644 --- a/core/lib/Drupal/Core/Utility/UnroutedUrlAssembler.php +++ b/core/lib/Drupal/Core/Utility/UnroutedUrlAssembler.php @@ -155,13 +155,29 @@ class UnroutedUrlAssembler implements UnroutedUrlAssemblerInterface { * The options to merge in the defaults. */ protected function addOptionDefaults(array &$options) { + $request = $this->requestStack->getCurrentRequest(); + $current_base_path = $request->getBasePath() . '/'; + $current_script_path = ''; + $base_path_with_script = $request->getBaseUrl(); + + // If the current request was made with the script name (eg, index.php) in + // it, then extract it, making sure the leading / is gone, and a trailing / + // is added, to allow simple string concatenation with other parts. This + // mirrors code from UrlGenerator::generateFromPath(). + if (!empty($base_path_with_script)) { + $script_name = $request->getScriptName(); + if (strpos($base_path_with_script, $script_name) !== FALSE) { + $current_script_path = ltrim(substr($script_name, strlen($current_base_path)), '/') . '/'; + } + } + // Merge in defaults. $options += [ 'fragment' => '', 'query' => [], 'absolute' => FALSE, 'prefix' => '', - 'script' => '', + 'script' => $current_script_path, ]; if (isset($options['fragment']) && $options['fragment'] !== '') { diff --git a/core/modules/aggregator/src/Tests/FeedParserTest.php b/core/modules/aggregator/src/Tests/FeedParserTest.php index ab6aaafde6a..7e45f189594 100644 --- a/core/modules/aggregator/src/Tests/FeedParserTest.php +++ b/core/modules/aggregator/src/Tests/FeedParserTest.php @@ -7,6 +7,7 @@ namespace Drupal\aggregator\Tests; +use Drupal\Core\Url; use Zend\Feed\Reader\Reader; /** @@ -76,12 +77,11 @@ class FeedParserTest extends AggregatorTestBase { } /** - * Tests error handling when an invalid feed is added. + * Tests that a redirected feed is tracked to its target. */ function testRedirectFeed() { - // Simulate a typo in the URL to force a curl exception. - $invalid_url = _url('aggregator/redirect', array('absolute' => TRUE)); - $feed = entity_create('aggregator_feed', array('url' => $invalid_url, 'title' => $this->randomMachineName())); + $redirect_url = Url::fromRoute('aggregator_test.redirect')->setAbsolute()->toString(); + $feed = entity_create('aggregator_feed', array('url' => $redirect_url, 'title' => $this->randomMachineName())); $feed->save(); $feed->refreshItems(); diff --git a/core/modules/basic_auth/src/Tests/Authentication/BasicAuthTest.php b/core/modules/basic_auth/src/Tests/Authentication/BasicAuthTest.php index 9c5375a4aed..227f11a4c03 100644 --- a/core/modules/basic_auth/src/Tests/Authentication/BasicAuthTest.php +++ b/core/modules/basic_auth/src/Tests/Authentication/BasicAuthTest.php @@ -7,6 +7,7 @@ namespace Drupal\basic_auth\Tests\Authentication; +use Drupal\Core\Url; use Drupal\language\Entity\ConfigurableLanguage; use Drupal\simpletest\WebTestBase; @@ -29,18 +30,21 @@ class BasicAuthTest extends WebTestBase { */ public function testBasicAuth() { $account = $this->drupalCreateUser(); + $url = Url::fromRoute('router_test.11'); - $this->basicAuthGet('router_test/test11', $account->getUsername(), $account->pass_raw); + $this->basicAuthGet($url, $account->getUsername(), $account->pass_raw); $this->assertText($account->getUsername(), 'Account name is displayed.'); $this->assertResponse('200', 'HTTP response is OK'); $this->curlClose(); - $this->basicAuthGet('router_test/test11', $account->getUsername(), $this->randomMachineName()); + $this->basicAuthGet($url, $account->getUsername(), $this->randomMachineName()); $this->assertNoText($account->getUsername(), 'Bad basic auth credentials do not authenticate the user.'); $this->assertResponse('403', 'Access is not granted.'); $this->curlClose(); - $this->drupalGet('router_test/test11'); + // @todo Change ->drupalGet() calls to just pass $url when + // https://www.drupal.org/node/2350837 gets committed + $this->drupalGet($url->setAbsolute()->toString()); $this->assertResponse('401', 'Not authenticated on the route that allows only basic_auth. Prompt to authenticate received.'); $this->drupalGet('admin'); @@ -48,7 +52,7 @@ class BasicAuthTest extends WebTestBase { $account = $this->drupalCreateUser(array('access administration pages')); - $this->basicAuthGet('admin', $account->getUsername(), $account->pass_raw); + $this->basicAuthGet(Url::fromRoute('system.admin'), $account->getUsername(), $account->pass_raw); $this->assertNoLink('Log out', 0, 'User is not logged in'); $this->assertResponse('403', 'No basic authentication for routes not explicitly defining authentication providers.'); $this->curlClose(); @@ -67,14 +71,15 @@ class BasicAuthTest extends WebTestBase { $user = $this->drupalCreateUser(array()); $incorrect_user = clone $user; $incorrect_user->pass_raw .= 'incorrect'; + $url = Url::fromRoute('router_test.11'); // Try 2 failed logins. for ($i = 0; $i < 2; $i++) { - $this->basicAuthGet('router_test/test11', $incorrect_user->getUsername(), $incorrect_user->pass_raw); + $this->basicAuthGet($url, $incorrect_user->getUsername(), $incorrect_user->pass_raw); } // IP limit has reached to its limit. Even valid user credentials will fail. - $this->basicAuthGet('router_test/test11', $user->getUsername(), $user->pass_raw); + $this->basicAuthGet($url, $user->getUsername(), $user->pass_raw); $this->assertResponse('403', 'Access is blocked because of IP based flood prevention.'); } @@ -92,26 +97,27 @@ class BasicAuthTest extends WebTestBase { $incorrect_user = clone $user; $incorrect_user->pass_raw .= 'incorrect'; $user2 = $this->drupalCreateUser(array()); + $url = Url::fromRoute('router_test.11'); // Try a failed login. - $this->basicAuthGet('router_test/test11', $incorrect_user->getUsername(), $incorrect_user->pass_raw); + $this->basicAuthGet($url, $incorrect_user->getUsername(), $incorrect_user->pass_raw); // A successful login will reset the per-user flood control count. - $this->basicAuthGet('router_test/test11', $user->getUsername(), $user->pass_raw); + $this->basicAuthGet($url, $user->getUsername(), $user->pass_raw); $this->assertResponse('200', 'Per user flood prevention gets reset on a successful login.'); // Try 2 failed logins for a user. They will trigger flood control. for ($i = 0; $i < 2; $i++) { - $this->basicAuthGet('router_test/test11', $incorrect_user->getUsername(), $incorrect_user->pass_raw); + $this->basicAuthGet($url, $incorrect_user->getUsername(), $incorrect_user->pass_raw); } // Now the user account is blocked. - $this->basicAuthGet('router_test/test11', $user->getUsername(), $user->pass_raw); + $this->basicAuthGet($url, $user->getUsername(), $user->pass_raw); $this->assertResponse('403', 'The user account is blocked due to per user flood prevention.'); // Try one successful attempt for a different user, it should not trigger // any flood control. - $this->basicAuthGet('router_test/test11', $user2->getUsername(), $user2->pass_raw); + $this->basicAuthGet($url, $user2->getUsername(), $user2->pass_raw); $this->assertResponse('200', 'Per user flood prevention does not block access for other users.'); } @@ -123,8 +129,9 @@ class BasicAuthTest extends WebTestBase { $this->config('system.site')->set('langcode', 'de')->save(); $account = $this->drupalCreateUser(); + $url = Url::fromRoute('router_test.11'); - $this->basicAuthGet('router_test/test11', $account->getUsername(), $account->pass_raw); + $this->basicAuthGet($url, $account->getUsername(), $account->pass_raw); $this->assertText($account->getUsername(), 'Account name is displayed.'); $this->assertResponse('200', 'HTTP response is OK'); $this->curlClose(); @@ -136,8 +143,8 @@ class BasicAuthTest extends WebTestBase { * 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|string $path + * Drupal path or URL to load into internal browser * @param string $username * The user name to authenticate with. * @param string $password @@ -147,10 +154,14 @@ class BasicAuthTest extends WebTestBase { * Curl output. */ protected function basicAuthGet($path, $username, $password) { + if ($path instanceof Url) { + $path = $path->setAbsolute()->toString(); + } + $out = $this->curlExec( array( CURLOPT_HTTPGET => TRUE, - CURLOPT_URL => _url($path, array('absolute' => TRUE)), + CURLOPT_URL => $path, CURLOPT_NOBODY => FALSE, CURLOPT_HTTPAUTH => CURLAUTH_BASIC, CURLOPT_USERPWD => $username . ':' . $password, diff --git a/core/modules/file/src/Tests/DownloadTest.php b/core/modules/file/src/Tests/DownloadTest.php index 1aece59350a..9de1b3a9276 100644 --- a/core/modules/file/src/Tests/DownloadTest.php +++ b/core/modules/file/src/Tests/DownloadTest.php @@ -112,9 +112,9 @@ class DownloadTest extends FileManagedTestBase { '%C3%A9%C3%B8%C3%AF%D0%B2%CE%B2%E4%B8%AD%E5%9C%8B%E6%9B%B8%DB%9E'; // Public files should not be served by Drupal, so their URLs should not be - // generated by _url(), whereas private files should be served by Drupal, so - // their URLs should be generated by _url(). The difference is most apparent - // when $script_path is not empty (i.e., when not using clean URLs). + // routed through Drupal, whereas private files should be served by Drupal, + // so they need to be. The difference is most apparent when $script_path + // is not empty (i.e., when not using clean URLs). $clean_url_settings = array( 'clean' => '', 'unclean' => 'index.php/', diff --git a/core/modules/filter/src/Tests/FilterDefaultConfigTest.php b/core/modules/filter/src/Tests/FilterDefaultConfigTest.php index 8820c976742..2cd99d4dfba 100644 --- a/core/modules/filter/src/Tests/FilterDefaultConfigTest.php +++ b/core/modules/filter/src/Tests/FilterDefaultConfigTest.php @@ -21,7 +21,7 @@ class FilterDefaultConfigTest extends KernelTestBase { protected function setUp() { parent::setUp(); - // Drupal\filter\FilterPermissions::permissions() calls into _url() to output + // Drupal\filter\FilterPermissions::permissions() builds an URL to output // a link in the description. $this->installSchema('system', 'url_alias'); diff --git a/core/modules/hal/src/Tests/DenormalizeTest.php b/core/modules/hal/src/Tests/DenormalizeTest.php index 6931d1c563e..cbb593c24aa 100644 --- a/core/modules/hal/src/Tests/DenormalizeTest.php +++ b/core/modules/hal/src/Tests/DenormalizeTest.php @@ -7,6 +7,7 @@ namespace Drupal\hal\Tests; +use Drupal\Core\Url; use Symfony\Component\Serializer\Exception\UnexpectedValueException; /** @@ -24,7 +25,7 @@ class DenormalizeTest extends NormalizerTestBase { $data_with_valid_type = array( '_links' => array( 'type' => array( - 'href' => _url('rest/type/entity_test/entity_test', array('absolute' => TRUE)), + 'href' => Url::fromUri('base://rest/type/entity_test/entity_test', array('absolute' => TRUE))->toString(), ), ), ); @@ -36,10 +37,10 @@ class DenormalizeTest extends NormalizerTestBase { '_links' => array( 'type' => array( array( - 'href' => _url('rest/types/foo', array('absolute' => TRUE)), + 'href' => Url::fromUri('base://rest/types/foo', array('absolute' => TRUE))->toString(), ), array( - 'href' => _url('rest/type/entity_test/entity_test', array('absolute' => TRUE)), + 'href' => Url::fromUri('base://rest/type/entity_test/entity_test', array('absolute' => TRUE))->toString(), ), ), ), @@ -51,7 +52,7 @@ class DenormalizeTest extends NormalizerTestBase { $data_with_invalid_type = array( '_links' => array( 'type' => array( - 'href' => _url('rest/types/foo', array('absolute' => TRUE)), + 'href' => Url::fromUri('base://rest/types/foo', array('absolute' => TRUE))->toString(), ), ), ); @@ -84,7 +85,7 @@ class DenormalizeTest extends NormalizerTestBase { $no_field_data = array( '_links' => array( 'type' => array( - 'href' => _url('rest/type/entity_test/entity_test', array('absolute' => TRUE)), + 'href' => Url::fromUri('base://rest/type/entity_test/entity_test', array('absolute' => TRUE))->toString(), ), ), ); @@ -94,7 +95,7 @@ class DenormalizeTest extends NormalizerTestBase { $empty_field_data = array( '_links' => array( 'type' => array( - 'href' => _url('rest/type/entity_test/entity_test', array('absolute' => TRUE)), + 'href' => Url::fromUri('base://rest/type/entity_test/entity_test', array('absolute' => TRUE))->toString(), ), ), 'field_test_text' => array(), @@ -112,7 +113,7 @@ class DenormalizeTest extends NormalizerTestBase { $data = array( '_links' => array( 'type' => array( - 'href' => _url('rest/type/entity_test/entity_test', array('absolute' => TRUE)), + 'href' => Url::fromUri('base://rest/type/entity_test/entity_test', array('absolute' => TRUE))->toString(), ), ), 'uuid' => array( @@ -182,7 +183,7 @@ class DenormalizeTest extends NormalizerTestBase { $data = array( '_links' => array( 'type' => array( - 'href' => _url('rest/type/entity_test/entity_test', array('absolute' => TRUE)), + 'href' => Url::fromUri('base://rest/type/entity_test/entity_test', array('absolute' => TRUE))->toString(), ), ), 'field_test_text' => array( diff --git a/core/modules/hal/src/Tests/FileNormalizeTest.php b/core/modules/hal/src/Tests/FileNormalizeTest.php index d841ddfc02e..2b5038166d8 100644 --- a/core/modules/hal/src/Tests/FileNormalizeTest.php +++ b/core/modules/hal/src/Tests/FileNormalizeTest.php @@ -39,7 +39,8 @@ class FileNormalizeTest extends NormalizerTestBase { $this->installEntitySchema('file'); $entity_manager = \Drupal::entityManager(); - $link_manager = new LinkManager(new TypeLinkManager(new MemoryBackend('default')), new RelationLinkManager(new MemoryBackend('default'), $entity_manager)); + $url_assembler = \Drupal::service('unrouted_url_assembler'); + $link_manager = new LinkManager(new TypeLinkManager(new MemoryBackend('default'), $url_assembler), new RelationLinkManager(new MemoryBackend('default'), $entity_manager, $url_assembler)); // Set up the mock serializer. $normalizers = array( diff --git a/core/modules/hal/src/Tests/NormalizeTest.php b/core/modules/hal/src/Tests/NormalizeTest.php index ee40c25dabe..183430fcb46 100644 --- a/core/modules/hal/src/Tests/NormalizeTest.php +++ b/core/modules/hal/src/Tests/NormalizeTest.php @@ -7,6 +7,8 @@ namespace Drupal\hal\Tests; +use Drupal\Core\Url; + /** * Tests that entities can be normalized in HAL. * @@ -59,8 +61,8 @@ class NormalizeTest extends NormalizerTestBase { $entity->getTranslation('en')->set('field_test_entity_reference', array(0 => $translation_values['field_test_entity_reference'])); $entity->save(); - $type_uri = _url('rest/type/entity_test/entity_test', array('absolute' => TRUE)); - $relation_uri = _url('rest/relation/entity_test/entity_test/field_test_entity_reference', array('absolute' => TRUE)); + $type_uri = Url::fromUri('base://rest/type/entity_test/entity_test', array('absolute' => TRUE))->toString(); + $relation_uri = Url::fromUri('base://rest/relation/entity_test/entity_test/field_test_entity_reference', array('absolute' => TRUE))->toString(); $expected_array = array( '_links' => array( diff --git a/core/modules/hal/src/Tests/NormalizerTestBase.php b/core/modules/hal/src/Tests/NormalizerTestBase.php index 5e721826c63..43f10b1295e 100644 --- a/core/modules/hal/src/Tests/NormalizerTestBase.php +++ b/core/modules/hal/src/Tests/NormalizerTestBase.php @@ -134,7 +134,8 @@ abstract class NormalizerTestBase extends KernelTestBase { ))->save(); $entity_manager = \Drupal::entityManager(); - $link_manager = new LinkManager(new TypeLinkManager(new MemoryBackend('default')), new RelationLinkManager(new MemoryBackend('default'), $entity_manager)); + $url_assembler = \Drupal::service('unrouted_url_assembler'); + $link_manager = new LinkManager(new TypeLinkManager(new MemoryBackend('default'), $url_assembler), new RelationLinkManager(new MemoryBackend('default'), $entity_manager, $url_assembler)); $chain_resolver = new ChainEntityResolver(array(new UuidResolver($entity_manager), new TargetIdResolver())); diff --git a/core/modules/image/src/Entity/ImageStyle.php b/core/modules/image/src/Entity/ImageStyle.php index cf9c861a023..624eea03b04 100644 --- a/core/modules/image/src/Entity/ImageStyle.php +++ b/core/modules/image/src/Entity/ImageStyle.php @@ -14,6 +14,7 @@ use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\EntityWithPluginCollectionInterface; use Drupal\Core\Routing\RequestHelper; use Drupal\Core\Site\Settings; +use Drupal\Core\Url; use Drupal\image\ImageEffectPluginCollection; use Drupal\image\ImageEffectInterface; use Drupal\image\ImageStyleInterface; @@ -218,12 +219,13 @@ class ImageStyle extends ConfigEntityBase implements ImageStyleInterface, Entity } // If not using clean URLs, the image derivative callback is only available - // with the script path. If the file does not exist, use _url() to ensure - // that it is included. Once the file exists it's fine to fall back to the - // actual file path, this avoids bootstrapping PHP once the files are built. + // with the script path. If the file does not exist, use Url::fromUri() to + // ensure that it is included. Once the file exists it's fine to fall back + // to the actual file path, this avoids bootstrapping PHP once the files are + // built. if ($clean_urls === FALSE && file_uri_scheme($uri) == 'public' && !file_exists($uri)) { $directory_path = file_stream_wrapper_get_instance_by_uri($uri)->getDirectoryPath(); - return _url($directory_path . '/' . file_uri_target($uri), array('absolute' => TRUE, 'query' => $token_query)); + return Url::fromUri('base://' . $directory_path . '/' . file_uri_target($uri), array('absolute' => TRUE, 'query' => $token_query))->toString(); } $file_url = file_create_url($uri); diff --git a/core/modules/language/src/LanguageNegotiatorInterface.php b/core/modules/language/src/LanguageNegotiatorInterface.php index b17f3f48b28..9a1efbe8202 100644 --- a/core/modules/language/src/LanguageNegotiatorInterface.php +++ b/core/modules/language/src/LanguageNegotiatorInterface.php @@ -25,7 +25,7 @@ use Drupal\Core\Session\AccountInterface; * - Content language: The language used to present content that is available * in more than one language. * - URL language: The language associated with URLs. When generating a URL, - * this value will be used by _url() as a default if no explicit preference is + * this value will be used for URL's as a default if no explicit preference is * provided. * Modules can define additional language types through * hook_language_types_info(), and alter existing language type definitions diff --git a/core/modules/language/src/Tests/LanguageUILanguageNegotiationTest.php b/core/modules/language/src/Tests/LanguageUILanguageNegotiationTest.php index 37611cd9234..4d16686ed6b 100644 --- a/core/modules/language/src/Tests/LanguageUILanguageNegotiationTest.php +++ b/core/modules/language/src/Tests/LanguageUILanguageNegotiationTest.php @@ -7,6 +7,7 @@ namespace Drupal\language\Tests; +use Drupal\Core\Url; use Drupal\language\Entity\ConfigurableLanguage; use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationBrowser; use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationSelected; @@ -417,7 +418,7 @@ class LanguageUILanguageNegotiationTest extends WebTestBase { } /** - * Tests _url() when separate domains are used for multiple languages. + * Tests URL handling when separate domains are used for multiple languages. */ function testLanguageDomain() { global $base_url; @@ -462,23 +463,22 @@ class LanguageUILanguageNegotiationTest extends WebTestBase { // Test URL in another language: http://it.example.com/admin. // Base path gives problems on the testbot, so $correct_link is hard-coded. // @see UrlAlterFunctionalTest::assertUrlOutboundAlter (path.test). - $italian_url = _url('admin', array('language' => $languages['it'], 'script' => '')); + $italian_url = Url::fromRoute('system.admin', [], ['language' => $languages['it']])->toString(); $url_scheme = \Drupal::request()->isSecure() ? 'https://' : 'http://'; $correct_link = $url_scheme . $link; - $this->assertEqual($italian_url, $correct_link, format_string('The _url() function returns the right URL (@url) in accordance with the chosen language', array('@url' => $italian_url))); + $this->assertEqual($italian_url, $correct_link, format_string('The right URL (@url) in accordance with the chosen language', array('@url' => $italian_url))); // Test HTTPS via options. - $italian_url = _url('admin', array('https' => TRUE, 'language' => $languages['it'], 'script' => '')); + $italian_url = Url::fromRoute('system.admin', [], ['https' => TRUE, 'language' => $languages['it']])->toString(); $correct_link = 'https://' . $link; - $this->assertTrue($italian_url == $correct_link, format_string('The _url() function returns the right HTTPS URL (via options) (@url) in accordance with the chosen language', array('@url' => $italian_url))); + $this->assertTrue($italian_url == $correct_link, format_string('The right HTTPS URL (via options) (@url) in accordance with the chosen language', array('@url' => $italian_url))); // Test HTTPS via current URL scheme. $request = Request::create('', 'GET', array(), array(), array(), array('HTTPS' => 'on')); $this->container->get('request_stack')->push($request); - $generator = $this->container->get('url_generator'); - $italian_url = _url('admin', array('language' => $languages['it'], 'script' => '')); + $italian_url = Url::fromRoute('system.admin', [], ['language' => $languages['it']])->toString(); $correct_link = 'https://' . $link; - $this->assertTrue($italian_url == $correct_link, format_string('The _url() function returns the right URL (via current URL scheme) (@url) in accordance with the chosen language', array('@url' => $italian_url))); + $this->assertTrue($italian_url == $correct_link, format_string('The right URL (via current URL scheme) (@url) in accordance with the chosen language', array('@url' => $italian_url))); } /** diff --git a/core/modules/language/src/Tests/LanguageUrlRewritingTest.php b/core/modules/language/src/Tests/LanguageUrlRewritingTest.php index f9fee4f4cec..f5b838a150e 100644 --- a/core/modules/language/src/Tests/LanguageUrlRewritingTest.php +++ b/core/modules/language/src/Tests/LanguageUrlRewritingTest.php @@ -9,6 +9,7 @@ namespace Drupal\language\Tests; use Drupal\Core\Language\Language; use Drupal\Core\Language\LanguageInterface; +use Drupal\Core\Url; use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl; use Drupal\simpletest\WebTestBase; use Symfony\Component\HttpFoundation\Request; @@ -138,21 +139,21 @@ class LanguageUrlRewritingTest extends WebTestBase { // Create an absolute French link. $language = \Drupal::languageManager()->getLanguage('fr'); - $url = _url('', array( + $url = Url::fromRoute('', [], [ 'absolute' => TRUE, 'language' => $language, - )); + ])->toString(); $expected = ($index_php ? 'http://example.fr:88/index.php' : 'http://example.fr:88') . rtrim(base_path(), '/') . '/'; $this->assertEqual($url, $expected, 'The right port is used.'); - // If we set the port explicitly in _url(), it should not be overriden. - $url = _url('', array( + // If we set the port explicitly, it should not be overriden. + $url = Url::fromRoute('', [], [ 'absolute' => TRUE, 'language' => $language, 'base_url' => $request->getBaseUrl() . ':90', - )); + ])->toString(); $expected = $index_php ? 'http://example.fr:90/index.php' : 'http://example.fr:90' . rtrim(base_path(), '/') . '/'; diff --git a/core/modules/locale/src/Tests/LocaleUpdateBase.php b/core/modules/locale/src/Tests/LocaleUpdateBase.php index 7e17c892e15..83972214519 100644 --- a/core/modules/locale/src/Tests/LocaleUpdateBase.php +++ b/core/modules/locale/src/Tests/LocaleUpdateBase.php @@ -8,6 +8,7 @@ namespace Drupal\locale\Tests; use Drupal\Core\StreamWrapper\PublicStream; +use Drupal\Core\Url; use Drupal\simpletest\WebTestBase; use Drupal\Component\Utility\String; @@ -60,7 +61,7 @@ abstract class LocaleUpdateBase extends WebTestBase { // Update module should not go out to d.o to check for updates. We override // the url to the default update_test xml path. But without providing // a mock xml file, no update data will be found. - $this->config('update.settings')->set('fetch.url', _url('update-test', array('absolute' => TRUE)))->save(); + $this->config('update.settings')->set('fetch.url', Url::fromRoute('update_test.update_test', [], ['absolute' => TRUE])->toString())->save(); // Setup timestamps to identify old and new translation sources. $this->timestampOld = REQUEST_TIME - 300; diff --git a/core/modules/menu_link_content/src/Entity/MenuLinkContent.php b/core/modules/menu_link_content/src/Entity/MenuLinkContent.php index 152dc548aba..3bff7dc2090 100644 --- a/core/modules/menu_link_content/src/Entity/MenuLinkContent.php +++ b/core/modules/menu_link_content/src/Entity/MenuLinkContent.php @@ -342,7 +342,7 @@ class MenuLinkContent extends ContentEntityBase implements MenuLinkContentInterf $fields['options'] = BaseFieldDefinition::create('map') ->setLabel(t('Options')) - ->setDescription(t('A serialized array of options to be passed to the _url() or _l() function, such as a query string or HTML attributes.')) + ->setDescription(t('A serialized array of URL options, such as a query string or HTML attributes.')) ->setSetting('default_value', array()); $fields['external'] = BaseFieldDefinition::create('boolean') diff --git a/core/modules/path/src/Tests/PathLanguageTest.php b/core/modules/path/src/Tests/PathLanguageTest.php index 93cd776c003..f801134c2bf 100644 --- a/core/modules/path/src/Tests/PathLanguageTest.php +++ b/core/modules/path/src/Tests/PathLanguageTest.php @@ -119,11 +119,11 @@ class PathLanguageTest extends PathTestBase { $this->drupalGet('fr/' . $edit['path[0][alias]']); $this->assertText($french_node->body->value, 'Alias for French translation works.'); - // Confirm that the alias is returned by _url(). Languages are cached on + // Confirm that the alias is returned for the URL. Languages are cached on // many levels, and we need to clear those caches. $this->container->get('language_manager')->reset(); $languages = $this->container->get('language_manager')->getLanguages(); - $url = $this->container->get('url_generator')->generateFromPath('node/' . $french_node->id(), array('language' => $languages['fr'])); + $url = $french_node->url('canonical', array('language' => $languages['fr'])); $this->assertTrue(strpos($url, $edit['path[0][alias]']), 'URL contains the path alias.'); diff --git a/core/modules/rest/rest.services.yml b/core/modules/rest/rest.services.yml index c25d6920b3e..14e4ab219b6 100644 --- a/core/modules/rest/rest.services.yml +++ b/core/modules/rest/rest.services.yml @@ -18,10 +18,10 @@ services: arguments: ['@rest.link_manager.type', '@rest.link_manager.relation'] rest.link_manager.type: class: Drupal\rest\LinkManager\TypeLinkManager - arguments: ['@cache.default'] + arguments: ['@cache.default', '@unrouted_url_assembler'] rest.link_manager.relation: class: Drupal\rest\LinkManager\RelationLinkManager - arguments: ['@cache.default', '@entity.manager'] + arguments: ['@cache.default', '@entity.manager', '@unrouted_url_assembler'] rest.resource_routes: class: Drupal\rest\Routing\ResourceRoutes arguments: ['@plugin.manager.rest', '@config.factory', '@logger.channel.rest'] diff --git a/core/modules/rest/src/LinkManager/RelationLinkManager.php b/core/modules/rest/src/LinkManager/RelationLinkManager.php index a3e483bd42e..54bec536ae3 100644 --- a/core/modules/rest/src/LinkManager/RelationLinkManager.php +++ b/core/modules/rest/src/LinkManager/RelationLinkManager.php @@ -11,6 +11,7 @@ use Drupal\Core\Cache\Cache; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Entity\ContentEntityTypeInterface; use Drupal\Core\Entity\EntityManagerInterface; +use Drupal\Core\Utility\UnroutedUrlAssemblerInterface; class RelationLinkManager implements RelationLinkManagerInterface { @@ -26,6 +27,13 @@ class RelationLinkManager implements RelationLinkManagerInterface { */ protected $entityManager; + /** + * The unrouted URL assembler. + * + * @var \Drupal\Core\Utility\UnroutedUrlAssemblerInterface + */ + protected $urlAssembler; + /** * Constructor. * @@ -33,18 +41,20 @@ class RelationLinkManager implements RelationLinkManagerInterface { * The cache of relation URIs and their associated Typed Data IDs. * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager * The entity manager. + * @param \Drupal\Core\Utility\UnroutedUrlAssemblerInterface $url_assembler + * The unrouted URL assembler. */ - public function __construct(CacheBackendInterface $cache, EntityManagerInterface $entity_manager) { + public function __construct(CacheBackendInterface $cache, EntityManagerInterface $entity_manager, UnroutedUrlAssemblerInterface $url_assembler) { $this->cache = $cache; $this->entityManager = $entity_manager; + $this->urlAssembler = $url_assembler; } /** * {@inheritdoc} */ public function getRelationUri($entity_type, $bundle, $field_name) { - // @todo Make the base path configurable. - return _url("rest/relation/$entity_type/$bundle/$field_name", array('absolute' => TRUE)); + return $this->urlAssembler->assemble("base://rest/relation/$entity_type/$bundle/$field_name", array('absolute' => TRUE)); } /** diff --git a/core/modules/rest/src/LinkManager/TypeLinkManager.php b/core/modules/rest/src/LinkManager/TypeLinkManager.php index 98ac3d6369e..5a7e6034a7d 100644 --- a/core/modules/rest/src/LinkManager/TypeLinkManager.php +++ b/core/modules/rest/src/LinkManager/TypeLinkManager.php @@ -9,6 +9,7 @@ namespace Drupal\rest\LinkManager; use Drupal\Core\Cache\Cache; use Drupal\Core\Cache\CacheBackendInterface; +use Drupal\Core\Utility\UnroutedUrlAssemblerInterface; class TypeLinkManager implements TypeLinkManagerInterface { @@ -19,14 +20,24 @@ class TypeLinkManager implements TypeLinkManagerInterface { */ protected $cache; + /** + * The unrouted URL assembler. + * + * @var \Drupal\Core\Utility\UnroutedUrlAssemblerInterface + */ + protected $urlAssembler; + /** * Constructor. * * @param \Drupal\Core\Cache\CacheBackendInterface $cache * The injected cache backend for caching type URIs. + * @param \Drupal\Core\Utility\UnroutedUrlAssemblerInterface $url_assembler + * The unrouted URL assembler. */ - public function __construct(CacheBackendInterface $cache) { + public function __construct(CacheBackendInterface $cache, UnroutedUrlAssemblerInterface $url_assembler) { $this->cache = $cache; + $this->urlAssembler = $url_assembler; } /** @@ -42,7 +53,7 @@ class TypeLinkManager implements TypeLinkManagerInterface { */ public function getTypeUri($entity_type, $bundle) { // @todo Make the base path configurable. - return _url("rest/type/$entity_type/$bundle", array('absolute' => TRUE)); + return $this->urlAssembler->assemble("base://rest/type/$entity_type/$bundle", array('absolute' => TRUE)); } /** diff --git a/core/modules/rest/src/Plugin/rest/resource/EntityResource.php b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php index 0f2a785d882..ffb15e0d533 100644 --- a/core/modules/rest/src/Plugin/rest/resource/EntityResource.php +++ b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php @@ -99,9 +99,8 @@ class EntityResource extends ResourceBase { $entity->save(); $this->logger->notice('Created entity %type with ID %id.', array('%type' => $entity->getEntityTypeId(), '%id' => $entity->id())); - $url = _url(strtr($this->pluginId, ':', '/') . '/' . $entity->id(), array('absolute' => TRUE)); // 201 Created responses have an empty body. - return new ResourceResponse(NULL, 201, array('Location' => $url)); + return new ResourceResponse(NULL, 201, array('Location' => $entity->url('canonical', ['absolute' => TRUE]))); } catch (EntityStorageException $e) { throw new HttpException(500, 'Internal Server Error', $e); diff --git a/core/modules/rest/src/Tests/CsrfTest.php b/core/modules/rest/src/Tests/CsrfTest.php index 7ff63896aff..d44d7876f3c 100644 --- a/core/modules/rest/src/Tests/CsrfTest.php +++ b/core/modules/rest/src/Tests/CsrfTest.php @@ -5,6 +5,8 @@ namespace Drupal\rest\Tests; +use Drupal\Core\Url; + /** * Tests the CSRF protection. * @@ -107,7 +109,7 @@ class CsrfTest extends RESTTestBase { CURLOPT_HTTPGET => FALSE, CURLOPT_POST => TRUE, CURLOPT_POSTFIELDS => $this->serialized, - CURLOPT_URL => _url('entity/' . $this->testEntityType, array('absolute' => TRUE)), + CURLOPT_URL => Url::fromRoute('rest.entity.' . $this->testEntityType . '.POST')->setAbsolute()->toString(), CURLOPT_NOBODY => FALSE, CURLOPT_HTTPHEADER => array( "Content-Type: {$this->defaultMimeType}", diff --git a/core/modules/rest/src/Tests/DeleteTest.php b/core/modules/rest/src/Tests/DeleteTest.php index c4c6a9081c9..5a86d776ad5 100644 --- a/core/modules/rest/src/Tests/DeleteTest.php +++ b/core/modules/rest/src/Tests/DeleteTest.php @@ -7,6 +7,7 @@ namespace Drupal\rest\Tests; +use Drupal\Core\Url; use Drupal\rest\Tests\RESTTestBase; /** @@ -53,7 +54,7 @@ class DeleteTest extends RESTTestBase { $this->assertEqual($response, '', 'Response body is empty.'); // Try to delete an entity that does not exist. - $response = $this->httpRequest($entity_type . '/9999', 'DELETE'); + $response = $this->httpRequest(Url::fromRoute('entity.' . $entity_type . '.canonical', [$entity_type => 9999]), 'DELETE'); $this->assertResponse(404); $this->assertText('The requested page could not be found.'); @@ -70,9 +71,9 @@ class DeleteTest extends RESTTestBase { $this->enableService(FALSE); $account = $this->drupalCreateUser(); $this->drupalLogin($account); - $this->httpRequest('entity/user/' . $account->id(), 'DELETE'); + $this->httpRequest($account->urlInfo(), 'DELETE'); $user = entity_load('user', $account->id(), TRUE); $this->assertEqual($account->id(), $user->id(), 'User still exists in the database.'); - $this->assertResponse(404); + $this->assertResponse(405); } } diff --git a/core/modules/rest/src/Tests/NodeTest.php b/core/modules/rest/src/Tests/NodeTest.php index 71d4c3305fb..863cd0435ff 100644 --- a/core/modules/rest/src/Tests/NodeTest.php +++ b/core/modules/rest/src/Tests/NodeTest.php @@ -7,6 +7,7 @@ namespace Drupal\rest\Tests; +use Drupal\Core\Url; use Drupal\rest\Tests\RESTTestBase; /** @@ -50,14 +51,14 @@ class NodeTest extends RESTTestBase { $node = $this->entityCreate('node'); $node->save(); - $this->httpRequest('node/' . $node->id(), 'GET', NULL, $this->defaultMimeType); + $this->httpRequest($node->urlInfo(), 'GET', NULL, $this->defaultMimeType); $this->assertResponse(200); $this->assertHeader('Content-type', $this->defaultMimeType); // Also check that JSON works and the routing system selects the correct // REST route. $this->enableService('entity:node', 'GET', 'json'); - $this->httpRequest('node/' . $node->id(), 'GET', NULL, 'application/json'); + $this->httpRequest($node->urlInfo(), 'GET', NULL, 'application/json'); $this->assertResponse(200); $this->assertHeader('Content-type', 'application/json'); @@ -69,7 +70,7 @@ class NodeTest extends RESTTestBase { $data = array( '_links' => array( 'type' => array( - 'href' => _url('rest/type/node/resttest', array('absolute' => TRUE)), + 'href' => Url::fromUri('base://rest/type/node/resttest', array('absolute' => TRUE))->toString(), ), ), 'title' => array( @@ -79,7 +80,7 @@ class NodeTest extends RESTTestBase { ), ); $serialized = $this->container->get('serializer')->serialize($data, $this->defaultFormat); - $this->httpRequest('node/' . $node->id(), 'PATCH', $serialized, $this->defaultMimeType); + $this->httpRequest($node->urlInfo(), 'PATCH', $serialized, $this->defaultMimeType); $this->assertResponse(204); // Reload the node from the DB and check if the title was correctly updated. diff --git a/core/modules/rest/src/Tests/RESTTestBase.php b/core/modules/rest/src/Tests/RESTTestBase.php index 6f90925e0c8..6b0597355ee 100644 --- a/core/modules/rest/src/Tests/RESTTestBase.php +++ b/core/modules/rest/src/Tests/RESTTestBase.php @@ -64,7 +64,7 @@ abstract class RESTTestBase extends WebTestBase { * Helper function to issue a HTTP request with simpletest's cURL. * * @param string|\Drupal\Core\Url $url - * A relative URL string or a Url object. + * A Url object or system path. * @param string $method * HTTP method, one of GET, POST, PUT or DELETE. * @param array $body @@ -81,13 +81,7 @@ abstract class RESTTestBase extends WebTestBase { $token = $this->drupalGet('rest/session/token'); } - // Convert to absolute URL. - if ($url instanceof Url) { - $url = $url->setAbsolute()->toString(); - } - else { - $url = _url($url, array('absolute' => TRUE)); - } + $url = $this->buildUrl($url); switch ($method) { case 'GET': diff --git a/core/modules/search/src/Tests/SearchConfigSettingsFormTest.php b/core/modules/search/src/Tests/SearchConfigSettingsFormTest.php index 7d99214b518..23954053c24 100644 --- a/core/modules/search/src/Tests/SearchConfigSettingsFormTest.php +++ b/core/modules/search/src/Tests/SearchConfigSettingsFormTest.php @@ -7,6 +7,8 @@ namespace Drupal\search\Tests; +use Drupal\Core\Url; + /** * Verify the search config settings form. * @@ -19,7 +21,7 @@ class SearchConfigSettingsFormTest extends SearchTestBase { * * @var array */ - public static $modules = array('block', 'search_extra_type'); + public static $modules = array('block', 'search_extra_type', 'test_page_test'); /** * User who can search and administer search. @@ -269,8 +271,8 @@ class SearchConfigSettingsFormTest extends SearchTestBase { // Ensure both search pages have their tabs displayed. $this->drupalGet('search'); $elements = $this->xpath('//*[contains(@class, :class)]//a', array(':class' => 'tabs primary')); - $this->assertIdentical((string) $elements[0]['href'], _url('search/' . $first['path'])); - $this->assertIdentical((string) $elements[1]['href'], _url('search/' . $second['path'])); + $this->assertIdentical((string) $elements[0]['href'], Url::fromRoute('search.view_' . $first_id)->toString()); + $this->assertIdentical((string) $elements[1]['href'], Url::fromRoute('search.view_' . $second_id)->toString()); // Switch the weight of the search pages and check the order of the tabs. $edit = array( @@ -280,8 +282,8 @@ class SearchConfigSettingsFormTest extends SearchTestBase { $this->drupalPostForm('admin/config/search/pages', $edit, t('Save configuration')); $this->drupalGet('search'); $elements = $this->xpath('//*[contains(@class, :class)]//a', array(':class' => 'tabs primary')); - $this->assertIdentical((string) $elements[0]['href'], _url('search/' . $second['path'])); - $this->assertIdentical((string) $elements[1]['href'], _url('search/' . $first['path'])); + $this->assertIdentical((string) $elements[0]['href'], Url::fromRoute('search.view_' . $second_id)->toString()); + $this->assertIdentical((string) $elements[1]['href'], Url::fromRoute('search.view_' . $first_id)->toString()); // Check the initial state of the search pages. $this->drupalGet('admin/config/search/pages'); diff --git a/core/modules/search/src/Tests/SearchKeywordsConditionsTest.php b/core/modules/search/src/Tests/SearchKeywordsConditionsTest.php index c5e42f1a883..63f492f11c8 100644 --- a/core/modules/search/src/Tests/SearchKeywordsConditionsTest.php +++ b/core/modules/search/src/Tests/SearchKeywordsConditionsTest.php @@ -23,7 +23,7 @@ class SearchKeywordsConditionsTest extends SearchTestBase { * * @var array */ - public static $modules = array('comment', 'search_extra_type'); + public static $modules = array('comment', 'search_extra_type', 'test_page_test'); /** * A user with permission to search and post comments. diff --git a/core/modules/search/tests/modules/search_extra_type/search_extra_type.info.yml b/core/modules/search/tests/modules/search_extra_type/search_extra_type.info.yml index caea321b30a..1b4cf554369 100644 --- a/core/modules/search/tests/modules/search_extra_type/search_extra_type.info.yml +++ b/core/modules/search/tests/modules/search_extra_type/search_extra_type.info.yml @@ -4,3 +4,6 @@ description: 'Support module for Search module testing.' package: Testing version: VERSION core: 8.x +dependencies: + - test_page_test + diff --git a/core/modules/search/tests/modules/search_extra_type/src/Plugin/Search/SearchExtraTypeSearch.php b/core/modules/search/tests/modules/search_extra_type/src/Plugin/Search/SearchExtraTypeSearch.php index d1855ad5658..fc358d03fa2 100644 --- a/core/modules/search/tests/modules/search_extra_type/src/Plugin/Search/SearchExtraTypeSearch.php +++ b/core/modules/search/tests/modules/search_extra_type/src/Plugin/Search/SearchExtraTypeSearch.php @@ -9,6 +9,8 @@ namespace Drupal\search_extra_type\Plugin\Search; use Drupal\Component\Utility\SafeMarkup; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Routing\UrlGeneratorTrait; +use Drupal\Core\Url; use Drupal\search\Plugin\ConfigurableSearchPluginBase; /** @@ -21,6 +23,8 @@ use Drupal\search\Plugin\ConfigurableSearchPluginBase; */ class SearchExtraTypeSearch extends ConfigurableSearchPluginBase { + use UrlGeneratorTrait; + /** * {@inheritdoc} */ @@ -57,7 +61,7 @@ class SearchExtraTypeSearch extends ConfigurableSearchPluginBase { } return array( array( - 'link' => _url('node'), + 'link' => Url::fromRoute('test_page_test.test_page')->toString(), 'type' => 'Dummy result type', 'title' => 'Dummy title', 'snippet' => SafeMarkup::set("Dummy search snippet to display. Keywords: {$this->keywords}\n\nConditions: " . print_r($this->searchParameters, TRUE)), diff --git a/core/modules/serialization/src/Tests/EntityResolverTest.php b/core/modules/serialization/src/Tests/EntityResolverTest.php index 2bf4ed9b7c7..e87b69b8723 100644 --- a/core/modules/serialization/src/Tests/EntityResolverTest.php +++ b/core/modules/serialization/src/Tests/EntityResolverTest.php @@ -6,6 +6,8 @@ namespace Drupal\serialization\Tests; +use Drupal\Core\Url; + /** * Tests that entities references can be resolved. * @@ -30,6 +32,9 @@ class EntityResolverTest extends NormalizerTestBase { protected function setUp() { parent::setUp(); + $this->installSchema('system', 'router'); + \Drupal::service('router.builder')->rebuild(); + // Create the test field storage. entity_create('field_storage_config', array( 'entity_type' => 'entity_test_mulrev', @@ -58,16 +63,16 @@ class EntityResolverTest extends NormalizerTestBase { $entity->set('field_test_entity_reference', array(array('target_id' => 1))); $entity->save(); - $field_uri = _url('rest/relation/entity_test_mulrev/entity_test_mulrev/field_test_entity_reference', array('absolute' => TRUE)); + $field_uri = Url::fromUri('base://rest/relation/entity_test_mulrev/entity_test_mulrev/field_test_entity_reference', array('absolute' => TRUE))->toString(); $data = array( '_links' => array( 'type' => array( - 'href' => _url('rest/type/entity_test_mulrev/entity_test_mulrev', array('absolute' => TRUE)), + 'href' => Url::fromUri('base://rest/type/entity_test_mulrev/entity_test_mulrev', array('absolute' => TRUE))->toString(), ), $field_uri => array( array( - 'href' => _url('entity/entity_test_mulrev/' . $entity->id()), + 'href' => $entity->url(), ), ), ), @@ -75,7 +80,7 @@ class EntityResolverTest extends NormalizerTestBase { $field_uri => array( array( '_links' => array( - 'self' => _url('entity/entity_test_mulrev/' . $entity->id()), + 'self' => $entity->url(), ), 'uuid' => array( array( diff --git a/core/modules/simpletest/src/Tests/SimpleTestBrowserTest.php b/core/modules/simpletest/src/Tests/SimpleTestBrowserTest.php index a5b97035da4..fedd64c0a88 100644 --- a/core/modules/simpletest/src/Tests/SimpleTestBrowserTest.php +++ b/core/modules/simpletest/src/Tests/SimpleTestBrowserTest.php @@ -7,6 +7,7 @@ namespace Drupal\simpletest\Tests; +use Drupal\Core\Url; use Drupal\simpletest\WebTestBase; /** @@ -76,8 +77,7 @@ class SimpleTestBrowserTest extends WebTestBase { // @see drupal_valid_test_ua() // Not using File API; a potential error must trigger a PHP warning. unlink($this->siteDirectory . '/.htkey'); - global $base_url; - $this->drupalGet(_url($base_url . '/core/install.php', array('external' => TRUE, 'absolute' => TRUE))); + $this->drupalGet(Url::fromUri('base://core/install.php', array('external' => TRUE, 'absolute' => TRUE))->toString()); $this->assertResponse(403, 'Cannot access install.php.'); } diff --git a/core/modules/simpletest/src/WebTestBase.php b/core/modules/simpletest/src/WebTestBase.php index 98253a44940..b24d762942e 100644 --- a/core/modules/simpletest/src/WebTestBase.php +++ b/core/modules/simpletest/src/WebTestBase.php @@ -1470,23 +1470,10 @@ abstract class WebTestBase extends TestBase { * The retrieved HTML string, also available as $this->getRawContent() */ protected function drupalGet($path, array $options = array(), array $headers = array()) { - if ($path instanceof Url) { - $url = $path->setAbsolute()->toString(); - } - // The URL generator service is not necessarily available yet; e.g., in - // interactive installer tests. - else if ($this->container->has('url_generator')) { - $options['absolute'] = TRUE; - $url = $this->container->get('url_generator')->generateFromPath($path, $options); - } - else { - $url = $this->getAbsoluteUrl($path); - } - // We re-using a CURL connection here. If that connection still has certain // options set, it might change the GET into a POST. Make sure we clear out // previous options. - $out = $this->curlExec(array(CURLOPT_HTTPGET => TRUE, CURLOPT_URL => $url, CURLOPT_NOBODY => FALSE, CURLOPT_HTTPHEADER => $headers)); + $out = $this->curlExec(array(CURLOPT_HTTPGET => TRUE, CURLOPT_URL => $this->buildUrl($path, $options), CURLOPT_NOBODY => FALSE, CURLOPT_HTTPHEADER => $headers)); // Ensure that any changes to variables in the other thread are picked up. $this->refreshVariables(); @@ -1512,7 +1499,7 @@ abstract class WebTestBase extends TestBase { * @param string $path * Path to request AJAX from. * @param array $options - * Array of options to pass to _url(). + * Array of URL options. * @param array $headers * Array of headers. Eg array('Accept: application/vnd.drupal-ajax'). * @@ -1967,11 +1954,10 @@ abstract class WebTestBase extends TestBase { * * @see WebTestBase::getAjaxPageStatePostData() * @see WebTestBase::curlExec() - * @see _url() */ protected function drupalPost($path, $accept, array $post, $options = array()) { return $this->curlExec(array( - CURLOPT_URL => _url($path, $options + array('absolute' => TRUE)), + CURLOPT_URL => $this->buildUrl($path, $options), CURLOPT_POST => TRUE, CURLOPT_POSTFIELDS => $this->serializePostValues($post), CURLOPT_HTTPHEADER => array( @@ -2733,4 +2719,30 @@ abstract class WebTestBase extends TestBase { return $request; } + + /** + * Builds an a absolute URL from a system path or a URL object. + * + * @param string|\Drupal\Core\Url $path + * A system path or a URL. + * @param array $options + * Options to be passed to Url::fromUri(). + * + * @return string + * An absolute URL stsring. + */ + protected function buildUrl($path, array $options = array()) { + if ($path instanceof Url) { + return $path->setAbsolute()->toString(); + } + // The URL generator service is not necessarily available yet; e.g., in + // interactive installer tests. + else if ($this->container->has('url_generator')) { + $options['absolute'] = TRUE; + return $this->container->get('url_generator')->generateFromPath($path, $options); + } + else { + return $this->getAbsoluteUrl($path); + } + } } diff --git a/core/modules/statistics/statistics.module b/core/modules/statistics/statistics.module index 489241fe95e..c70c1a63f70 100644 --- a/core/modules/statistics/statistics.module +++ b/core/modules/statistics/statistics.module @@ -8,6 +8,7 @@ use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\Display\EntityViewDisplayInterface; use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\Core\Url; use Drupal\node\NodeInterface; /** @@ -39,7 +40,7 @@ function statistics_help($route_name, RouteMatchInterface $route_match) { function statistics_node_view(array &$build, EntityInterface $node, EntityViewDisplayInterface $display, $view_mode) { if (!$node->isNew() && $view_mode == 'full' && node_is_page($node) && empty($node->in_preview)) { $build['statistics_content_counter']['#attached']['library'][] = 'statistics/drupal.statistics'; - $settings = array('data' => array('nid' => $node->id()), 'url' => _url(drupal_get_path('module', 'statistics') . '/statistics.php')); + $settings = array('data' => array('nid' => $node->id()), 'url' => Url::fromUri('base://' . drupal_get_path('module', 'statistics') . '/statistics.php')->toString()); $build['statistics_content_counter']['#attached']['drupalSettings']['statistics'] = $settings; } } diff --git a/core/modules/system/menu.api.php b/core/modules/system/menu.api.php index 54e55d96561..0da0dc6e1e5 100644 --- a/core/modules/system/menu.api.php +++ b/core/modules/system/menu.api.php @@ -480,7 +480,7 @@ function hook_local_tasks_alter(&$local_tasks) { * - title: The localized title of the link. * - route_name: The route name of the link. * - route_parameters: The route parameters of the link. - * - localized_options: An array of options to pass to _url(). + * - localized_options: An array of URL options. * - (optional) weight: The weight of the link, which is used to sort the links. * * diff --git a/core/modules/system/src/Controller/DbUpdateController.php b/core/modules/system/src/Controller/DbUpdateController.php index d61ab93c6c0..ba5d75cf4d8 100644 --- a/core/modules/system/src/Controller/DbUpdateController.php +++ b/core/modules/system/src/Controller/DbUpdateController.php @@ -601,7 +601,7 @@ class DbUpdateController extends ControllerBase { ); batch_set($batch); - return batch_process('update.php/results', 'update.php/batch'); + return batch_process('update.php/results', Url::fromRoute('system.db_update')); } /** diff --git a/core/modules/system/src/Tests/Cache/PageCacheTagsIntegrationTest.php b/core/modules/system/src/Tests/Cache/PageCacheTagsIntegrationTest.php index 3fc3e3413ab..c41d2fa8489 100644 --- a/core/modules/system/src/Tests/Cache/PageCacheTagsIntegrationTest.php +++ b/core/modules/system/src/Tests/Cache/PageCacheTagsIntegrationTest.php @@ -7,6 +7,7 @@ namespace Drupal\system\Tests\Cache; +use Drupal\Core\Url; use Drupal\simpletest\WebTestBase; use Drupal\Core\Cache\Cache; @@ -67,7 +68,7 @@ class PageCacheTagsIntegrationTest extends WebTestBase { )); // Full node page 1. - $this->verifyPageCacheTags('node/' . $node_1->id(), array( + $this->verifyPageCacheTags($node_1->urlInfo(), array( 'rendered', 'block_view', 'config:block_list', @@ -96,7 +97,7 @@ class PageCacheTagsIntegrationTest extends WebTestBase { )); // Full node page 2. - $this->verifyPageCacheTags('node/' . $node_2->id(), array( + $this->verifyPageCacheTags($node_2->urlInfo(), array( 'rendered', 'block_view', 'config:block_list', @@ -130,24 +131,26 @@ class PageCacheTagsIntegrationTest extends WebTestBase { /** * Fills page cache for the given path, verify cache tags on page cache hit. * - * @param $path - * The Drupal page path to test. + * @param \Drupal\Core\Url $url + * The url * @param $expected_tags * The expected cache tags for the page cache entry of the given $path. */ - protected function verifyPageCacheTags($path, $expected_tags) { + protected function verifyPageCacheTags(Url $url, $expected_tags) { + // @todo Change ->drupalGet() calls to just pass $url when + // https://www.drupal.org/node/2350837 gets committed sort($expected_tags); - $this->drupalGet($path); + $this->drupalGet($url->setAbsolute()->toString()); $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS'); $actual_tags = explode(' ', $this->drupalGetHeader('X-Drupal-Cache-Tags')); sort($actual_tags); $this->assertIdentical($actual_tags, $expected_tags); - $this->drupalGet($path); + $this->drupalGet($url->setAbsolute()->toString()); $actual_tags = explode(' ', $this->drupalGetHeader('X-Drupal-Cache-Tags')); sort($actual_tags); $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT'); $this->assertIdentical($actual_tags, $expected_tags); - $cid_parts = array(_url($path, array('absolute' => TRUE)), 'html'); + $cid_parts = array($url->setAbsolute()->toString(), 'html'); $cid = implode(':', $cid_parts); $cache_entry = \Drupal::cache('render')->get($cid); sort($cache_entry->tags); diff --git a/core/modules/system/src/Tests/Common/AddFeedTest.php b/core/modules/system/src/Tests/Common/AddFeedTest.php index 0f5a5607c16..4fe5e6f388f 100644 --- a/core/modules/system/src/Tests/Common/AddFeedTest.php +++ b/core/modules/system/src/Tests/Common/AddFeedTest.php @@ -7,6 +7,7 @@ namespace Drupal\system\Tests\Common; +use Drupal\Core\Url; use Drupal\simpletest\WebTestBase; /** @@ -22,15 +23,15 @@ class AddFeedTest extends WebTestBase { function testBasicFeedAddNoTitle() { $path = $this->randomMachineName(12); $external_url = 'http://' . $this->randomMachineName(12) . '/' . $this->randomMachineName(12); - $fully_qualified_local_url = _url($this->randomMachineName(12), array('absolute' => TRUE)); + $fully_qualified_local_url = Url::fromUri('base://' . $this->randomMachineName(12), array('absolute' => TRUE))->toString(); $path_for_title = $this->randomMachineName(12); $external_for_title = 'http://' . $this->randomMachineName(12) . '/' . $this->randomMachineName(12); - $fully_qualified_for_title = _url($this->randomMachineName(12), array('absolute' => TRUE)); + $fully_qualified_for_title = Url::fromUri('base://' . $this->randomMachineName(12), array('absolute' => TRUE))->toString(); $urls = array( 'path without title' => array( - 'url' => _url($path, array('absolute' => TRUE)), + 'url' => Url::fromUri('base://' . $path, array('absolute' => TRUE))->toString(), 'title' => '', ), 'external URL without title' => array( @@ -42,7 +43,7 @@ class AddFeedTest extends WebTestBase { 'title' => '', ), 'path with title' => array( - 'url' => _url($path_for_title, array('absolute' => TRUE)), + 'url' => Url::fromUri('base://' . $path_for_title, array('absolute' => TRUE))->toString(), 'title' => $this->randomMachineName(12), ), 'external URL with title' => array( diff --git a/core/modules/system/src/Tests/Common/AttachedAssetsTest.php b/core/modules/system/src/Tests/Common/AttachedAssetsTest.php index 537d062abee..10bf8181907 100644 --- a/core/modules/system/src/Tests/Common/AttachedAssetsTest.php +++ b/core/modules/system/src/Tests/Common/AttachedAssetsTest.php @@ -52,6 +52,8 @@ class AttachedAssetsTest extends KernelTestBase { */ protected function setUp() { parent::setUp(); + $this->installSchema('system', array('router')); + $this->container->get('router.builder')->rebuild(); $this->assetResolver = $this->container->get('asset.resolver'); $this->renderer = $this->container->get('renderer'); diff --git a/core/modules/system/src/Tests/Common/RenderElementTypesTest.php b/core/modules/system/src/Tests/Common/RenderElementTypesTest.php index 4484ea54760..f757ef20119 100644 --- a/core/modules/system/src/Tests/Common/RenderElementTypesTest.php +++ b/core/modules/system/src/Tests/Common/RenderElementTypesTest.php @@ -148,7 +148,7 @@ class RenderElementTypesTest extends KernelTestBase { '#type' => 'more_link', '#url' => Url::fromRoute('router_test.1'), ), - 'expected' => '//div[@class="more-link"]/a[@href="' . _url('router_test/test1') . '" and text()="More"]', + 'expected' => '//div[@class="more-link"]/a[@href="' . Url::fromRoute('router_test.1')->toString() . '" and text()="More"]', ), array( 'name' => "#type 'more_link' anchor tag with a route", @@ -165,7 +165,7 @@ class RenderElementTypesTest extends KernelTestBase { '#url' => Url::fromRoute('system.admin_content'), '#options' => array('absolute' => TRUE), ), - 'expected' => '//div[@class="more-link"]/a[@href="' . _url('admin/content', array('absolute' => TRUE)) . '" and text()="More"]', + 'expected' => '//div[@class="more-link"]/a[@href="' . Url::fromRoute('system.admin_content')->setAbsolute()->toString() . '" and text()="More"]', ), array( 'name' => "#type 'more_link' anchor tag to the front page", @@ -173,7 +173,7 @@ class RenderElementTypesTest extends KernelTestBase { '#type' => 'more_link', '#url' => Url::fromRoute(''), ), - 'expected' => '//div[@class="more-link"]/a[@href="' . _url('') . '" and text()="More"]', + 'expected' => '//div[@class="more-link"]/a[@href="' . Url::fromRoute('')->toString() . '" and text()="More"]', ), ); diff --git a/core/modules/system/src/Tests/Common/UrlTest.php b/core/modules/system/src/Tests/Common/UrlTest.php index 92342d2cc06..21ea4322196 100644 --- a/core/modules/system/src/Tests/Common/UrlTest.php +++ b/core/modules/system/src/Tests/Common/UrlTest.php @@ -13,15 +13,11 @@ use Drupal\Core\Url; use Drupal\simpletest\WebTestBase; /** - * Confirm that _url(), + * Confirm that \Drupal\Core\Url, * \Drupal\Component\Utility\UrlHelper::filterQueryParameters(), * \Drupal\Component\Utility\UrlHelper::buildQuery(), and _l() work correctly * with various input. * - * _url() calls \Drupal::moduleHandler()->getImplementations(), - * which may issue a db query, which requires - * inheriting from a web test case rather than a unit test case. - * * @group Common */ class UrlTest extends WebTestBase { @@ -36,12 +32,12 @@ class UrlTest extends WebTestBase { $text = $this->randomMachineName(); $path = ""; $link = _l($text, $path); - $sanitized_path = check_url(_url($path)); + $sanitized_path = check_url(Url::fromUri('base://' . $path)->toString()); $this->assertTrue(strpos($link, $sanitized_path) !== FALSE, format_string('XSS attack @path was filtered by _l().', array('@path' => $path))); - // Test _url(). - $link = _url($path); - $sanitized_path = check_url(_url($path)); + // Test \Drupal\Core\Url. + $link = Url::fromUri('base://' . $path)->toString(); + $sanitized_path = check_url(Url::fromUri('base://' . $path)->toString()); $this->assertTrue(strpos($link, $sanitized_path) !== FALSE, format_string('XSS attack @path was filtered by #theme', ['@path' => $path])); } @@ -91,20 +87,20 @@ class UrlTest extends WebTestBase { $path = 'common-test/type-link-active-class'; $this->drupalGet($path, $options_no_query); - $links = $this->xpath('//a[@href = :href and contains(@class, :class)]', array(':href' => _url($path, $options_no_query), ':class' => 'active')); + $links = $this->xpath('//a[@href = :href and contains(@class, :class)]', array(':href' => Url::fromRoute('common_test.l_active_class', [], $options_no_query)->toString(), ':class' => 'active')); $this->assertTrue(isset($links[0]), 'A link generated by _l() to the current page is marked active.'); - $links = $this->xpath('//a[@href = :href and not(contains(@class, :class))]', array(':href' => _url($path, $options_query), ':class' => 'active')); + $links = $this->xpath('//a[@href = :href and not(contains(@class, :class))]', array(':href' => Url::fromRoute('common_test.l_active_class', [], $options_query)->toString(), ':class' => 'active')); $this->assertTrue(isset($links[0]), 'A link generated by _l() to the current page with a query string when the current page has no query string is not marked active.'); $this->drupalGet($path, $options_query); - $links = $this->xpath('//a[@href = :href and contains(@class, :class)]', array(':href' => _url($path, $options_query), ':class' => 'active')); + $links = $this->xpath('//a[@href = :href and contains(@class, :class)]', array(':href' => Url::fromRoute('common_test.l_active_class', [], $options_query)->toString(), ':class' => 'active')); $this->assertTrue(isset($links[0]), 'A link generated by _l() to the current page with a query string that matches the current query string is marked active.'); - $links = $this->xpath('//a[@href = :href and contains(@class, :class)]', array(':href' => _url($path, $options_query_reverse), ':class' => 'active')); + $links = $this->xpath('//a[@href = :href and contains(@class, :class)]', array(':href' => Url::fromRoute('common_test.l_active_class', [], $options_query_reverse)->toString(), ':class' => 'active')); $this->assertTrue(isset($links[0]), 'A link generated by _l() to the current page with a query string that has matching parameters to the current query string but in a different order is marked active.'); - $links = $this->xpath('//a[@href = :href and not(contains(@class, :class))]', array(':href' => _url($path, $options_no_query), ':class' => 'active')); + $links = $this->xpath('//a[@href = :href and not(contains(@class, :class))]', array(':href' => Url::fromRoute('common_test.l_active_class', [], $options_no_query)->toString(), ':class' => 'active')); $this->assertTrue(isset($links[0]), 'A link generated by _l() to the current page without a query string when the current page has a query string is not marked active.'); // Test adding a custom class in links produced by _l() and #type 'link'. @@ -257,30 +253,30 @@ class UrlTest extends WebTestBase { // Verify external URL can contain a fragment. $url = $test_url . '#drupal'; - $result = _url($url); + $result = Url::fromUri($url)->toString(); $this->assertEqual($url, $result, 'External URL with fragment works without a fragment in $options.'); // Verify fragment can be overidden in an external URL. $url = $test_url . '#drupal'; $fragment = $this->randomMachineName(10); - $result = _url($url, array('fragment' => $fragment)); + $result = Url::fromUri($url, array('fragment' => $fragment))->toString(); $this->assertEqual($test_url . '#' . $fragment, $result, 'External URL fragment is overidden with a custom fragment in $options.'); // Verify external URL can contain a query string. $url = $test_url . '?drupal=awesome'; - $result = _url($url); + $result = Url::fromUri($url)->toString(); $this->assertEqual($url, $result, 'External URL with query string works without a query string in $options.'); // Verify external URL can be extended with a query string. $url = $test_url; $query = array($this->randomMachineName(5) => $this->randomMachineName(5)); - $result = _url($url, array('query' => $query)); + $result = Url::fromUri($url, array('query' => $query))->toString(); $this->assertEqual($url . '?' . http_build_query($query, '', '&'), $result, 'External URL can be extended with a query string in $options.'); // Verify query string can be extended in an external URL. $url = $test_url . '?drupal=awesome'; $query = array($this->randomMachineName(5) => $this->randomMachineName(5)); - $result = _url($url, array('query' => $query)); + $result = Url::fromUri($url, array('query' => $query))->toString(); $this->assertEqual($url . '&' . http_build_query($query, '', '&'), $result, 'External URL query string can be extended with a custom query string in $options.'); } } diff --git a/core/modules/system/src/Tests/Form/RebuildTest.php b/core/modules/system/src/Tests/Form/RebuildTest.php index a1d4ac2cbe9..76de7480af5 100644 --- a/core/modules/system/src/Tests/Form/RebuildTest.php +++ b/core/modules/system/src/Tests/Form/RebuildTest.php @@ -8,6 +8,7 @@ namespace Drupal\system\Tests\Form; use Drupal\Core\Field\FieldStorageDefinitionInterface; +use Drupal\Core\Url; use Drupal\simpletest\WebTestBase; /** @@ -105,6 +106,6 @@ class RebuildTest extends WebTestBase { // Ensure that the form's action is correct. $forms = $this->xpath('//form[contains(@class, "node-page-form")]'); - $this->assert(count($forms) == 1 && $forms[0]['action'] == _url('node/add/page'), 'Re-rendered form contains the correct action value.'); + $this->assert(count($forms) == 1 && $forms[0]['action'] == Url::fromRoute('node.add', ['node_type' => 'page'])->toString(), 'Re-rendered form contains the correct action value.'); } } diff --git a/core/modules/system/src/Tests/Menu/AssertBreadcrumbTrait.php b/core/modules/system/src/Tests/Menu/AssertBreadcrumbTrait.php index a21a0db2174..463ad4e17fc 100644 --- a/core/modules/system/src/Tests/Menu/AssertBreadcrumbTrait.php +++ b/core/modules/system/src/Tests/Menu/AssertBreadcrumbTrait.php @@ -8,6 +8,7 @@ namespace Drupal\system\Tests\Menu; use Drupal\Component\Utility\String; +use Drupal\Core\Url; /** * Provides test assertions for verifying breadcrumbs. @@ -68,9 +69,19 @@ trait AssertBreadcrumbTrait { // this test would go into an infinite loop, so we need to check that too. while ($trail && !empty($parts)) { foreach ($trail as $path => $title) { - // If the path is empty or does not start with a leading /, assume it - // is an internal path that needs to be passed through _url(). - $url = $path == '' || $path[0] != '/' ? _url($path) : $path; + // If the path is empty, generate the path from the route. If + // the path does not start with a leading, then run it through + // Url::fromUri('base://')->toString() to get correct the base + // prepended. + if ($path == '') { + $url = Url::fromRoute('')->toString(); + } + elseif ($path[0] != '/') { + $url = Url::fromUri('base://' . $path)->toString(); + } + else { + $url = $path; + } $part = array_shift($parts); $pass = ($pass && $part['href'] === $url && $part['text'] === String::checkPlain($title)); } diff --git a/core/modules/system/src/Tests/Menu/AssertMenuActiveTrailTrait.php b/core/modules/system/src/Tests/Menu/AssertMenuActiveTrailTrait.php index a3146ba2b4d..ecf6f4368a0 100644 --- a/core/modules/system/src/Tests/Menu/AssertMenuActiveTrailTrait.php +++ b/core/modules/system/src/Tests/Menu/AssertMenuActiveTrailTrait.php @@ -7,6 +7,8 @@ namespace Drupal\system\Tests\Menu; +use Drupal\Core\Url; + /** * Provides test assertions for verifying the active menu trail. */ @@ -35,7 +37,7 @@ trait AssertMenuActiveTrailTrait { $part_xpath .= 'li[contains(@class, :class)]/a[contains(@href, :href) and contains(text(), :title)]'; $part_args = array( ':class' => 'active-trail', - ':href' => _url($link_path), + ':href' => Url::fromUri('base://' . $link_path)->toString(), ':title' => $link_title, ); $xpath .= $this->buildXPathQuery($part_xpath, $part_args); @@ -55,7 +57,7 @@ trait AssertMenuActiveTrailTrait { $args = array( ':class-trail' => 'active-trail', ':class-active' => 'active', - ':href' => _url($active_link_path), + ':href' => Url::fromUri('base://' . $active_link_path)->toString(), ':title' => $active_link_title, ); $elements = $this->xpath($xpath, $args); diff --git a/core/modules/system/src/Tests/Menu/BreadcrumbTest.php b/core/modules/system/src/Tests/Menu/BreadcrumbTest.php index ab0950c5637..6e3db53675b 100644 --- a/core/modules/system/src/Tests/Menu/BreadcrumbTest.php +++ b/core/modules/system/src/Tests/Menu/BreadcrumbTest.php @@ -7,8 +7,7 @@ namespace Drupal\system\Tests\Menu; -use Drupal\Component\Utility\String; -use Drupal\Component\Utility\Unicode; +use Drupal\Core\Url; use Drupal\node\Entity\NodeType; /** @@ -279,7 +278,7 @@ class BreadcrumbTest extends MenuTestBase { // other than the breadcrumb trail. $elements = $this->xpath('//nav[@id=:menu]/descendant::a[@href=:href]', array( ':menu' => 'block-bartik-tools', - ':href' => _url($link_path), + ':href' => Url::fromUri('base://' . $link_path)->toString(), )); $this->assertTrue(count($elements) == 1, "Link to {$link_path} appears only once."); diff --git a/core/modules/system/src/Tests/Menu/LocalActionTest.php b/core/modules/system/src/Tests/Menu/LocalActionTest.php index 3c02aad9009..c049198fcd4 100644 --- a/core/modules/system/src/Tests/Menu/LocalActionTest.php +++ b/core/modules/system/src/Tests/Menu/LocalActionTest.php @@ -7,6 +7,7 @@ namespace Drupal\system\Tests\Menu; +use Drupal\Core\Url; use Drupal\simpletest\WebTestBase; /** @@ -27,12 +28,12 @@ class LocalActionTest extends WebTestBase { public function testLocalAction() { $this->drupalGet('menu-test-local-action'); // Ensure that both menu and route based actions are shown. - $this->assertLocalAction(array( - 'menu-test-local-action/dynamic-title' => 'My dynamic-title action', - 'menu-test-local-action/hook_menu' => 'My hook_menu action', - 'menu-test-local-action/routing' => 'My YAML discovery action', - 'menu-test-local-action/routing2' => 'Title override', - )); + $this->assertLocalAction([ + [Url::fromRoute('menu_test.local_action4'), 'My dynamic-title action'], + [Url::fromRoute('menu_test.local_action2'), 'My hook_menu action'], + [Url::fromRoute('menu_test.local_action3'), 'My YAML discovery action'], + [Url::fromRoute('menu_test.local_action5'), 'Title override'], + ]); } /** @@ -46,9 +47,11 @@ class LocalActionTest extends WebTestBase { ':class' => 'button-action', )); $index = 0; - foreach ($actions as $href => $title) { + foreach ($actions as $action) { + /** @var \Drupal\Core\Url $url */ + list($url, $title) = $action; $this->assertEqual((string) $elements[$index], $title); - $this->assertEqual($elements[$index]['href'], _url($href)); + $this->assertEqual($elements[$index]['href'], $url->toString()); $index++; } } diff --git a/core/modules/system/src/Tests/Menu/LocalTasksTest.php b/core/modules/system/src/Tests/Menu/LocalTasksTest.php index fc6131510d1..37b44d8aad5 100644 --- a/core/modules/system/src/Tests/Menu/LocalTasksTest.php +++ b/core/modules/system/src/Tests/Menu/LocalTasksTest.php @@ -7,6 +7,7 @@ namespace Drupal\system\Tests\Menu; +use Drupal\Core\Url; use Drupal\simpletest\WebTestBase; /** @@ -34,7 +35,7 @@ class LocalTasksTest extends WebTestBase { )); $this->assertTrue(count($elements), 'Local tasks found.'); foreach ($hrefs as $index => $element) { - $expected = _url($hrefs[$index]); + $expected = Url::fromUri('base://' . $hrefs[$index])->toString(); $method = ($elements[$index]['href'] == $expected ? 'pass' : 'fail'); $this->{$method}(format_string('Task @number href @value equals @expected.', array( '@number' => $index + 1, diff --git a/core/modules/system/src/Tests/Menu/MenuRouterTest.php b/core/modules/system/src/Tests/Menu/MenuRouterTest.php index 68617bed078..063169799ff 100644 --- a/core/modules/system/src/Tests/Menu/MenuRouterTest.php +++ b/core/modules/system/src/Tests/Menu/MenuRouterTest.php @@ -7,6 +7,7 @@ namespace Drupal\system\Tests\Menu; +use Drupal\Core\Url; use Drupal\simpletest\WebTestBase; /** @@ -62,7 +63,8 @@ class MenuRouterTest extends WebTestBase { */ protected function doTestHookMenuIntegration() { // Generate base path with random argument. - $base_path = 'foo/' . $this->randomMachineName(8); + $machine_name = $this->randomMachineName(8); + $base_path = 'foo/' . $machine_name; $this->drupalGet($base_path); // Confirm correct controller activated. $this->assertText('test1'); @@ -70,8 +72,8 @@ class MenuRouterTest extends WebTestBase { $this->assertLink('Local task A'); $this->assertLink('Local task B'); // Confirm correct local task href. - $this->assertLinkByHref(_url($base_path)); - $this->assertLinkByHref(_url($base_path . '/b')); + $this->assertLinkByHref(Url::fromRoute('menu_test.router_test1', ['bar' => $machine_name])->toString()); + $this->assertLinkByHref(Url::fromRoute('menu_test.router_test2', ['bar' => $machine_name])->toString()); } /** diff --git a/core/modules/system/src/Tests/Menu/MenuTranslateTest.php b/core/modules/system/src/Tests/Menu/MenuTranslateTest.php index ea4b3024327..e316c95002f 100644 --- a/core/modules/system/src/Tests/Menu/MenuTranslateTest.php +++ b/core/modules/system/src/Tests/Menu/MenuTranslateTest.php @@ -7,6 +7,7 @@ namespace Drupal\system\Tests\Menu; +use Drupal\Core\Url; use Drupal\simpletest\WebTestBase; /** @@ -40,7 +41,7 @@ class MenuTranslateTest extends WebTestBase { $this->assertResponse(403); $elements = $this->xpath('//ul[@class=:class]/li/a[@href=:href]', array( ':class' => 'tabs primary', - ':href' => _url('foo/asdf'), + ':href' => Url::fromRoute('menu_test.router_test1', ['bar' => 'asdf'])->toString(), )); $this->assertTrue(empty($elements), 'No tab linking to foo/asdf found'); $this->assertNoLinkByHref('foo/asdf/b'); diff --git a/core/modules/system/src/Tests/Path/UrlAlterFunctionalTest.php b/core/modules/system/src/Tests/Path/UrlAlterFunctionalTest.php index 72601696d90..c62decbe1b3 100644 --- a/core/modules/system/src/Tests/Path/UrlAlterFunctionalTest.php +++ b/core/modules/system/src/Tests/Path/UrlAlterFunctionalTest.php @@ -78,9 +78,9 @@ class UrlAlterFunctionalTest extends WebTestBase { * Assert that an outbound path is altered to an expected value. * * @param $original - * A string with the original path that is run through _url(). + * A string with the original path that is run through generateFrommPath(). * @param $final - * A string with the expected result after _url(). + * A string with the expected result after generateFrommPath(). * @return * TRUE if $original was correctly altered to $final, FALSE otherwise. */ @@ -98,7 +98,7 @@ class UrlAlterFunctionalTest extends WebTestBase { * @param $original * The original path before it has been altered by inbound URL processing. * @param $final - * A string with the expected result after _url(). + * A string with the expected result. * @return * TRUE if $original was correctly altered to $final, FALSE otherwise. */ diff --git a/core/modules/system/src/Tests/System/TokenReplaceUnitTest.php b/core/modules/system/src/Tests/System/TokenReplaceUnitTest.php index 9a51f2f706f..f489c7548d8 100644 --- a/core/modules/system/src/Tests/System/TokenReplaceUnitTest.php +++ b/core/modules/system/src/Tests/System/TokenReplaceUnitTest.php @@ -74,7 +74,7 @@ class TokenReplaceUnitTest extends TokenReplaceUnitTestBase { * Tests the generation of all system site information tokens. */ public function testSystemSiteTokenReplacement() { - // The use of the _url() function requires the url_alias table to exist. + // The use of the \Drupal::url() method requires the url_alias table to exist. $this->installSchema('system', 'url_alias'); $url_options = array( 'absolute' => TRUE, diff --git a/core/modules/system/src/Tests/Theme/FunctionsTest.php b/core/modules/system/src/Tests/Theme/FunctionsTest.php index c1ad1c7e4da..abdcff646ff 100644 --- a/core/modules/system/src/Tests/Theme/FunctionsTest.php +++ b/core/modules/system/src/Tests/Theme/FunctionsTest.php @@ -217,7 +217,7 @@ class FunctionsTest extends WebTestBase { $expected_links .= '