diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index be8c695..f991991 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -6,7 +6,7 @@ use Drupal\Component\Utility\String; use Drupal\Component\Utility\Timer; use Drupal\Component\Utility\Unicode; -use Drupal\Component\Utility\Url; +use Drupal\Component\Utility\UrlHelper; use Drupal\Core\DrupalKernel; use Drupal\Core\Database\Database; use Drupal\Core\DependencyInjection\ContainerBuilder; diff --git a/core/includes/common.inc b/core/includes/common.inc index b97cc5e..f06cae2 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -6,7 +6,7 @@ use Drupal\Component\Utility\SortArray; use Drupal\Component\Utility\String; use Drupal\Component\Utility\Tags; -use Drupal\Component\Utility\Url; +use Drupal\Component\Utility\UrlHelper; use Drupal\Component\Utility\Xss; use Drupal\Core\Cache\Cache; use Drupal\Core\Language\Language; @@ -421,26 +421,26 @@ function drupal_get_feeds($delimiter = "\n") { * @return * An array containing query parameters, which can be used for url(). * - * @deprecated as of Drupal 8.0. Use Url::filterQueryParameters() instead. + * @deprecated as of Drupal 8.0. Use UrlHelper::filterQueryParameters() instead. */ function drupal_get_query_parameters(array $query = NULL, array $exclude = array(), $parent = '') { if (!isset($query)) { $query = \Drupal::request()->query->all(); } - return Url::filterQueryParameters($query, $exclude, $parent); + return UrlHelper::filterQueryParameters($query, $exclude, $parent); } /** * Parses an array into a valid, rawurlencoded query string. * * @see drupal_get_query_parameters() - * @deprecated as of Drupal 8.0. Use Url::buildQuery() instead. + * @deprecated as of Drupal 8.0. Use UrlHelper::buildQuery() instead. * @ingroup php_wrappers * - * @deprecated as of Drupal 8.0. Use Url::buildQuery() instead. + * @deprecated as of Drupal 8.0. Use UrlHelper::buildQuery() instead. */ function drupal_http_build_query(array $query, $parent = '') { - return Url::buildQuery($query, $parent); + return UrlHelper::buildQuery($query, $parent); } /** @@ -471,7 +471,7 @@ function drupal_get_destination() { } else { $path = current_path(); - $query = Url::buildQuery(Url::filterQueryParameters($query->all())); + $query = UrlHelper::buildQuery(UrlHelper::filterQueryParameters($query->all())); if ($query != '') { $path .= '?' . $query; } @@ -513,10 +513,10 @@ function drupal_get_destination() { * @see url() * @ingroup php_wrappers * - * @deprecated as of Drupal 8.0. Use Url::parse() instead. + * @deprecated as of Drupal 8.0. Use UrlHelper::parse() instead. */ function drupal_parse_url($url) { - return Url::parse($url); + return UrlHelper::parse($url); } /** @@ -530,10 +530,10 @@ function drupal_parse_url($url) { * @param $path * The Drupal path to encode. * - * @deprecated as of Drupal 8.0. Use Url::encodePath() instead. + * @deprecated as of Drupal 8.0. Use UrlHelper::encodePath() instead. */ function drupal_encode_path($path) { - return Url::encodePath($path); + return UrlHelper::encodePath($path); } /** @@ -545,10 +545,10 @@ function drupal_encode_path($path) { * @return * TRUE if the URL has the same domain and base path. * - * @deprecated as of Drupal 8.0. Use Url::externalIsLocal() instead. + * @deprecated as of Drupal 8.0. Use UrlHelper::externalIsLocal() instead. */ function _external_url_is_local($url) { - return Url::externalIsLocal($url, base_path()); + return UrlHelper::externalIsLocal($url, base_path()); } /** @@ -602,12 +602,12 @@ function valid_email_address($mail) { * @return * TRUE if the URL is in a valid format. * - * @see \Drupal\Component\Utility\Url::isValid() + * @see \Drupal\Component\Utility\UrlHelper::isValid() * - * @deprecated as of Drupal 8.0. Use Url::isValid() instead. + * @deprecated as of Drupal 8.0. Use UrlHelper::isValid() instead. */ function valid_url($url, $absolute = FALSE) { - return Url::isValid($url, $absolute); + return UrlHelper::isValid($url, $absolute); } /** @@ -666,10 +666,10 @@ function valid_number_step($value, $step, $offset = 0.0) { * \Drupal\Component\Utility\String::checkPlain() being called on it. However, * it can be passed to functions expecting plain-text strings. * - * @see \Drupal\Component\Utility\Url::stripDangerousProtocols() + * @see \Drupal\Component\Utility\UrlHelper::stripDangerousProtocols() */ function drupal_strip_dangerous_protocols($uri) { - return Url::stripDangerousProtocols($uri); + return UrlHelper::stripDangerousProtocols($uri); } /** @@ -685,13 +685,13 @@ function drupal_strip_dangerous_protocols($uri) { * because Drupal\Core\Template\Attribute expects those values to be * plain-text strings. To pass a filtered URI to * Drupal\Core\Template\Attribute, call - * \Drupal\Component\Utility\Url::stripDangerousProtocols() instead. + * \Drupal\Component\Utility\UrlHelper::stripDangerousProtocols() instead. * - * @see \Drupal\Component\Utility\Url::stripDangerousProtocols() + * @see \Drupal\Component\Utility\UrlHelper::stripDangerousProtocols() * @see \Drupal\Component\Utility\String::checkPlain() */ function check_url($uri) { - return String::checkPlain(Url::stripDangerousProtocols($uri)); + return String::checkPlain(UrlHelper::stripDangerousProtocols($uri)); } /** @@ -757,10 +757,10 @@ function filter_xss($string, $allowed_tags = array('a', 'em', 'strong', 'cite', * @return string * Cleaned up and HTML-escaped version of $string. * - * @see \Drupal\Component\Utility\Url::filterBadProtocol() + * @see \Drupal\Component\Utility\UrlHelper::filterBadProtocol() */ function filter_xss_bad_protocol($string) { - return Url::filterBadProtocol($string); + return UrlHelper::filterBadProtocol($string); } /** @@ -1140,7 +1140,7 @@ function url($path = NULL, array $options = array()) { * Boolean TRUE or FALSE, where TRUE indicates an external path. */ function url_is_external($path) { - return Url::isExternal($path); + return UrlHelper::isExternal($path); } /** @@ -3082,7 +3082,7 @@ function _drupal_bootstrap_code() { // of allowed protocols for these cases. $allowed_protocols = array('http', 'https'); } - Url::setAllowedProtocols($allowed_protocols); + UrlHelper::setAllowedProtocols($allowed_protocols); } /** diff --git a/core/includes/form.inc b/core/includes/form.inc index 5d4a943..e41e360 100644 --- a/core/includes/form.inc +++ b/core/includes/form.inc @@ -8,7 +8,7 @@ use Drupal\Component\Utility\NestedArray; use Drupal\Component\Utility\Number; use Drupal\Component\Utility\String; -use Drupal\Component\Utility\Url; +use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Database\Database; use Drupal\Core\Language\Language; use Drupal\Core\Template\Attribute; @@ -2565,7 +2565,7 @@ function form_pre_render_color($element) { function theme_form($variables) { $element = $variables['element']; if (isset($element['#action'])) { - $element['#attributes']['action'] = Url::stripDangerousProtocols($element['#action']); + $element['#attributes']['action'] = UrlHelper::stripDangerousProtocols($element['#action']); } element_set_attributes($element, array('method', 'id')); if (empty($element['#attributes']['accept-charset'])) { diff --git a/core/includes/menu.inc b/core/includes/menu.inc index bbf5c43..02f40b7 100644 --- a/core/includes/menu.inc +++ b/core/includes/menu.inc @@ -16,6 +16,7 @@ use Symfony\Cmf\Component\Routing\RouteObjectInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Component\Routing\Exception\ResourceNotFoundException; use Symfony\Component\Routing\Route; /** @@ -922,7 +923,6 @@ function _menu_link_translate(&$item) { * @return bool * TRUE if the user has access or FALSE if the user should be presented * with access denied. - * */ function menu_item_route_access(Route $route, $href, &$map, Request $request = NULL) { if (!isset($request)) { @@ -937,6 +937,9 @@ function menu_item_route_access(Route $route, $href, &$map, Request $request = N catch (NotFoundHttpException $e) { return FALSE; } + catch (ResourceNotFoundException $e) { + return FALSE; + } // Populate the map with any matching values from the request. $path_bits = explode('/', trim($route->getPath(), '/')); diff --git a/core/includes/pager.inc b/core/includes/pager.inc index 9874689..caf1044 100644 --- a/core/includes/pager.inc +++ b/core/includes/pager.inc @@ -6,7 +6,7 @@ */ use Drupal\Core\Template\Attribute; -use Drupal\Component\Utility\Url; +use Drupal\Component\Utility\UrlHelper; /** * Returns the current page being requested for display within a pager. @@ -138,7 +138,7 @@ function pager_default_initialize($total, $limit, $element = 0) { function pager_get_query_parameters() { $query = &drupal_static(__FUNCTION__); if (!isset($query)) { - $query = Url::filterQueryParameters(\Drupal::request()->query->all(), array('page')); + $query = UrlHelper::filterQueryParameters(\Drupal::request()->query->all(), array('page')); } return $query; } diff --git a/core/includes/tablesort.inc b/core/includes/tablesort.inc index 1f6962b..e342e3e 100644 --- a/core/includes/tablesort.inc +++ b/core/includes/tablesort.inc @@ -3,7 +3,7 @@ use Drupal\Core\Database\Connection; use Drupal\Core\Database\Query\SelectExtender; use Drupal\Core\Database\Query\SelectInterface; -use Drupal\Component\Utility\Url; +use Drupal\Component\Utility\UrlHelper; /** * @file @@ -101,7 +101,7 @@ function tablesort_cell($cell, $header, $ts, $i) { * page request except for those pertaining to table sorting. */ function tablesort_get_query_parameters() { - return Url::filterQueryParameters(\Drupal::request()->query->all(), array('sort', 'order')); + return UrlHelper::filterQueryParameters(\Drupal::request()->query->all(), array('sort', 'order')); } /** diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 96a0466..529ce90 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -9,7 +9,7 @@ */ use Drupal\Component\Utility\String; -use Drupal\Component\Utility\Url; +use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Config\Config; use Drupal\Core\Language\Language; use Drupal\Core\Extension\ExtensionNameLengthException; @@ -2117,7 +2117,7 @@ function template_preprocess_html(&$variables) { $type = theme_get_setting('favicon.mimetype'); $build['#attached']['drupal_add_html_head_link'][][] = array( 'rel' => 'shortcut icon', - 'href' => Url::stripDangerousProtocols($favicon), + 'href' => UrlHelper::stripDangerousProtocols($favicon), 'type' => $type, ); drupal_render($build); @@ -2410,7 +2410,7 @@ function template_preprocess_maintenance_page(&$variables) { $type = theme_get_setting('favicon.mimetype'); $build['#attached']['drupal_add_html_head_link'][][] = array( 'rel' => 'shortcut icon', - 'href' => Url::stripDangerousProtocols($favicon), + 'href' => UrlHelper::stripDangerousProtocols($favicon), 'type' => $type, ); drupal_render($build); diff --git a/core/lib/Drupal.php b/core/lib/Drupal.php index 0ec88d7..f98d607 100644 --- a/core/lib/Drupal.php +++ b/core/lib/Drupal.php @@ -5,6 +5,7 @@ * Contains Drupal. */ +use Drupal\Core\Url; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -517,7 +518,13 @@ public static function linkGenerator() { * @see \Drupal\Core\Utility\LinkGeneratorInterface::generate() */ public static function l($text, $route_name, array $parameters = array(), array $options = array()) { - return static::$container->get('link_generator')->generate($text, $route_name, $parameters, $options); + $link_generator = static::linkGenerator(); + if ($route_name instanceof Url) { + return $link_generator->generateFromUrl($text, $route_name); + } + else { + return $link_generator->generate($text, $route_name, $parameters, $options); + } } /** diff --git a/core/lib/Drupal/Component/Utility/Url.php b/core/lib/Drupal/Component/Utility/UrlHelper.php similarity index 98% rename from core/lib/Drupal/Component/Utility/Url.php rename to core/lib/Drupal/Component/Utility/UrlHelper.php index c7eff3e..bf956c9 100644 --- a/core/lib/Drupal/Component/Utility/Url.php +++ b/core/lib/Drupal/Component/Utility/UrlHelper.php @@ -2,7 +2,7 @@ /** * @file - * Contains \Drupal\Component\Utility\Url. + * Contains \Drupal\Component\Utility\UrlHelper. */ namespace Drupal\Component\Utility; @@ -10,7 +10,7 @@ /** * Helper class URL based methods. */ -class Url { +class UrlHelper { /** * The list of allowed protocols. @@ -119,7 +119,7 @@ public static function filterQueryParameters(array $query, array $exclude = arra * The returned array contains a 'path' that may be passed separately to url(). * For example: * @code - * $options = Url::parse(\Drupal::request()->query->get('destination')); + * $options = UrlHelper::parse(\Drupal::request()->query->get('destination')); * $my_url = url($options['path'], $options); * $my_link = l('Example link', $options['path'], $options); * @endcode diff --git a/core/lib/Drupal/Component/Utility/Xss.php b/core/lib/Drupal/Component/Utility/Xss.php index 0daab37..2485f6c 100644 --- a/core/lib/Drupal/Component/Utility/Xss.php +++ b/core/lib/Drupal/Component/Utility/Xss.php @@ -226,7 +226,7 @@ protected static function attributes($attributes) { case 2: // Attribute value, a URL after href= for instance. if (preg_match('/^"([^"]*)"(\s+|$)/', $attributes, $match)) { - $thisval = Url::filterBadProtocol($match[1]); + $thisval = UrlHelper::filterBadProtocol($match[1]); if (!$skip) { $attributes_array[] = "$attribute_name=\"$thisval\""; @@ -238,7 +238,7 @@ protected static function attributes($attributes) { } if (preg_match("/^'([^']*)'(\s+|$)/", $attributes, $match)) { - $thisval = Url::filterBadProtocol($match[1]); + $thisval = UrlHelper::filterBadProtocol($match[1]); if (!$skip) { $attributes_array[] = "$attribute_name='$thisval'"; @@ -249,7 +249,7 @@ protected static function attributes($attributes) { } if (preg_match("%^([^\s\"']+)(\s+|$)%", $attributes, $match)) { - $thisval = Url::filterBadProtocol($match[1]); + $thisval = UrlHelper::filterBadProtocol($match[1]); if (!$skip) { $attributes_array[] = "$attribute_name=\"$thisval\""; diff --git a/core/lib/Drupal/Core/Form/ConfirmFormHelper.php b/core/lib/Drupal/Core/Form/ConfirmFormHelper.php index f2b4f25..0475d5a 100644 --- a/core/lib/Drupal/Core/Form/ConfirmFormHelper.php +++ b/core/lib/Drupal/Core/Form/ConfirmFormHelper.php @@ -8,7 +8,7 @@ namespace Drupal\Core\Form; use Drupal\Component\Utility\String; -use Drupal\Component\Utility\Url; +use Drupal\Component\Utility\UrlHelper; use Symfony\Component\HttpFoundation\Request; /** @@ -36,7 +36,7 @@ public static function buildCancelLink(ConfirmFormInterface $form, Request $requ $query = $request->query; // If a destination is specified, that serves as the cancel link. if ($query->has('destination')) { - $options = Url::parse($query->get('destination')); + $options = UrlHelper::parse($query->get('destination')); $link = array( '#href' => $options['path'], '#options' => $options, diff --git a/core/lib/Drupal/Core/Form/FormBuilder.php b/core/lib/Drupal/Core/Form/FormBuilder.php index 43d15a6..821ed61 100644 --- a/core/lib/Drupal/Core/Form/FormBuilder.php +++ b/core/lib/Drupal/Core/Form/FormBuilder.php @@ -10,7 +10,7 @@ use Drupal\Component\Utility\Crypt; use Drupal\Component\Utility\NestedArray; use Drupal\Component\Utility\Unicode; -use Drupal\Component\Utility\Url; +use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Access\CsrfTokenGenerator; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\HttpKernel; @@ -18,6 +18,7 @@ use Drupal\Core\Render\Element; use Drupal\Core\Routing\UrlGeneratorInterface; use Drupal\Core\StringTranslation\TranslationInterface; +use Drupal\Core\Url; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; @@ -847,7 +848,7 @@ public function validateForm($form_id, &$form, &$form_state) { if (isset($form['#token'])) { if (!$this->csrfToken->validate($form_state['values']['form_token'], $form['#token'])) { $path = $this->request->attributes->get('_system_path'); - $query = Url::filterQueryParameters($this->request->query->all()); + $query = UrlHelper::filterQueryParameters($this->request->query->all()); $url = $this->urlGenerator->generateFromPath($path, array('query' => $query)); // Setting this error will cause the form to fail validation. @@ -933,13 +934,17 @@ public function redirectForm($form_state) { // Check for a route-based redirection. if (isset($form_state['redirect_route'])) { - $form_state['redirect_route'] += array( - 'route_parameters' => array(), - 'options' => array(), - ); - $form_state['redirect_route']['options']['absolute'] = TRUE; - $url = $this->urlGenerator->generateFromRoute($form_state['redirect_route']['route_name'], $form_state['redirect_route']['route_parameters'], $form_state['redirect_route']['options']); - return new RedirectResponse($url); + // @todo Remove once all redirects are converted to Url. + if (!($form_state['redirect_route'] instanceof Url)) { + $form_state['redirect_route'] += array( + 'route_parameters' => array(), + 'options' => array(), + ); + $form_state['redirect_route'] = new Url($form_state['redirect_route']['route_name'], $form_state['redirect_route']['route_parameters'], $form_state['redirect_route']['options']); + } + + $form_state['redirect_route']->setAbsolute(); + return new RedirectResponse($form_state['redirect_route']->toString()); } // Only invoke a redirection if redirect value was not set to FALSE. @@ -1318,7 +1323,7 @@ public function doBuildForm($form_id, &$element, &$form_state) { // Special handling if we're on the top level form element. if (isset($element['#type']) && $element['#type'] == 'form') { if (!empty($element['#https']) && settings()->get('mixed_mode_sessions', FALSE) && - !Url::isExternal($element['#action'])) { + !UrlHelper::isExternal($element['#action'])) { global $base_root; // Not an external URL so ensure that it is secure. diff --git a/core/lib/Drupal/Core/Routing/NullGenerator.php b/core/lib/Drupal/Core/Routing/NullGenerator.php index 1430f1f..a677a60 100644 --- a/core/lib/Drupal/Core/Routing/NullGenerator.php +++ b/core/lib/Drupal/Core/Routing/NullGenerator.php @@ -12,7 +12,7 @@ use Symfony\Component\Routing\Route; /** - * No-op implementation of a Url Generator, needed for backward compatibility. + * No-op implementation of a UrlGenerator, needed for backward compatibility. */ class NullGenerator extends UrlGenerator { diff --git a/core/lib/Drupal/Core/Routing/UrlGenerator.php b/core/lib/Drupal/Core/Routing/UrlGenerator.php index 1bb4b53..9496e19 100644 --- a/core/lib/Drupal/Core/Routing/UrlGenerator.php +++ b/core/lib/Drupal/Core/Routing/UrlGenerator.php @@ -16,7 +16,7 @@ use Symfony\Cmf\Component\Routing\ProviderBasedGenerator; use Drupal\Component\Utility\Settings; -use Drupal\Component\Utility\Url; +use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Config\ConfigFactory; use Drupal\Core\PathProcessor\OutboundPathProcessorInterface; use Drupal\Core\RouteProcessor\OutboundRouteProcessorInterface; @@ -92,7 +92,7 @@ public function __construct(RouteProviderInterface $provider, OutboundPathProces $this->routeProcessor = $route_processor; $this->mixedModeSessions = $settings->get('mixed_mode_sessions', FALSE); $allowed_protocols = $config->get('system.filter')->get('protocols') ?: array('http', 'https'); - Url::setAllowedProtocols($allowed_protocols); + UrlHelper::setAllowedProtocols($allowed_protocols); } /** @@ -237,12 +237,12 @@ public function generateFromPath($path = NULL, $options = array()) { if (!isset($options['external'])) { // Return an external link if $path contains an allowed absolute URL. Only - // call the slow \Drupal\Component\Utility\Url::stripDangerousProtocols() + // call the slow \Drupal\Component\Utility\UrlHelper::stripDangerousProtocols() // if $path contains a ':' before any / ? or #. Note: we could use // url_is_external($path) here, but that would require another function // call, and performance inside url() is critical. $colonpos = strpos($path, ':'); - $options['external'] = ($colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && Url::stripDangerousProtocols($path) == $path); + $options['external'] = ($colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && UrlHelper::stripDangerousProtocols($path) == $path); } if (isset($options['fragment']) && $options['fragment'] !== '') { @@ -260,7 +260,7 @@ public function generateFromPath($path = NULL, $options = array()) { } // Append the query. if ($options['query']) { - $path .= (strpos($path, '?') !== FALSE ? '&' : '?') . Url::buildQuery($options['query']); + $path .= (strpos($path, '?') !== FALSE ? '&' : '?') . UrlHelper::buildQuery($options['query']); } if (isset($options['https']) && $this->mixedModeSessions) { if ($options['https'] === TRUE) { @@ -303,7 +303,7 @@ public function generateFromPath($path = NULL, $options = array()) { $prefix = empty($path) ? rtrim($options['prefix'], '/') : $options['prefix']; $path = str_replace('%2F', '/', rawurlencode($prefix . $path)); - $query = $options['query'] ? ('?' . Url::buildQuery($options['query'])) : ''; + $query = $options['query'] ? ('?' . UrlHelper::buildQuery($options['query'])) : ''; return $base . $options['script'] . $path . $query . $options['fragment']; } diff --git a/core/lib/Drupal/Core/Routing/UrlMatcher.php b/core/lib/Drupal/Core/Routing/UrlMatcher.php index 9e973d4..c347b51 100644 --- a/core/lib/Drupal/Core/Routing/UrlMatcher.php +++ b/core/lib/Drupal/Core/Routing/UrlMatcher.php @@ -30,36 +30,16 @@ public function finalMatch(RouteCollection $collection, Request $request) { $context = new RequestContext(); $context->fromRequest($request); $this->setContext($context); - return $this->match('/' . $request->attributes->get('_system_path')); - } - - /** - * Returns the route_name and route parameters matching a system path. - * - * @todo Find a better place for this method in - * https://drupal.org/node/2153891. - * - * @param string $link_path - * The link path to find a route name for. - * - * @return array - * Returns an array with both the route name and parameters, or an empty - * array if no route was matched. - */ - public function findRouteNameParameters($link_path) { - // Look up the route_name used for the given path. - $request = Request::create('/' . $link_path); - $request->attributes->set('_system_path', $link_path); - try { - $result = \Drupal::service('router')->matchRequest($request); - $return = array(); - $return[] = isset($result['_route']) ? $result['_route'] : ''; - $return[] = $result['_raw_variables']->all(); - return $return; + if ($request->attributes->has('_system_path')) { + // _system_path never has leading or trailing slashes. + $path = '/' . $request->attributes->get('_system_path'); } - catch (\Exception $e) { - return array(); + else { + // getPathInfo() always has leading slash, and might or might not have a + // trailing slash. + $path = rtrim($request->getPathInfo(), '/'); } + return $this->match($path); } } diff --git a/core/lib/Drupal/Core/Url.php b/core/lib/Drupal/Core/Url.php new file mode 100644 index 0000000..7e3886d --- /dev/null +++ b/core/lib/Drupal/Core/Url.php @@ -0,0 +1,346 @@ +routeName = $route_name; + $this->routeParameters = $route_parameters; + $this->options = $options; + } + + /** + * Returns the Url object matching a system path. + * + * @param string $path + * A system path (e.g. 'node/1'). + * + * @return static + * An Url object. + * + * @throws \Symfony\Component\Routing\Exception\ResourceNotFoundException + */ + public static function createFromPath($path) { + if (UrlHelper::isExternal($path)) { + $url = new static($path); + $url->setExternal(); + return $url; + } + // Look up the route name and parameters used for the given path. + $result = \Drupal::service('router')->match('/' . $path); + return new static($result['_route'], $result['_raw_variables']->all()); + } + + /** + * Returns the Url object matching a request + * + * @param \Symfony\Component\HttpFoundation\Request $request + * A request object. + * + * @return static + * An Url object. + */ + public static function createFromRequest(Request $request) { + if ($route_name = $request->attributes->get(RouteObjectInterface::ROUTE_NAME)) { + $route_parameters = $request->attributes->get('_raw_variables')->all(); + return new static($route_name, $route_parameters); + } + elseif (($path = $request->attributes->get('_system_path')) && UrlHelper::isExternal($path)) { + $url = new static($path); + $url->setExternal(); + return $url; + } + throw new \Exception('asdf'); + } + + /** + * Sets this Url to be external. + * + * @return $this + */ + protected function setExternal() { + $this->external = TRUE; + // What was passed in as the route name is actually the path. + $this->path = $this->routeName; + $this->routeName = NULL; + return $this; + } + + /** + * Indicates if this Url is external. + * + * @return bool + */ + public function isExternal() { + return $this->external; + } + + /** + * Returns the route name. + * + * @return string + */ + public function getRouteName() { + if ($this->isExternal()) { + throw new \Exception('External URLs do not have route names.'); + } + return $this->routeName; + } + + /** + * Returns the route parameters. + * + * @return array + */ + public function getRouteParameters() { + if ($this->isExternal()) { + throw new \Exception('External URLs do not have route parameters.'); + } + return $this->routeParameters; + } + + /** + * Sets the route parameters. + * + * @param array $parameters + * The array of parameters. + * + * @return $this + */ + public function setRouteParameters($parameters) { + if ($this->isExternal()) { + throw new \Exception('External URLs do not have route parameters.'); + } + $this->routeParameters = $parameters; + return $this; + } + + /** + * Sets a specific route parameter. + * + * @param string $key + * The key of the route parameter. + * @param mixed $value + * The route parameter. + * + * @return $this + */ + public function setRouteParameter($key, $value) { + if ($this->isExternal()) { + throw new \Exception('External URLs do not have route parameters.'); + } + $this->routeParameters[$key] = $value; + return $this; + } + + /** + * Returns the URL options. + * + * @return array + */ + public function getOptions() { + return $this->options; + } + + /** + * Sets the URL options. + * + * @param array $options + * The array of options. + * + * @return $this + */ + public function setOptions($options) { + $this->options = $options; + return $this; + } + + /** + * Sets a specific option. + * + * @param string $name + * The name of the option. + * @param mixed $value + * The option value. + * + * @return $this + */ + public function setOption($name, $value) { + $this->options[$name] = $value; + return $this; + } + + /** + * Sets the absolute value for this Url. + * + * @param bool $absolute + * (optional) Whether to make this Url absolute or not. Defaults to TRUE. + * + * @return $this + */ + public function setAbsolute($absolute = TRUE) { + $this->options['absolute'] = $absolute; + return $this; + } + + /** + * Generates the path for this Url object. + */ + public function toString() { + if ($this->isExternal()) { + return $this->urlGenerator()->generateFromPath($this->path, $this->getOptions()); + } + + return $this->urlGenerator()->generateFromRoute($this->getRouteName(), $this->getRouteParameters(), $this->getOptions()); + } + + /** + * Returns all the information about the route. + * + * @return array + * An associative array containing all the properties of the route. + */ + public function toArray() { + if ($this->isExternal()) { + throw new \Exception('External URLs do not have route metadata.'); + } + return array( + 'route_name' => $this->getRouteName(), + 'route_parameters' => $this->getRouteParameters(), + 'options' => $this->getOptions(), + ); + } + + /** + * Returns the internal path for this route. + * + * This path will not include any prefixes, fragments, or query strings. + * + * @return string + * The internal path for this route. + */ + public function getInternalPath() { + if ($this->isExternal()) { + throw new \Exception('External URLs do not have internal representations.'); + } + return $this->urlGenerator()->getPathFromRoute($this->getRouteName(), $this->getRouteParameters()); + } + + /** + * {@inheritdoc} + */ + public function __sleep() { + unset($this->urlGenerator); + return array_keys(get_object_vars($this)); + } + + /** + * Gets the URL generator. + * + * @return \Drupal\Core\Routing\UrlGeneratorInterface + * The URL generator. + */ + protected function urlGenerator() { + if (!$this->urlGenerator) { + $this->urlGenerator = \Drupal::urlGenerator(); + } + return $this->urlGenerator; + } + + /** + * Sets the URL generator. + * + * @param \Drupal\Core\Routing\UrlGeneratorInterface + * The URL generator. + * + * @return $this + */ + public function setUrlGenerator(UrlGeneratorInterface $url_generator) { + $this->urlGenerator = $url_generator; + return $this; + } + +} diff --git a/core/lib/Drupal/Core/Utility/LinkGenerator.php b/core/lib/Drupal/Core/Utility/LinkGenerator.php index 2874da4..5c06ab8 100644 --- a/core/lib/Drupal/Core/Utility/LinkGenerator.php +++ b/core/lib/Drupal/Core/Utility/LinkGenerator.php @@ -15,7 +15,7 @@ use Drupal\Core\Path\AliasManagerInterface; use Drupal\Core\Template\Attribute; use Drupal\Core\Routing\UrlGeneratorInterface; -use Drupal\Core\Session\AccountInterface; +use Drupal\Core\Url; use Symfony\Cmf\Component\Routing\RouteObjectInterface; use Symfony\Component\HttpFoundation\Request; @@ -99,80 +99,88 @@ public function getActive() { /** * {@inheritdoc} - * - * For anonymous users, the "active" class will be calculated on the server, - * because most sites serve each anonymous user the same cached page anyway. - * For authenticated users, the "active" class will be calculated on the - * client (through JavaScript), only data- attributes are added to links to - * prevent breaking the render cache. The JavaScript is added in - * system_page_build(). - * - * @see system_page_build() */ - public function generate($text, $route_name, array $parameters = array(), array $options = array()) { - // Start building a structured representation of our link to be altered later. - $variables = array( - // @todo Inject the service when drupal_render() is converted to one. - 'text' => is_array($text) ? drupal_render($text) : $text, - 'route_name' => $route_name, - 'parameters' => $parameters, - 'options' => $options, - ); + public function generateFromUrl($text, Url $url) { + // @todo Inject the service when drupal_render() is converted to one. + $text = is_array($text) ? drupal_render($text) : $text; // Merge in default options. - $variables['options'] += array( + $options = $url->getOptions(); + $options += array( 'attributes' => array(), 'query' => array(), 'html' => FALSE, 'language' => NULL, 'set_active_class' => FALSE, + 'absolute' => FALSE, ); // Add a hreflang attribute if we know the language of this link's url and // hreflang has not already been set. - if (!empty($variables['options']['language']) && !isset($variables['options']['attributes']['hreflang'])) { - $variables['options']['attributes']['hreflang'] = $variables['options']['language']->id; + if (!empty($options['language']) && !isset($options['attributes']['hreflang'])) { + $options['attributes']['hreflang'] = $options['language']->id; } // Set the "active" class if the 'set_active_class' option is not empty. - if (!empty($variables['options']['set_active_class'])) { + if (!empty($options['set_active_class'])) { // Add a "data-drupal-link-query" attribute to let the // drupal.active-link library know the query in a standardized manner. - if (!empty($variables['options']['query'])) { - $query = $variables['options']['query']; + if (!empty($options['query'])) { + $query = $options['query']; ksort($query); - $variables['options']['attributes']['data-drupal-link-query'] = Json::encode($query); + $options['attributes']['data-drupal-link-query'] = Json::encode($query); } // Add a "data-drupal-link-system-path" attribute to let the // drupal.active-link library know the path in a standardized manner. - if (!isset($variables['options']['attributes']['data-drupal-link-system-path'])) { - $path = $this->urlGenerator->getPathFromRoute($route_name, $parameters); - $variables['options']['attributes']['data-drupal-link-system-path'] = $this->aliasManager->getSystemPath($path); + if (!isset($options['attributes']['data-drupal-link-system-path'])) { + $options['attributes']['data-drupal-link-system-path'] = $this->aliasManager->getSystemPath($url->getInternalPath()); } } // Remove all HTML and PHP tags from a tooltip, calling expensive strip_tags() // only when a quick strpos() gives suspicion tags are present. - if (isset($variables['options']['attributes']['title']) && strpos($variables['options']['attributes']['title'], '<') !== FALSE) { - $variables['options']['attributes']['title'] = strip_tags($variables['options']['attributes']['title']); + if (isset($options['attributes']['title']) && strpos($options['attributes']['title'], '<') !== FALSE) { + $options['attributes']['title'] = strip_tags($options['attributes']['title']); } + // Update the options before allowing altering. + $url->setOptions($options); + // Allow other modules to modify the structure of the link. - $this->moduleHandler->alter('link', $variables); + $this->moduleHandler->alter('link', $text, $url); // Move attributes out of options. generateFromRoute(() doesn't need them. - $attributes = new Attribute($variables['options']['attributes']); - unset($variables['options']['attributes']); + $attributes = new Attribute($options['attributes']); + unset($options['attributes']); + $url->setOptions($options); // The result of the url generator is a plain-text URL. Because we are using // it here in an HTML argument context, we need to encode it properly. - $url = String::checkPlain($this->urlGenerator->generateFromRoute($variables['route_name'], $variables['parameters'], $variables['options'])); + $url = String::checkPlain($url->toString()); // Sanitize the link text if necessary. - $text = $variables['options']['html'] ? $variables['text'] : String::checkPlain($variables['text']); + $text = $options['html'] ? $text : String::checkPlain($text); return '' . $text . ''; } + /** + * {@inheritdoc} + * + * For anonymous users, the "active" class will be calculated on the server, + * because most sites serve each anonymous user the same cached page anyway. + * For authenticated users, the "active" class will be calculated on the + * client (through JavaScript), only data- attributes are added to links to + * prevent breaking the render cache. The JavaScript is added in + * system_page_build(). + * + * @see system_page_build() + */ + public function generate($text, $route_name, array $parameters = array(), array $options = array()) { + $url = new Url($route_name, $parameters, $options); + $url->setUrlGenerator($this->urlGenerator); + return $this->generateFromUrl($text, $url); + } + } diff --git a/core/lib/Drupal/Core/Utility/LinkGeneratorInterface.php b/core/lib/Drupal/Core/Utility/LinkGeneratorInterface.php index 02e31af..851100d 100644 --- a/core/lib/Drupal/Core/Utility/LinkGeneratorInterface.php +++ b/core/lib/Drupal/Core/Utility/LinkGeneratorInterface.php @@ -7,6 +7,8 @@ namespace Drupal\Core\Utility; +use Drupal\Core\Url; + /** * Defines an interface for generating links from route names and parameters. */ @@ -78,6 +80,19 @@ public function generate($text, $route_name, array $parameters = array(), array $options = array()); /** + * Renders a link to a URL. + * + * @param string $text + * The link text for the anchor tag as a translated string. + * @param \Drupal\Core\Url $url + * The URL object used for the link. + * + * @return string + * An HTML string containing a link to the given route and parameters. + */ + public function generateFromUrl($text, Url $url); + + /** * Returns information for the currently active route. * * @return array diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Form/OpmlFeedAdd.php b/core/modules/aggregator/lib/Drupal/aggregator/Form/OpmlFeedAdd.php index b370063..f26b395 100644 --- a/core/modules/aggregator/lib/Drupal/aggregator/Form/OpmlFeedAdd.php +++ b/core/modules/aggregator/lib/Drupal/aggregator/Form/OpmlFeedAdd.php @@ -8,7 +8,7 @@ namespace Drupal\aggregator\Form; use Drupal\aggregator\FeedStorageControllerInterface; -use Drupal\Component\Utility\Url; +use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Entity\Query\QueryFactory; use Drupal\Core\Form\FormBase; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -158,7 +158,7 @@ public function submitForm(array &$form, array &$form_state) { // @todo Move this functionality to a processor. foreach ($feeds as $feed) { // Ensure URL is valid. - if (!Url::isValid($feed['url'], TRUE)) { + if (!UrlHelper::isValid($feed['url'], TRUE)) { drupal_set_message($this->t('The URL %url is invalid.', array('%url' => $feed['url'])), 'warning'); continue; } diff --git a/core/modules/contextual/contextual.module b/core/modules/contextual/contextual.module index 3fd2cb9..77e240f 100644 --- a/core/modules/contextual/contextual.module +++ b/core/modules/contextual/contextual.module @@ -5,7 +5,7 @@ * Adds contextual links to perform actions related to elements on a page. */ -use Drupal\Component\Utility\Url; +use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Template\Attribute; /** @@ -329,8 +329,8 @@ function contextual_contextual_links_view_alter(&$element, $items) { function _contextual_links_to_id($contextual_links) { $ids = array(); foreach ($contextual_links as $group => $args) { - $route_parameters = Url::buildQuery($args['route_parameters']); - $metadata = Url::buildQuery((isset($args['metadata'])) ? $args['metadata'] : array()); + $route_parameters = UrlHelper::buildQuery($args['route_parameters']); + $metadata = UrlHelper::buildQuery((isset($args['metadata'])) ? $args['metadata'] : array()); $ids[] = "{$group}:{$route_parameters}:{$metadata}"; } return implode('|', $ids); diff --git a/core/modules/field_ui/lib/Drupal/field_ui/FieldUI.php b/core/modules/field_ui/lib/Drupal/field_ui/FieldUI.php index c0ed669..d6d2a2d 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/FieldUI.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/FieldUI.php @@ -7,7 +7,7 @@ namespace Drupal\field_ui; -use Drupal\Component\Utility\Url; +use Drupal\Component\Utility\UrlHelper; /** * Static service container wrapper for Field UI. @@ -59,7 +59,7 @@ public static function getNextDestination(array $destinations) { $next_destination['options']['query']['destinations'] = $destinations; } else { - $options = Url::parse($next_destination); + $options = UrlHelper::parse($next_destination); if ($destinations) { $options['query']['destinations'] = $destinations; } diff --git a/core/modules/image/lib/Drupal/image/Entity/ImageStyle.php b/core/modules/image/lib/Drupal/image/Entity/ImageStyle.php index 57869d4..286f1e8 100644 --- a/core/modules/image/lib/Drupal/image/Entity/ImageStyle.php +++ b/core/modules/image/lib/Drupal/image/Entity/ImageStyle.php @@ -13,7 +13,7 @@ use Drupal\image\ImageEffectInterface; use Drupal\image\ImageStyleInterface; use Drupal\Component\Utility\Crypt; -use Drupal\Component\Utility\Url; +use Drupal\Component\Utility\UrlHelper; use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; /** @@ -225,7 +225,7 @@ public function buildUrl($path, $clean_urls = NULL) { $file_url = file_create_url($uri); // Append the query string with the token, if necessary. if ($token_query) { - $file_url .= (strpos($file_url, '?') !== FALSE ? '&' : '?') . Url::buildQuery($token_query); + $file_url .= (strpos($file_url, '?') !== FALSE ? '&' : '?') . UrlHelper::buildQuery($token_query); } return $file_url; diff --git a/core/modules/link/lib/Drupal/link/Plugin/Field/FieldFormatter/LinkFormatter.php b/core/modules/link/lib/Drupal/link/Plugin/Field/FieldFormatter/LinkFormatter.php index ef8db96..ef86eaf 100644 --- a/core/modules/link/lib/Drupal/link/Plugin/Field/FieldFormatter/LinkFormatter.php +++ b/core/modules/link/lib/Drupal/link/Plugin/Field/FieldFormatter/LinkFormatter.php @@ -7,7 +7,7 @@ namespace Drupal\link\Plugin\Field\FieldFormatter; -use Drupal\Component\Utility\Url; +use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Field\FieldItemInterface; use Drupal\Core\Field\FormatterBase; @@ -169,7 +169,7 @@ protected function buildLink(FieldItemInterface $item) { $settings = $this->getSettings(); // Split out the link into the parts required for url(): path and options. - $parsed_url = Url::parse($item->url); + $parsed_url = UrlHelper::parse($item->url); $result = array( 'path' => $parsed_url['path'], 'options' => array( diff --git a/core/modules/menu_link/lib/Drupal/menu_link/Entity/MenuLink.php b/core/modules/menu_link/lib/Drupal/menu_link/Entity/MenuLink.php index 6d70014..d5d358b 100644 --- a/core/modules/menu_link/lib/Drupal/menu_link/Entity/MenuLink.php +++ b/core/modules/menu_link/lib/Drupal/menu_link/Entity/MenuLink.php @@ -9,7 +9,9 @@ use Drupal\Core\Entity\Entity; use Drupal\Core\Entity\EntityStorageControllerInterface; +use Drupal\Core\Url; use Drupal\menu_link\MenuLinkInterface; +use Symfony\Component\Routing\Exception\ResourceNotFoundException; use Symfony\Component\Routing\Route; /** @@ -461,6 +463,10 @@ public function preSave(EntityStorageControllerInterface $storage_controller) { // This is the easiest way to handle the unique internal path '', // since a path marked as external does not need to match a route. $this->external = (url_is_external($this->link_path) || $this->link_path == '') ? 1 : 0; + if ($this->link_path == '') { + $this->route_name = ''; + $this->route_parameters = array(); + } // Try to find a parent link. If found, assign it and derive its menu. $parent = $this->findParent($storage_controller); @@ -505,13 +511,20 @@ public function preSave(EntityStorageControllerInterface $storage_controller) { // Find the route_name. if (!isset($this->route_name)) { - if (!$this->external && $result = \Drupal::service('router.matcher.final_matcher')->findRouteNameParameters($this->link_path)) { - list($this->route_name, $this->route_parameters) = $result; - } - else { - $this->route_name = ''; - $this->route_parameters = array(); + $route_name = ''; + $route_parameters = array(); + if (!$this->external) { + try { + $url = Url::createFromPath($this->link_path); + $route_name = $url->getRouteName(); + $route_parameters = $url->getRouteParameters(); + } + catch (ResourceNotFoundException $e) { + } } + + $this->route_name = $route_name; + $this->route_parameters = $route_parameters; } elseif (empty($this->link_path)) { $this->link_path = \Drupal::urlGenerator()->getPathFromRoute($this->route_name, $this->route_parameters); diff --git a/core/modules/shortcut/lib/Drupal/shortcut/Entity/Shortcut.php b/core/modules/shortcut/lib/Drupal/shortcut/Entity/Shortcut.php index 59f8287..6784bd0 100644 --- a/core/modules/shortcut/lib/Drupal/shortcut/Entity/Shortcut.php +++ b/core/modules/shortcut/lib/Drupal/shortcut/Entity/Shortcut.php @@ -11,7 +11,9 @@ use Drupal\Core\Entity\EntityStorageControllerInterface; use Drupal\Core\Field\FieldDefinition; use Drupal\Core\Routing\UrlMatcher; +use Drupal\Core\Url; use Drupal\shortcut\ShortcutInterface; +use Symfony\Component\Routing\Exception\ResourceNotFoundException; /** * Defines the shortcut entity class. @@ -124,9 +126,12 @@ public static function preCreate(EntityStorageControllerInterface $storage_contr public function preSave(EntityStorageControllerInterface $storage_controller) { parent::preSave($storage_controller); - if ($route_info = \Drupal::service('router.matcher.final_matcher')->findRouteNameParameters($this->path->value)) { - $this->setRouteName($route_info[0]); - $this->setRouteParams($route_info[1]); + try { + $url = Url::createFromPath($this->path->value); + $this->setRouteName($url->getRouteName()); + $this->setRouteParams($url->getRouteParameters()); + } + catch (ResourceNotFoundException $e) { } } diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module index a988cf4..381ec2b 100644 --- a/core/modules/shortcut/shortcut.module +++ b/core/modules/shortcut/shortcut.module @@ -5,7 +5,7 @@ * Allows users to manage customizable lists of shortcut links. */ -use Drupal\Core\Routing\UrlMatcher; +use Drupal\Core\Url; use Drupal\shortcut\ShortcutSetInterface; use Symfony\Component\HttpFoundation\Request; @@ -389,7 +389,7 @@ function shortcut_preprocess_page(&$variables) { // pages). if (shortcut_set_edit_access() && ($item = menu_get_item()) && $item['access']) { $link = current_path(); - if (!($route_info = \Drupal::service('router.matcher.final_matcher')->findRouteNameParameters($link))) { + if (!($url = Url::createFromPath($link))) { // Bail out early if we couldn't find a matching route. return; } @@ -405,7 +405,7 @@ function shortcut_preprocess_page(&$variables) { // Check if $link is already a shortcut and set $link_mode accordingly. $shortcuts = \Drupal::entityManager()->getStorageController('shortcut')->loadByProperties(array('shortcut_set' => $shortcut_set->id())); foreach ($shortcuts as $shortcut) { - if ($shortcut->getRouteName() == $route_info[0] && $shortcut->getRouteParams() == $route_info[1]) { + if ($shortcut->getRouteName() == $url->getRouteName() && $shortcut->getRouteParams() == $url->getRouteParameters()) { $shortcut_id = $shortcut->id(); break; } diff --git a/core/modules/system/lib/Drupal/system/Tests/Common/XssUnitTest.php b/core/modules/system/lib/Drupal/system/Tests/Common/XssUnitTest.php index bcafe30..0f47192 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Common/XssUnitTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Common/XssUnitTest.php @@ -7,7 +7,7 @@ namespace Drupal\system\Tests\Common; -use Drupal\Component\Utility\Url; +use Drupal\Component\Utility\UrlHelper; use Drupal\simpletest\DrupalUnitTestBase; /** @@ -54,12 +54,12 @@ function testT() { */ function testBadProtocolStripping() { // Ensure that check_url() strips out harmful protocols, and encodes for - // HTML. Ensure \Drupal\Component\Utility\Url::stripDangerousProtocols() can + // HTML. Ensure \Drupal\Component\Utility\UrlHelper::stripDangerousProtocols() can // be used to return a plain-text string stripped of harmful protocols. $url = 'javascript:http://www.example.com/?x=1&y=2'; $expected_plain = 'http://www.example.com/?x=1&y=2'; $expected_html = 'http://www.example.com/?x=1&y=2'; $this->assertIdentical(check_url($url), $expected_html, 'check_url() filters a URL and encodes it for HTML.'); - $this->assertIdentical(Url::stripDangerousProtocols($url), $expected_plain, '\Drupal\Component\Utility\Url::stripDangerousProtocols() filters a URL and returns plain text.'); + $this->assertIdentical(UrlHelper::stripDangerousProtocols($url), $expected_plain, '\Drupal\Component\Utility\UrlHelper::stripDangerousProtocols() filters a URL and returns plain text.'); } } diff --git a/core/modules/system/lib/Drupal/system/Tests/Routing/RouterPermissionTest.php b/core/modules/system/lib/Drupal/system/Tests/Routing/RouterPermissionTest.php index 060303a..3f3a1d8 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Routing/RouterPermissionTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Routing/RouterPermissionTest.php @@ -37,17 +37,10 @@ public function testPermissionAccess() { $path = 'router_test/test7'; $this->drupalGet($path); $this->assertResponse(403, "Access denied for a route where we don't have a permission"); - // An invalid path should throw an exception. + $map = array(); $route = \Drupal::service('router.route_provider')->getRouteByName('router_test.7'); - try { - menu_item_route_access($route, $path . 'invalid', $map); - $exception = FALSE; - } - catch (ResourceNotFoundException $e) { - $exception = TRUE; - } - $this->assertTrue($exception, 'A ResourceNotFoundException was thrown while checking access for an invalid route.'); + $this->assertFalse(menu_item_route_access($route, $path . 'invalid', $map)); $this->drupalGet('router_test/test8'); $this->assertResponse(403, 'Access denied by default if no access specified'); diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php index 6c83611..42159d6 100644 --- a/core/modules/system/system.api.php +++ b/core/modules/system/system.api.php @@ -5,6 +5,7 @@ * Hooks provided by Drupal core and the System module. */ +use Drupal\Core\Url; use Drupal\Core\Utility\UpdateException; /** @@ -3157,50 +3158,35 @@ function hook_filetransfer_info_alter(&$filetransfer_info) { /** * Alter the parameters for links. * - * @param array $variables - * An associative array of variables defining a link. The link may be either a - * "route link" using \Drupal\Core\Utility\LinkGenerator::link(), which is - * exposed as the 'link_generator' service or a link generated by l(). If the - * link is a "route link", 'route_name' will be set, otherwise 'path' will be - * set. The following keys can be altered: - * - text: The link text for the anchor tag as a translated string. - * - url_is_active: Whether or not the link points to the currently active - * URL. - * - path: If this link is being generated by l(), this system path, relative - * path, or external URL will be passed to url() to generate the href - * attribute for this link. - * - route_name: The name of the route to use to generate the link, if - * this is a "route link". - * - parameters: Any parameters needed to render the route path pattern, if - * this is a "route link". - * - options: An associative array of additional options that will be passed - * to either \Drupal\Core\Routing\UrlGenerator::generateFromPath() or - * \Drupal\Core\Routing\UrlGenerator::generateFromRoute() to generate the - * href attribute for this link, and also used when generating the link. - * Defaults to an empty array. It may contain the following elements: - * - 'query': An array of query key/value-pairs (without any URL-encoding) to - * append to the URL. - * - absolute: Whether to force the output to be an absolute link (beginning - * with http:). Useful for links that will be displayed outside the site, - * such as in an RSS feed. Defaults to FALSE. - * - language: An optional language object. May affect the rendering of - * the anchor tag, such as by adding a language prefix to the path. - * - attributes: An associative array of HTML attributes to apply to the - * anchor tag. If element 'class' is included, it must be an array; 'title' - * must be a string; other elements are more flexible, as they just need - * to work as an argument for the constructor of the class - * Drupal\Core\Template\Attribute($options['attributes']). - * - html: Whether or not HTML should be allowed as the link text. If FALSE, - * the text will be run through - * \Drupal\Component\Utility\String::checkPlain() before being output. + * @param string $text + * The link text for the anchor tag as a translated string. + * @param \Drupal\Core\Url $url + * The URL object used for the link. Url::getOptions() can contain many + * keys, but the following are guaranteed to exist: + * - query: An array of query key/value-pairs (without any URL-encoding) to + * append to the URL. + * - absolute: Whether to force the output to be an absolute link (beginning + * with http:). Useful for links that will be displayed outside the site, + * such as in an RSS feed. Defaults to FALSE. + * - language: An optional language object. May affect the rendering of the + * anchor tag, such as by adding a language prefix to the path. + * - attributes: An associative array of HTML attributes to apply to the + * anchor tag. If element 'class' is included, it must be an array; 'title' + * must be a string; other elements are more flexible, as they just need + * to work as an argument for the constructor of the class + * \Drupal\Core\Template\Attribute($options['attributes']). + * - html: Whether or not HTML should be allowed as the link text. If FALSE, + * the text will be run through + * \Drupal\Component\Utility\String::checkPlain() before being output. + * - set_active_class: Whether to set the 'active' class or not. * * @see \Drupal\Core\Routing\UrlGenerator::generateFromPath() * @see \Drupal\Core\Routing\UrlGenerator::generateFromRoute() */ -function hook_link_alter(&$variables) { +function hook_link_alter(&$text, Url $url) { // Add a warning to the end of route links to the admin section. - if (isset($variables['route_name']) && strpos($variables['route_name'], 'admin') !== FALSE) { - $variables['text'] .= ' (Warning!)'; + if (strpos($url->getRouteName(), 'admin') !== FALSE) { + $text .= ' (Warning!)'; } } diff --git a/core/modules/system/system.install b/core/modules/system/system.install index 25f75c7..6ad4f6c 100644 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -1761,7 +1761,7 @@ function system_update_8034() { * Move filter_allowed_protocols variable to config. * * This config is provided now by the system module because it is used by - * \Drupal\Component\Utility\Url::stripDangerousProtocols() and must to be + * \Drupal\Component\Utility\UrlHelper::stripDangerousProtocols() and must to be * available before the filter module be installed. * * @ingroup config_upgrade diff --git a/core/modules/views/lib/Drupal/views/Controller/ViewAjaxController.php b/core/modules/views/lib/Drupal/views/Controller/ViewAjaxController.php index 307d63f..8df3017 100644 --- a/core/modules/views/lib/Drupal/views/Controller/ViewAjaxController.php +++ b/core/modules/views/lib/Drupal/views/Controller/ViewAjaxController.php @@ -7,7 +7,7 @@ namespace Drupal\views\Controller; -use Drupal\Component\Utility\Url; +use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Ajax\ReplaceCommand; use Drupal\Core\DependencyInjection\ContainerInjectionInterface; use Drupal\Core\Entity\EntityStorageControllerInterface; @@ -115,7 +115,7 @@ public function ajaxView(Request $request) { // Overwrite the destination. // @see drupal_get_destination() $origin_destination = $path; - $query = Url::buildQuery($request->query->all()); + $query = UrlHelper::buildQuery($request->query->all()); if ($query != '') { $origin_destination .= '?' . $query; } diff --git a/core/modules/views/lib/Drupal/views/Form/ViewsForm.php b/core/modules/views/lib/Drupal/views/Form/ViewsForm.php index 3e409f7..cc01f8d 100644 --- a/core/modules/views/lib/Drupal/views/Form/ViewsForm.php +++ b/core/modules/views/lib/Drupal/views/Form/ViewsForm.php @@ -7,7 +7,7 @@ namespace Drupal\views\Form; -use Drupal\Component\Utility\Url; +use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Controller\ControllerResolverInterface; use Drupal\Core\DependencyInjection\ContainerInjectionInterface; use Drupal\Core\DependencyInjection\DependencySerialization; @@ -126,7 +126,7 @@ public function buildForm(array $form, array &$form_state, ViewExecutable $view $form = array(); $query = $this->request->query->all(); - $query = Url::filterQueryParameters($query, array(), ''); + $query = UrlHelper::filterQueryParameters($query, array(), ''); $form['#action'] = $this->urlGenerator->generateFromPath($view->getUrl(), array('query' => $query)); // Tell the preprocessor whether it should hide the header, footer, pager... diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php index 1b8c4ce..1d3e9c7 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php @@ -9,7 +9,7 @@ use Drupal\Component\Utility\String; use Drupal\Component\Utility\Unicode; -use Drupal\Component\Utility\Url; +use Drupal\Component\Utility\UrlHelper; use Drupal\Component\Utility\Xss; use Drupal\Core\Session\AccountInterface; use Drupal\views\Plugin\views\display\DisplayPluginBase; @@ -230,7 +230,7 @@ public function sanitizeValue($value, $type = NULL) { $value = Xss::filterAdmin($value); break; case 'url': - $value = String::checkPlain(Url::stripDangerousProtocols($value)); + $value = String::checkPlain(UrlHelper::stripDangerousProtocols($value)); break; default: $value = String::checkPlain($value); diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewEditFormController.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewEditFormController.php index 05c11cc..2bf6b69 100644 --- a/core/modules/views_ui/lib/Drupal/views_ui/ViewEditFormController.php +++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewEditFormController.php @@ -11,6 +11,7 @@ use Drupal\Core\Ajax\HtmlCommand; use Drupal\Core\Ajax\ReplaceCommand; use Drupal\Component\Utility\NestedArray; +use Drupal\Core\Url; use Drupal\user\TempStoreFactory; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -271,10 +272,10 @@ public function submit(array $form, array &$form_state) { unset($displays[$id]); // Redirect the user to the renamed display to be sure that the page itself exists and doesn't throw errors. - $form_state['redirect_route'] = array( - 'route_name' => 'views_ui.edit_display', - 'route_parameters' => array('view' => $view->id(), 'display_id' => $new_id), - ); + $form_state['redirect_route'] = new Url('views_ui.edit_display', array( + 'view' => $view->id(), + 'display_id' => $new_id, + )); } } $view->set('display', $displays); @@ -321,7 +322,7 @@ public function cancel(array $form, array &$form_state) { // Remove this view from cache so edits will be lost. $view = $this->entity; $this->tempStore->delete($view->id()); - $form_state['redirect_route']['route_name'] = 'views_ui.list'; + $form_state['redirect_route'] = new Url('views_ui.list'); } /** @@ -568,10 +569,10 @@ public function submitDisplayUndoDelete($form, &$form_state) { $view->cacheSet(); // Redirect to the top-level edit page. - $form_state['redirect_route'] = array( - 'route_name' => 'views_ui.edit_display', - 'route_parameters' => array('view' => $view->id(), 'display_id' => $id), - ); + $form_state['redirect_route'] = new Url('views_ui.edit_display', array( + 'view' => $view->id(), + 'display_id' => $id, + )); } /** @@ -587,10 +588,10 @@ public function submitDisplayEnable($form, &$form_state) { $view->cacheSet(); // Redirect to the top-level edit page. - $form_state['redirect_route'] = array( - 'route_name' => 'views_ui.edit_display', - 'route_parameters' => array('view' => $view->id(), 'display_id' => $id), - ); + $form_state['redirect_route'] = new Url('views_ui.edit_display', array( + 'view' => $view->id(), + 'display_id' => $id, + )); } /** @@ -605,10 +606,10 @@ public function submitDisplayDisable($form, &$form_state) { $view->cacheSet(); // Redirect to the top-level edit page. - $form_state['redirect_route'] = array( - 'route_name' => 'views_ui.edit_display', - 'route_parameters' => array('view' => $view->id(), 'display_id' => $id), - ); + $form_state['redirect_route'] = new Url('views_ui.edit_display', array( + 'view' => $view->id(), + 'display_id' => $id, + )); } /** @@ -626,10 +627,9 @@ public function submitDisplayDelete($form, &$form_state) { // Redirect to the top-level edit page. The first remaining display will // become the active display. - $form_state['redirect_route'] = array( - 'route_name' => 'views_ui.edit', - 'route_parameters' => array('view' => $view->id()), - ); + $form_state['redirect_route'] = new Url('views_ui.edit', array( + 'view' => $view->id(), + )); } /** @@ -802,10 +802,10 @@ public function submitDisplayDuplicate($form, &$form_state) { $view->cacheSet(); // Redirect to the new display's edit page. - $form_state['redirect_route'] = array( - 'route_name' => 'views_ui.edit_display', - 'route_parameters' => array('view' => $view->id(), 'display_id' => $new_display_id), - ); + $form_state['redirect_route'] = new Url('views_ui.edit_display', array( + 'view' => $view->id(), + 'display_id' => $new_display_id, + )); } /** @@ -824,10 +824,10 @@ public function submitDisplayAdd($form, &$form_state) { $view->cacheSet(); // Redirect to the new display's edit page. - $form_state['redirect_route'] = array( - 'route_name' => 'views_ui.edit_display', - 'route_parameters' => array('view' => $view->id(), 'display_id' => $display_id), - ); + $form_state['redirect_route'] = new Url('views_ui.edit_display', array( + 'view' => $view->id(), + 'display_id' => $display_id, + )); } /** @@ -860,10 +860,10 @@ public function submitCloneDisplayAsType($form, &$form_state) { $view->cacheSet(); // Redirect to the new display's edit page. - $form_state['redirect_route'] = array( - 'route_name' => 'views_ui.edit_display', - 'route_parameters' => array('view' => $view->id(), 'display_id' => $new_display_id), - ); + $form_state['redirect_route'] = new Url('views_ui.edit_display', array( + 'view' => $view->id(), + 'display_id' => $new_display_id, + )); } /** diff --git a/core/tests/Drupal/Tests/Component/Utility/UrlTest.php b/core/tests/Drupal/Tests/Component/Utility/UrlHelperTest.php similarity index 89% rename from core/tests/Drupal/Tests/Component/Utility/UrlTest.php rename to core/tests/Drupal/Tests/Component/Utility/UrlHelperTest.php index 4dec865..df970aa 100644 --- a/core/tests/Drupal/Tests/Component/Utility/UrlTest.php +++ b/core/tests/Drupal/Tests/Component/Utility/UrlHelperTest.php @@ -2,13 +2,12 @@ /** * @file - * Contains \Drupal\Tests\Component\Utility\UrlTest. + * Contains \Drupal\Tests\Component\Utility\UrlHelperTest. */ namespace Drupal\Tests\Component\Utility; - -use Drupal\Component\Utility\Url; +use Drupal\Component\Utility\UrlHelper; use Drupal\Component\Utility\String; use Drupal\Tests\UnitTestCase; @@ -17,12 +16,12 @@ * * @see \Drupal\Component\Utility\Url */ -class UrlTest extends UnitTestCase { +class UrlHelperTest extends UnitTestCase { public static function getInfo() { return array( - 'name' => t('Url Tests'), - 'description' => t('Tests the Url utility class.'), + 'name' => t('UrlHelper Tests'), + 'description' => t('Tests the UrlHelper utility class.'), 'group' => t('Path API'), ); } @@ -43,7 +42,7 @@ public function providerTestBuildQuery() { } /** - * Tests Url::buildQuery(). + * Tests UrlHelper::buildQuery(). * * @param array $query * The array of query parameters. @@ -55,7 +54,7 @@ public function providerTestBuildQuery() { * @dataProvider providerTestBuildQuery */ public function testBuildQuery($query, $expected, $message) { - $this->assertEquals(Url::buildQuery($query), $expected, $message); + $this->assertEquals(UrlHelper::buildQuery($query), $expected, $message); } /** @@ -100,7 +99,7 @@ public function providerTestValidAbsoluteData() { */ public function testValidAbsolute($url, $scheme) { $test_url = $scheme . '://' . $url; - $valid_url = Url::isValid($test_url, TRUE); + $valid_url = UrlHelper::isValid($test_url, TRUE); $this->assertTrue($valid_url, String::format('@url is a valid URL.', array('@url' => $test_url))); } @@ -130,7 +129,7 @@ public function providerTestInvalidAbsolute() { */ public function testInvalidAbsolute($url, $scheme) { $test_url = $scheme . '://' . $url; - $valid_url = Url::isValid($test_url, TRUE); + $valid_url = UrlHelper::isValid($test_url, TRUE); $this->assertFalse($valid_url, String::format('@url is NOT a valid URL.', array('@url' => $test_url))); } @@ -163,7 +162,7 @@ public function providerTestValidRelativeData() { */ public function testValidRelative($url, $prefix) { $test_url = $prefix . $url; - $valid_url = Url::isValid($test_url); + $valid_url = UrlHelper::isValid($test_url); $this->assertTrue($valid_url, String::format('@url is a valid URL.', array('@url' => $test_url))); } @@ -193,7 +192,7 @@ public function providerTestInvalidRelativeData() { */ public function testInvalidRelative($url, $prefix) { $test_url = $prefix . $url; - $valid_url = Url::isValid($test_url); + $valid_url = UrlHelper::isValid($test_url); $this->assertFalse($valid_url, String::format('@url is NOT a valid URL.', array('@url' => $test_url))); } @@ -210,10 +209,10 @@ public function testInvalidRelative($url, $prefix) { * * @dataProvider providerTestFilterQueryParameters * - * @see \Drupal\Component\Utility\Url::filterQueryParameters(). + * @see \Drupal\Component\Utility\UrlHelper::filterQueryParameters(). */ public function testFilterQueryParameters($query, $exclude, $expected) { - $filtered = Url::filterQueryParameters($query, $exclude); + $filtered = UrlHelper::filterQueryParameters($query, $exclude); $this->assertEquals($expected, $filtered, 'The query was not properly filtered.'); } @@ -249,10 +248,10 @@ public static function providerTestFilterQueryParameters() { * * @dataProvider providerTestParse * - * @see \Drupal\Component\Utility\Url::parse() + * @see \Drupal\Component\Utility\UrlHelper::parse() */ public function testParse($url, $expected) { - $parsed = Url::parse($url); + $parsed = UrlHelper::parse($url); $this->assertEquals($expected, $parsed, 'The url was not properly parsed.'); } @@ -302,12 +301,12 @@ public static function providerTestParse() { * @param string $expected * The expected encoded path. * - * @see \Drupal\Component\Utility\Url::encodePath(). + * @see \Drupal\Component\Utility\UrlHelper::encodePath(). * * @dataProvider providerTestEncodePath */ public function testEncodePath($path, $expected) { - $encoded = Url::encodePath($path); + $encoded = UrlHelper::encodePath($path); $this->assertEquals($expected, $encoded); } @@ -331,12 +330,12 @@ public static function providerTestEncodePath() { * @param bool $expected * Expected result. * - * @see \Drupal\Component\Utility\Url::isExternal() + * @see \Drupal\Component\Utility\UrlHelper::isExternal() * * @dataProvider providerTestIsExternal */ public function testIsExternal($path, $expected) { - $isExternal = Url::isExternal($path); + $isExternal = UrlHelper::isExternal($path); $this->assertEquals($expected, $isExternal); } @@ -366,8 +365,8 @@ public static function providerTestIsExternal() { * @dataProvider providerTestFilterBadProtocol */ public function testFilterBadProtocol($uri, $expected, $protocols) { - Url::setAllowedProtocols($protocols); - $filtered = Url::filterBadProtocol($uri); + UrlHelper::setAllowedProtocols($protocols); + $filtered = UrlHelper::filterBadProtocol($uri); $this->assertEquals($expected, $filtered); } @@ -398,13 +397,13 @@ public static function providerTestFilterBadProtocol() { * @param array $protocols * Protocols to allow. * - * @see \Drupal\Component\Utility\Url::stripDangerousProtocols() + * @see \Drupal\Component\Utility\UrlHelper::stripDangerousProtocols() * * @dataProvider providerTestStripDangerousProtocols */ public function testStripDangerousProtocols($uri, $expected, $protocols) { - Url::setAllowedProtocols($protocols); - $stripped = Url::stripDangerousProtocols($uri); + UrlHelper::setAllowedProtocols($protocols); + $stripped = UrlHelper::stripDangerousProtocols($uri); $this->assertEquals($expected, $stripped); } diff --git a/core/tests/Drupal/Tests/Component/Utility/XssTest.php b/core/tests/Drupal/Tests/Component/Utility/XssTest.php index 2614c5d..f58e353 100644 --- a/core/tests/Drupal/Tests/Component/Utility/XssTest.php +++ b/core/tests/Drupal/Tests/Component/Utility/XssTest.php @@ -8,7 +8,7 @@ namespace Drupal\Tests\Component\Utility; use Drupal\Component\Utility\String; -use Drupal\Component\Utility\Url; +use Drupal\Component\Utility\UrlHelper; use Drupal\Component\Utility\Xss; use Drupal\Tests\UnitTestCase; @@ -53,7 +53,7 @@ protected function setUp() { 'webcal', 'rtsp', ); - Url::setAllowedProtocols($allowed_protocols); + UrlHelper::setAllowedProtocols($allowed_protocols); } /** diff --git a/core/tests/Drupal/Tests/Core/DrupalTest.php b/core/tests/Drupal/Tests/Core/DrupalTest.php index b37010f..2a9e764 100644 --- a/core/tests/Drupal/Tests/Core/DrupalTest.php +++ b/core/tests/Drupal/Tests/Core/DrupalTest.php @@ -7,6 +7,7 @@ namespace Drupal\Tests\Core; +use Drupal\Core\Url; use Drupal\Tests\UnitTestCase; /** @@ -296,7 +297,30 @@ public function testL() { ->will($this->returnValue('link_html_string')); $this->setMockContainerService('link_generator', $generator); - $this->assertInternalType('string', \Drupal::l('Test title', 'test_route', $route_parameters, $options)); + $link = \Drupal::l('Test title', 'test_route', $route_parameters, $options); + $this->assertSame('link_html_string', $link); + $this->assertInternalType('string', $link); + } + + /** + * Tests the l() method. + * + * @see \Drupal\Core\Utility\LinkGeneratorInterface::generateFromUrl() + */ + public function testLWithUrl() { + $route_parameters = array('test_parameter' => 'test'); + $options = array('test_option' => 'test'); + $url = new Url('test_route', $route_parameters, $options); + $generator = $this->getMock('Drupal\Core\Utility\LinkGeneratorInterface'); + $generator->expects($this->once()) + ->method('generateFromUrl') + ->with('Test title', $url) + ->will($this->returnValue('link_html_string')); + $this->setMockContainerService('link_generator', $generator); + + $link = \Drupal::l('Test title', $url); + $this->assertSame('link_html_string', $link); + $this->assertInternalType('string', $link); } /** diff --git a/core/tests/Drupal/Tests/Core/ExternalUrlTest.php b/core/tests/Drupal/Tests/Core/ExternalUrlTest.php new file mode 100644 index 0000000..8dd02d3 --- /dev/null +++ b/core/tests/Drupal/Tests/Core/ExternalUrlTest.php @@ -0,0 +1,191 @@ + 'Url object (external)', + 'description' => 'Tests the \Drupal\Core\Url class with external paths.', + 'group' => 'Routing', + ); + } + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $this->urlGenerator = $this->getMock('Drupal\Core\Routing\UrlGeneratorInterface'); + $this->urlGenerator->expects($this->any()) + ->method('generateFromPath') + ->will($this->returnCallback(function ($path) { + return $path; + })); + + $container = new ContainerBuilder(); + $container->set('url_generator', $this->urlGenerator); + \Drupal::setContainer($container); + } + + /** + * Tests the createFromPath method. + * + * @covers ::createFromPath() + * @covers ::setExternal() + */ + public function testCreateFromPath() { + $url = Url::createFromPath($this->path); + $this->assertInstanceOf('Drupal\Core\Url', $url); + $this->assertTrue($url->isExternal()); + return $url; + } + + /** + * Tests the createFromRequest method. + * + * @covers ::createFromRequest() + */ + public function testCreateFromRequest() { + $request = new Request(array(), array(), array('_system_path' => $this->path)); + $url = Url::createFromRequest($request); + $this->assertInstanceOf('Drupal\Core\Url', $url); + $this->assertTrue($url->isExternal()); + } + + /** + * Tests the createFromRequest method. + * + * @covers ::createFromRequest() + * + * @expectedException \Exception + */ + public function testCreateFromRequestWithoutSystemPath() { + $request = new Request(); + $url = \Drupal\Core\Url::createFromRequest($request); + $this->assertNull($url); + } + + /** + * Tests the isExternal() method. + * + * @depends testCreateFromPath + * + * @covers ::isExternal() + */ + public function testIsExternal(\Drupal\Core\Url $url) { + $this->assertTrue($url->isExternal()); + } + + /** + * Tests the toString() method. + * + * @depends testCreateFromPath + * + * @covers ::toString() + */ + public function testToString(Url $url) { + $this->assertSame($this->path, $url->toString()); + } + + /** + * Tests the toArray() method. + * + * @depends testCreateFromPath + * + * @covers ::toArray() + * + * @expectedException \Exception + */ + public function testToArray(Url $url) { + $this->assertNull($url->toArray()); + } + + /** + * Tests the getRouteName() method. + * + * @depends testCreateFromPath + * + * @covers ::getRouteName() + * + * @expectedException \Exception + */ + public function testGetRouteName(Url $url) { + $this->assertNull($url->getRouteName()); + } + + /** + * Tests the getRouteParameters() method. + * + * @depends testCreateFromPath + * + * @covers ::getRouteParameters() + * + * @expectedException \Exception + */ + public function testGetRouteParameters(Url $url) { + $this->assertNull($url->getRouteParameters()); + } + + /** + * Tests the getInternalPath() method. + * + * @depends testCreateFromPath + * + * @covers ::getInternalPath() + * + * @expectedException \Exception + */ + public function testGetInternalPath(\Drupal\Core\Url $url) { + $this->assertNull($url->getInternalPath()); + } + + /** + * Tests the getOptions() method. + * + * @depends testCreateFromPath + * + * @covers ::getOptions() + */ + public function testGetOptions(\Drupal\Core\Url $url) { + $this->assertInternalType('array', $url->getOptions()); + } + +} diff --git a/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php b/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php index 0b52a75..4537b6e 100644 --- a/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php +++ b/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php @@ -7,8 +7,10 @@ namespace Drupal\Tests\Core\Form { +use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\DependencyInjection\ContainerInjectionInterface; use Drupal\Core\Form\FormInterface; +use Drupal\Core\Url; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; @@ -32,6 +34,17 @@ public static function getInfo() { } /** + * {@inheritdoc} + */ + public function setUp() { + parent::setUp(); + + $container = new ContainerBuilder(); + $container->set('url_generator', $this->urlGenerator); + \Drupal::setContainer($container); + } + + /** * Tests the getFormId() method with a string based form ID. */ public function testGetFormIdWithString() { @@ -225,6 +238,7 @@ public function providerTestRedirectWithRouteWithResult() { return array( array(array('redirect_route' => array('route_name' => 'test_route_a')), 'test-route'), array(array('redirect_route' => array('route_name' => 'test_route_b', 'route_parameters' => array('key' => 'value'))), 'test-route/value'), + array(array('redirect_route' => new Url('test_route_b', array('key' => 'value'))), 'test-route/value'), ); } diff --git a/core/tests/Drupal/Tests/Core/Routing/UrlMatcherTest.php b/core/tests/Drupal/Tests/Core/Routing/UrlMatcherTest.php deleted file mode 100644 index 450ae85..0000000 --- a/core/tests/Drupal/Tests/Core/Routing/UrlMatcherTest.php +++ /dev/null @@ -1,89 +0,0 @@ - 'UrlMatcher', - 'description' => 'Confirm that the UrlMatcher is functioning properly.', - 'group' => 'Routing', - ); - } - - /** - * {@inheritdoc} - */ - protected function setUp() { - $this->matcher = new UrlMatcher(); - } - - /** - * Tests the findRouteNameParameters method. - * - * @see \Drupal\Core\Routing\UrlMatcher::findRouteNameParameters() - */ - public function testFindRouteNameParameters() { - $router = $this->getMock('Symfony\Component\Routing\Matcher\RequestMatcherInterface'); - $container = new ContainerBuilder(); - $container->set('router', $router); - \Drupal::setContainer($container); - - $router->expects($this->at(0)) - ->method('matchRequest') - ->will($this->returnValue(array( - RouteObjectInterface::ROUTE_NAME => 'view.frontpage.page_1', - '_raw_variables' => new ParameterBag(), - ))); - $router->expects($this->at(1)) - ->method('matchRequest') - ->will($this->returnValue(array( - RouteObjectInterface::ROUTE_NAME => 'node_view', - '_raw_variables' => new ParameterBag(array('node' => '1')), - ))); - $router->expects($this->at(2)) - ->method('matchRequest') - ->will($this->returnValue(array( - RouteObjectInterface::ROUTE_NAME => 'node_edit', - '_raw_variables' => new ParameterBag(array('node' => '2')), - ))); - $router->expects($this->at(3)) - ->method('matchRequest') - ->will($this->throwException(new ResourceNotFoundException())); - - $this->assertEquals(array('view.frontpage.page_1', array()), $this->matcher->findRouteNameParameters('node')); - $this->assertEquals(array('node_view', array('node' => '1')), $this->matcher->findRouteNameParameters('node/1')); - $this->assertEquals(array('node_edit', array('node' => '2')), $this->matcher->findRouteNameParameters('node/2/edit')); - - $this->assertEquals(array(), $this->matcher->findRouteNameParameters('non-existing')); - } - -} diff --git a/core/tests/Drupal/Tests/Core/UrlTest.php b/core/tests/Drupal/Tests/Core/UrlTest.php new file mode 100644 index 0000000..8719fd1 --- /dev/null +++ b/core/tests/Drupal/Tests/Core/UrlTest.php @@ -0,0 +1,250 @@ + 'Url object (internal)', + 'description' => 'Tests the \Drupal\Core\Url class.', + 'group' => 'Routing', + ); + } + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $map = array(); + $map[] = array('view.frontpage.page_1', array(), array(), '/node'); + $map[] = array('node_view', array('node' => '1'), array(), '/node/1'); + $map[] = array('node_edit', array('node' => '2'), array(), '/node/2/edit'); + $this->map = $map; + + $this->urlGenerator = $this->getMock('Drupal\Core\Routing\UrlGeneratorInterface'); + $this->urlGenerator->expects($this->any()) + ->method('generateFromRoute') + ->will($this->returnValueMap($this->map)); + + $this->router = $this->getMock('Symfony\Component\Routing\RouterInterface'); + $container = new ContainerBuilder(); + $container->set('router', $this->router); + $container->set('url_generator', $this->urlGenerator); + \Drupal::setContainer($container); + } + + /** + * Tests the createFromPath method. + * + * @covers ::createFromPath() + */ + public function testCreateFromPath() { + $this->router->expects($this->exactly(3)) + ->method('match') + ->will($this->returnValueMap(array( + array('/node', array( + RouteObjectInterface::ROUTE_NAME => 'view.frontpage.page_1', + '_raw_variables' => new ParameterBag(), + )), + array('/node/1', array( + RouteObjectInterface::ROUTE_NAME => 'node_view', + '_raw_variables' => new ParameterBag(array('node' => '1')), + )), + array('/node/2/edit', array( + RouteObjectInterface::ROUTE_NAME => 'node_edit', + '_raw_variables' => new ParameterBag(array('node' => '2')), + )), + ))); + + $urls = array(); + foreach ($this->map as $index => $values) { + $path = trim(array_pop($values), '/'); + $url = Url::createFromPath($path); + $this->assertSame($values, array_values($url->toArray())); + $urls[$index] = $url; + } + return $urls; + } + + /** + * Tests that an invalid path will thrown an exception. + * + * @covers ::createFromPath() + * + * @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException + */ + public function testCreateFromPathInvalid() { + $this->router->expects($this->once()) + ->method('match') + ->with('/non-existent') + ->will($this->throwException(new ResourceNotFoundException())); + + Url::createFromPath('non-existent'); + } + + /** + * Tests the createFromRequest method. + * + * @covers ::createFromRequest() + */ + public function testCreateFromRequest() { + $request = new Request(array(), array(), array( + '_raw_variables' => new ParameterBag(array( + 'color' => 'chartreuse', + )), + RouteObjectInterface::ROUTE_NAME => 'the_route_name', + )); + + $url = Url::createFromRequest($request); + $expected = new Url('the_route_name', array('color' => 'chartreuse')); + $this->assertEquals($expected, $url); + } + + /** + * Tests the isExternal() method. + * + * @depends testCreateFromPath + * + * @covers ::isExternal() + */ + public function testIsExternal($urls) { + foreach ($urls as $url) { + $this->assertFalse($url->isExternal()); + } + } + + /** + * Tests the toString() method. + * + * @param \Drupal\Core\Url[] $urls + * An array of Url objects. + * + * @depends testCreateFromPath + * + * @covers ::toString() + */ + public function testToString($urls) { + foreach ($urls as $index => $url) { + $path = array_pop($this->map[$index]); + $this->assertSame($path, $url->toString()); + } + } + + /** + * Tests the toArray() method. + * + * @param \Drupal\Core\Url[] $urls + * An array of Url objects. + * + * @depends testCreateFromPath + * + * @covers ::toArray() + */ + public function testToArray($urls) { + foreach ($urls as $index => $url) { + $expected = array( + 'route_name' => $this->map[$index][0], + 'route_parameters' => $this->map[$index][1], + 'options' => $this->map[$index][2], + ); + $this->assertSame($expected, $url->toArray()); + } + } + + /** + * Tests the getRouteName() method. + * + * @param \Drupal\Core\Url[] $urls + * An array of Url objects. + * + * @depends testCreateFromPath + * + * @covers ::getRouteName() + */ + public function testGetRouteName($urls) { + foreach ($urls as $index => $url) { + $this->assertSame($this->map[$index][0], $url->getRouteName()); + } + } + + /** + * Tests the getRouteParameters() method. + * + * @param \Drupal\Core\Url[] $urls + * An array of Url objects. + * + * @depends testCreateFromPath + * + * @covers ::getRouteParameters() + */ + public function testGetRouteParameters($urls) { + foreach ($urls as $index => $url) { + $this->assertSame($this->map[$index][1], $url->getRouteParameters()); + } + } + + /** + * Tests the getOptions() method. + * + * @param \Drupal\Core\Url[] $urls + * An array of Url objects. + * + * @depends testCreateFromPath + * + * @covers ::getOptions() + */ + public function testGetOptions($urls) { + foreach ($urls as $index => $url) { + $this->assertSame($this->map[$index][2], $url->getOptions()); + } + } + +} diff --git a/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php b/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php index 80d9d58..23dd3ee 100644 --- a/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php +++ b/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php @@ -64,6 +64,7 @@ class LinkGeneratorTest extends UnitTestCase { 'html' => FALSE, 'language' => NULL, 'set_active_class' => FALSE, + 'absolute' => FALSE, ); /**