Skip to content
Snippets Groups Projects
Commit 65c808b1 authored by Alex Pott's avatar Alex Pott
Browse files

Issue #2153891 by tim.plunkett, amateescu: Add a Url value object.

parent f17c8b31
No related branches found
No related tags found
No related merge requests found
Showing
with 1064 additions and 169 deletions
......@@ -9,6 +9,8 @@
/**
* Helper class URL based methods.
*
* @todo Rename to UrlHelper in https://drupal.org/node/2184653.
*/
class Url {
......
......@@ -8,7 +8,8 @@
namespace Drupal\Core\Form;
use Drupal\Component\Utility\String;
use Drupal\Component\Utility\Url;
use Drupal\Component\Utility\Url as UrlHelper;
use Drupal\Core\Url;
use Symfony\Component\HttpFoundation\Request;
/**
......@@ -36,7 +37,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,
......@@ -44,19 +45,19 @@ public static function buildCancelLink(ConfirmFormInterface $form, Request $requ
}
// Check for a route-based cancel link.
elseif ($route = $form->getCancelRoute()) {
if (empty($route['route_name'])) {
throw new \UnexpectedValueException(String::format('Missing route name in !class::getCancelRoute().', array('!class' => get_class($form))));
if (!($route instanceof Url)) {
if (empty($route['route_name'])) {
throw new \UnexpectedValueException(String::format('Missing route name in !class::getCancelRoute().', array('!class' => get_class($form))));
}
// Ensure there is something to pass as the params and options.
$route += array(
'route_parameters' => array(),
'options' => array(),
);
$route = new Url($route['route_name'], $route['route_parameters'], $route['options']);
}
// Ensure there is something to pass as the params and options.
$route += array(
'route_parameters' => array(),
'options' => array(),
);
$link = array(
'#route_name' => $route['route_name'],
'#route_parameters' => $route['route_parameters'],
'#options' => $route['options'],
);
$link = $route->toRenderArray();
}
$link['#type'] = 'link';
......
......@@ -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\Url as 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.
......
<?php
/**
* @file
* Contains \Drupal\Core\Routing\MatchingRouteNotFoundException.
*/
namespace Drupal\Core\Routing;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
/**
* No matching route was found.
*/
class MatchingRouteNotFoundException extends ResourceNotFoundException {
}
......@@ -42,33 +42,4 @@ public function finalMatch(RouteCollection $collection, Request $request) {
return $this->match($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;
}
catch (\Exception $e) {
return array();
}
}
}
<?php
/**
* @file
* Contains \Drupal\Core\Url.
*/
namespace Drupal\Core;
use Drupal\Component\Utility\Url as UrlHelper;
use Drupal\Core\DependencyInjection\DependencySerialization;
use Drupal\Core\Routing\MatchingRouteNotFoundException;
use Drupal\Core\Routing\UrlGeneratorInterface;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
/**
* Defines an object that holds information about a URL.
*/
class Url extends DependencySerialization {
/**
* The URL generator.
*
* @var \Drupal\Core\Routing\UrlGeneratorInterface
*/
protected $urlGenerator;
/**
* The route name.
*
* @var string
*/
protected $routeName;
/**
* The route parameters.
*
* @var array
*/
protected $routeParameters = array();
/**
* The URL options.
*
* @var array
*/
protected $options = array();
/**
* Indicates whether this URL is external.
*
* @var bool
*/
protected $external = FALSE;
/**
* The external path.
*
* Only used if self::$external is TRUE.
*
* @var string
*/
protected $path;
/**
* Constructs a new Url object.
*
* @param string $route_name
* The name of the route
* @param array $route_parameters
* (optional) An associative array of parameter names and values.
* @param array $options
* (optional) An associative array of additional options, with the following
* elements:
* - 'query': An array of query key/value-pairs (without any URL-encoding)
* to append to the URL. Merged with the parameters array.
* - 'fragment': A fragment identifier (named anchor) to append to the URL.
* Do not include the leading '#' character.
* - 'absolute': Defaults to FALSE. 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.
* - 'language': An optional language object used to look up the alias
* for the URL. If $options['language'] is omitted, the language will be
* obtained from language(Language::TYPE_URL).
* - 'https': Whether this URL should point to a secure location. If not
* defined, the current scheme is used, so the user stays on HTTP or HTTPS
* respectively. if mixed mode sessions are permitted, TRUE enforces HTTPS
* and FALSE enforces HTTP.
*/
public function __construct($route_name, $route_parameters = array(), $options = array()) {
$this->routeName = $route_name;
$this->routeParameters = $route_parameters;
$this->options = $options;
}
/**
* Returns the Url object matching a path.
*
* @param string $path
* A path (e.g. 'node/1', 'http://drupal.org').
*
* @return static
* An Url object.
*
* @throws \Drupal\Core\Routing\MatchingRouteNotFoundException
* Thrown when the path cannot be matched.
*/
public static function createFromPath($path) {
if (UrlHelper::isExternal($path)) {
$url = new static($path);
$url->setExternal();
return $url;
}
// Special case the front page route.
if ($path == '<front>') {
$route_name = $path;
$route_parameters = array();
}
else {
// Look up the route name and parameters used for the given path.
try {
$result = \Drupal::service('router')->match('/' . $path);
}
catch (ResourceNotFoundException $e) {
throw new MatchingRouteNotFoundException(sprintf('No matching route could be found for the path "%s"', $path), 0, $e);
}
$route_name = $result[RouteObjectInterface::ROUTE_NAME];
$route_parameters = $result['_raw_variables']->all();
}
return new static($route_name, $route_parameters);
}
/**
* Returns the Url object matching a request.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* A request object.
*
* @return static
* A Url object.
*
* @throws \Drupal\Core\Routing\MatchingRouteNotFoundException
* Thrown when the request cannot be matched.
*/
public static function createFromRequest(Request $request) {
try {
$result = \Drupal::service('router')->matchRequest($request);
}
catch (ResourceNotFoundException $e) {
throw new MatchingRouteNotFoundException(sprintf('No matching route could be found for the request: %s', $request), 0, $e);
}
$route_name = $result[RouteObjectInterface::ROUTE_NAME];
$route_parameters = $result['_raw_variables']->all();
return new static($route_name, $route_parameters);
}
/**
* 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;
// Set empty route name and parameters.
$this->routeName = '';
$this->routeParameters = array();
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() {
return $this->routeName;
}
/**
* Returns the route parameters.
*
* @return array
*/
public function getRouteParameters() {
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;
}
/**
* Gets a specific option.
*
* @param string $name
* The name of the option.
*
* @return mixed
* The value for a specific option, or NULL if it does not exist.
*/
public function getOption($name) {
if (!isset($this->options[$name])) {
return NULL;
}
return $this->options[$name];
}
/**
* 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() {
return array(
'route_name' => $this->getRouteName(),
'route_parameters' => $this->getRouteParameters(),
'options' => $this->getOptions(),
);
}
/**
* Returns the route information for a render array.
*
* @return array
* An associative array suitable for a render array.
*/
public function toRenderArray() {
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());
}
/**
* 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;
}
}
......@@ -13,6 +13,7 @@
use Drupal\Core\Path\AliasManagerInterface;
use Drupal\Core\Template\Attribute;
use Drupal\Core\Routing\UrlGeneratorInterface;
use Drupal\Core\Url;
/**
* Provides a class which generates a link with route names and parameters.
......@@ -68,14 +69,13 @@ public function __construct(UrlGeneratorInterface $url_generator, ModuleHandlerI
*
* @see system_page_build()
*/
public function generate($text, $route_name, array $parameters = array(), array $options = array()) {
public function generateFromUrl($text, Url $url) {
// 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,
'url' => $url,
'options' => $url->getOptions(),
);
// Merge in default options.
......@@ -85,6 +85,7 @@ public function generate($text, $route_name, array $parameters = array(), 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
......@@ -106,7 +107,7 @@ public function generate($text, $route_name, array $parameters = array(), array
// 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);
$path = $url->getInternalPath();
$variables['options']['attributes']['data-drupal-link-system-path'] = $this->aliasManager->getSystemPath($path);
}
}
......@@ -123,10 +124,11 @@ public function generate($text, $route_name, array $parameters = array(), array
// Move attributes out of options. generateFromRoute(() doesn't need them.
$attributes = new Attribute($variables['options']['attributes']);
unset($variables['options']['attributes']);
$url->setOptions($variables['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']);
......@@ -134,4 +136,13 @@ public function generate($text, $route_name, array $parameters = array(), array
return '<a href="' . $url . '"' . $attributes . '>' . $text . '</a>';
}
/**
* {@inheritdoc}
*/
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);
}
}
......@@ -7,6 +7,8 @@
namespace Drupal\Core\Utility;
use Drupal\Core\Url;
/**
* Defines an interface for generating links from route names and parameters.
*/
......@@ -77,4 +79,17 @@ interface LinkGeneratorInterface {
*/
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);
}
......@@ -9,6 +9,7 @@
use Drupal\Core\Entity\Entity;
use Drupal\Core\Entity\EntityStorageControllerInterface;
use Drupal\Core\Url;
use Drupal\menu_link\MenuLinkInterface;
use Symfony\Component\Routing\Route;
......@@ -504,13 +505,9 @@ 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();
}
$url = Url::createFromPath($this->link_path);
$this->route_name = $url->getRouteName();
$this->route_parameters = $url->getRouteParameters();
}
elseif (empty($this->link_path)) {
$this->link_path = \Drupal::urlGenerator()->getPathFromRoute($this->route_name, $this->route_parameters);
......
......@@ -11,6 +11,7 @@
use Drupal\Core\Entity\EntityStorageControllerInterface;
use Drupal\Core\Field\FieldDefinition;
use Drupal\Core\Routing\UrlMatcher;
use Drupal\Core\Url;
use Drupal\shortcut\ShortcutInterface;
/**
......@@ -125,10 +126,9 @@ 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]);
}
$url = Url::createFromPath($this->path->value);
$this->setRouteName($url->getRouteName());
$this->setRouteParams($url->getRouteParameters());
}
/**
......
......@@ -6,6 +6,7 @@
*/
use Drupal\Core\Routing\UrlMatcher;
use Drupal\Core\Url;
use Drupal\shortcut\ShortcutSetInterface;
use Symfony\Component\HttpFoundation\Request;
......@@ -389,7 +390,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 +406,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;
}
......
......@@ -75,7 +75,6 @@ function testBreadCrumbs() {
'admin/structure/taxonomy/manage/tags' => t('Tags'),
);
$this->assertBreadcrumb('admin/structure/taxonomy/manage/tags/overview', $trail);
$this->assertBreadcrumb('admin/structure/taxonomy/manage/tags/fields', $trail);
$this->assertBreadcrumb('admin/structure/taxonomy/manage/tags/add', $trail);
// Verify Menu administration breadcrumbs.
......
......@@ -3156,13 +3156,7 @@ function hook_filetransfer_info_alter(&$filetransfer_info) {
* - 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".
* - url: The \Drupal\Core\Url object.
* - 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
......
......@@ -93,3 +93,37 @@ router_test.14:
defaults:
_controller: '\Drupal\router_test\TestControllers::test9'
router_test.hierarchy_parent:
path: '/menu-test/parent'
defaults:
_controller: '\Drupal\router_test\TestControllers::test'
requirements:
_access: 'TRUE'
router_test.hierarchy_parent_child1:
path: '/menu-test/parent/child-1'
defaults:
_controller: '\Drupal\router_test\TestControllers::test'
requirements:
_access: 'TRUE'
router_test.hierarchy_parent_child1_1:
path: '/menu-test/parent/child-1/child-1-1'
defaults:
_controller: '\Drupal\router_test\TestControllers::test'
requirements:
_access: 'TRUE'
router_test.hierarchy_parent_child1_2:
path: '/menu-test/parent/child-1/child-1-2'
defaults:
_controller: '\Drupal\router_test\TestControllers::test'
requirements:
_access: 'TRUE'
router_test.hierarchy_parent_child2:
path: '/menu-test/parent/child-2'
defaults:
_controller: '\Drupal\router_test\TestControllers::test'
requirements:
_access: 'TRUE'
<?php
/**
* @file
* Contains \Drupal\Tests\Core\ExternalUrlTest.
*/
namespace Drupal\Tests\Core;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Url;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
/**
* Tests the \Drupal\Core\Url class for external paths.
*
* @group Drupal
* @group Url
*
* @coversDefaultClass \Drupal\Core\Url
*/
class ExternalUrlTest extends UnitTestCase {
/**
* The URL generator
*
* @var \Drupal\Core\Routing\UrlGeneratorInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $urlGenerator;
/**
* The router.
*
* @var \Drupal\Tests\Core\Routing\TestRouterInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $router;
/**
* An external URL to test.
*
* @var string
*/
protected $path = 'http://drupal.org';
/**
* {@inheritdoc}
*/
public static function getInfo() {
return array(
'name' => '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;
}));
$this->router = $this->getMock('Drupal\Tests\Core\Routing\TestRouterInterface');
$container = new ContainerBuilder();
$container->set('router', $this->router);
$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()
*
* @expectedException \Drupal\Core\Routing\MatchingRouteNotFoundException
* @expectedExceptionMessage No matching route could be found for the request: request_as_a_string
*/
public function testCreateFromRequest() {
// Mock the request in order to override the __toString() method.
$request = $this->getMock('Symfony\Component\HttpFoundation\Request');
$request->expects($this->once())
->method('__toString')
->will($this->returnValue('request_as_a_string'));
$this->router->expects($this->once())
->method('matchRequest')
->with($request)
->will($this->throwException(new ResourceNotFoundException()));
$this->assertNull(Url::createFromRequest($request));
}
/**
* Tests the isExternal() method.
*
* @depends testCreateFromPath
*
* @covers ::isExternal()
*/
public function testIsExternal(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()
*/
public function testToArray(Url $url) {
$expected = array(
'route_name' => '',
'route_parameters' => array(),
'options' => array(),
);
$this->assertSame($expected, $url->toArray());
}
/**
* Tests the getRouteName() method.
*
* @depends testCreateFromPath
*
* @covers ::getRouteName()
*/
public function testGetRouteName(Url $url) {
$this->assertSame('', $url->getRouteName());
}
/**
* Tests the getRouteParameters() method.
*
* @depends testCreateFromPath
*
* @covers ::getRouteParameters()
*/
public function testGetRouteParameters(Url $url) {
$this->assertSame(array(), $url->getRouteParameters());
}
/**
* Tests the getInternalPath() method.
*
* @depends testCreateFromPath
*
* @covers ::getInternalPath()
*
* @expectedException \Exception
*/
public function testGetInternalPath(Url $url) {
$this->assertNull($url->getInternalPath());
}
/**
* Tests the getOptions() method.
*
* @depends testCreateFromPath
*
* @covers ::getOptions()
*/
public function testGetOptions(Url $url) {
$this->assertInternalType('array', $url->getOptions());
}
}
......@@ -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;
......@@ -31,6 +33,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.
*/
......@@ -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'),
);
}
......
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Routing\TestRouterInterface.
*/
namespace Drupal\Tests\Core\Routing;
use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
use Symfony\Component\Routing\RouterInterface;
/**
* Provides a router interface that also can match requests.
*/
interface TestRouterInterface extends RouterInterface, RequestMatcherInterface {
}
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Routing\UrlMatcherTest.
*/
namespace Drupal\Tests\Core\Routing;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Routing\UrlMatcher;
use Drupal\Tests\UnitTestCase;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
/**
* Tests the menu link entity class.
*
* @group Drupal
* @group Routing
*
* @see \Drupal\Core\Routing\UrlMatcher
*/
class UrlMatcherTest extends UnitTestCase {
/**
* The url generator to test.
*
* @var \Drupal\Core\Routing\UrlMatcher
*/
protected $matcher;
public static function getInfo() {
return array(
'name' => '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'));
}
}
<?php
/**
* @file
* Contains \Drupal\Tests\Core\UrlTest.
*/
namespace Drupal\Tests\Core;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Url;
use Drupal\Tests\UnitTestCase;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
/**
* Tests the \Drupal\Core\Url class.
*
* @group Drupal
* @group Url
*
* @coversDefaultClass \Drupal\Core\Url
*/
class UrlTest extends UnitTestCase {
/**
* The URL generator
*
* @var \Drupal\Core\Routing\UrlGeneratorInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $urlGenerator;
/**
* The router.
*
* @var \Drupal\Tests\Core\Routing\TestRouterInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $router;
/**
* An array of values to use for the test.
*
* @var array
*/
protected $map;
/**
* {@inheritdoc}
*/
public static function getInfo() {
return array(
'name' => '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('Drupal\Tests\Core\Routing\TestRouterInterface');
$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->any())
->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 the createFromPath method with the special <front> path.
*
* @covers ::createFromPath()
*/
public function testCreateFromPathFront() {
$url = Url::createFromPath('<front>');
$this->assertSame('<front>', $url->getRouteName());
}
/**
* Tests that an invalid path will thrown an exception.
*
* @covers ::createFromPath()
*
* @expectedException \Drupal\Core\Routing\MatchingRouteNotFoundException
* @expectedExceptionMessage No matching route could be found for the path "non-existent"
*/
public function testCreateFromPathInvalid() {
$this->router->expects($this->once())
->method('match')
->with('/non-existent')
->will($this->throwException(new ResourceNotFoundException()));
$this->assertNull(Url::createFromPath('non-existent'));
}
/**
* Tests the createFromRequest method.
*
* @covers ::createFromRequest()
*/
public function testCreateFromRequest() {
$attributes = array(
'_raw_variables' => new ParameterBag(array(
'color' => 'chartreuse',
)),
RouteObjectInterface::ROUTE_NAME => 'the_route_name',
);
$request = new Request(array(), array(), $attributes);
$this->router->expects($this->once())
->method('matchRequest')
->with($request)
->will($this->returnValue($attributes));
$url = Url::createFromRequest($request);
$expected = new Url('the_route_name', array('color' => 'chartreuse'));
$this->assertEquals($expected, $url);
}
/**
* Tests that an invalid request will thrown an exception.
*
* @covers ::createFromRequest()
*
* @expectedException \Drupal\Core\Routing\MatchingRouteNotFoundException
* @expectedExceptionMessage No matching route could be found for the request: request_as_a_string
*/
public function testCreateFromRequestInvalid() {
// Mock the request in order to override the __toString() method.
$request = $this->getMock('Symfony\Component\HttpFoundation\Request');
$request->expects($this->once())
->method('__toString')
->will($this->returnValue('request_as_a_string'));
$this->router->expects($this->once())
->method('matchRequest')
->with($request)
->will($this->throwException(new ResourceNotFoundException()));
$this->assertNull(Url::createFromRequest($request));
}
/**
* 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());
}
}
}
......@@ -8,6 +8,7 @@
namespace Drupal\Tests\Core\Utility {
use Drupal\Core\Language\Language;
use Drupal\Core\Url;
use Drupal\Core\Utility\LinkGenerator;
use Drupal\Tests\UnitTestCase;
......@@ -15,6 +16,8 @@
* Tests the link generator.
*
* @see \Drupal\Core\Utility\LinkGenerator
*
* @coversDefaultClass \Drupal\Core\Utility\LinkGenerator
*/
class LinkGeneratorTest extends UnitTestCase {
......@@ -54,6 +57,7 @@ class LinkGeneratorTest extends UnitTestCase {
'html' => FALSE,
'language' => NULL,
'set_active_class' => FALSE,
'absolute' => FALSE,
);
/**
......@@ -124,6 +128,34 @@ public function testGenerateHrefs($route_name, array $parameters, $absolute, $ur
), $result);
}
/**
* Tests the generateFromUrl() method.
*
* @covers ::generateFromUrl()
*/
public function testGenerateFromUrl() {
$this->urlGenerator->expects($this->once())
->method('generateFromRoute')
->with('test_route_1', array(), array('fragment' => 'the-fragment') + $this->defaultOptions)
->will($this->returnValue('/test-route-1#the-fragment'));
$this->moduleHandler->expects($this->once())
->method('alter')
->with('link', $this->isType('array'));
$url = new Url('test_route_1', array(), array('fragment' => 'the-fragment'));
$url->setUrlGenerator($this->urlGenerator);
$result = $this->linkGenerator->generateFromUrl('Test', $url);
$this->assertTag(array(
'tag' => 'a',
'attributes' => array(
'href' => '/test-route-1#the-fragment',
),
'content' => 'Test',
), $result);
}
/**
* Tests the link method with additional attributes.
*
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment