Commit 195d4999 authored by alexpott's avatar alexpott

Issue #2347465 by tim.plunkett, dawehner, cilefen: Convert all instances of...

Issue #2347465 by tim.plunkett, dawehner, cilefen: Convert all instances of #type link/links to convert to use routes.
parent 1308c595
......@@ -344,19 +344,9 @@ function template_preprocess_menu_local_task(&$variables) {
$variables['link'] = array(
'#type' => 'link',
'#title' => $link_text,
'#url' => $link['url'],
'#options' => $link['localized_options'],
);
if (!empty($link['href'])) {
// @todo - Remove this once all pages are converted to routes.
$variables['link']['#href'] = $link['href'];
}
else {
$variables['link'] += array(
'#route_name' => $link['route_name'],
'#route_parameters' => $link['route_parameters'],
);
}
}
/**
......@@ -373,9 +363,7 @@ function template_preprocess_menu_local_task(&$variables) {
function template_preprocess_menu_local_action(&$variables) {
$link = $variables['element']['#link'];
$link += array(
'href' => '',
'localized_options' => array(),
'route_parameters' => array(),
);
$link['localized_options']['attributes']['class'][] = 'button';
$link['localized_options']['attributes']['class'][] = 'button-action';
......@@ -385,19 +373,8 @@ function template_preprocess_menu_local_action(&$variables) {
'#type' => 'link',
'#title' => $link['title'],
'#options' => $link['localized_options'],
'#url' => $link['url'],
);
// @todo Figure out how to support local actions without a href properly.
if ($link['href'] === '' && !empty($link['route_name'])) {
$variables['link'] += array(
'#route_name' => $link['route_name'],
'#route_parameters' => $link['route_parameters'],
);
}
else {
// @todo - Remove this once all pages are converted to routes.
$variables['link']['#href'] = $link['href'];
}
}
/**
......
......@@ -902,14 +902,8 @@ function template_preprocess_status_messages(&$variables) {
* is used as its CSS class. Each link should be itself an array, with the
* following elements:
* - title: The link text.
* - route_name: (optional) The name of the route to link to. If omitted
* (and if 'href' is omitted as well), the 'title' is shown as
* a plain text item in the links list.
* - route_parameters: (optional) An array of route parameters for the link.
* - href: (optional) The link URL. It is preferred to use 'route_name' and
* 'route parameters' for internal links. Use 'href' for links to external
* URLs. If omitted (and if 'route_name' is omitted as well), the 'title'
* is shown as a plain text item in the links list.
* - url: (optional) The url object to link to. If omitted, no a tag is
* printed out.
* - html: (optional) Whether or not 'title' is HTML. If set, the title
* will not be passed through
* \Drupal\Component\Utility\String::checkPlain().
......@@ -986,30 +980,26 @@ function template_preprocess_links(&$variables) {
foreach ($links as $key => $link) {
$item = array();
$link += array(
'href' => NULL,
'route_name' => NULL,
'route_parameters' => NULL,
'ajax' => NULL,
'url' => NULL,
);
$li_attributes = array('class' => array());
// Use the array key as class name.
$li_attributes['class'][] = drupal_html_class($key);
$keys = array('title', 'href', 'route_name', 'route_parameters');
$keys = ['title', 'url'];
$link_element = array(
'#type' => 'link',
'#title' => $link['title'],
'#options' => array_diff_key($link, array_combine($keys, $keys)),
'#href' => $link['href'],
'#route_name' => $link['route_name'],
'#route_parameters' => $link['route_parameters'],
'#url' => $link['url'],
'#ajax' => $link['ajax'],
);
// Handle links and ensure that the active class is added on the LIs, but
// only if the 'set_active_class' option is not empty.
if (isset($link['href']) || isset($link['route_name'])) {
if (isset($link['url'])) {
if (!empty($variables['set_active_class'])) {
// Also enable set_active_class for the contained link.
......@@ -1027,16 +1017,16 @@ function template_preprocess_links(&$variables) {
$li_attributes['data-drupal-link-query'] = Json::encode($query);
}
if (isset($link['route_name'])) {
$path = \Drupal::service('url_generator')->getPathFromRoute($link['route_name'], $link['route_parameters']);
/** @var \Drupal\Core\Url $url */
$url = $link['url'];
if ($url->isRouted()) {
// Add a "data-drupal-link-system-path" attribute to let the
// drupal.active-link library know the path in a standardized manner.
$system_path = $url->getInternalPath();
// @todo System path is deprecated - use the route name and parameters.
// Special case for the front page.
$li_attributes['data-drupal-link-system-path'] = $system_path == '' ? '<front>' : $system_path;
}
else {
$path = $link['href'];
}
// Add a "data-drupal-link-system-path" attribute to let the
// drupal.active-link library know the path in a standardized manner.
$li_attributes['data-drupal-link-system-path'] = \Drupal::service('path.alias_manager')->getPathByAlias($path);
}
$item['link'] = $link_element;
......
......@@ -41,13 +41,15 @@ public function getDefaultOperations(EntityInterface $entity) {
$operations['enable'] = array(
'title' => t('Enable'),
'weight' => -10,
) + $entity->urlInfo('enable')->toArray();
'url' => $entity->urlInfo('enable'),
);
}
elseif ($entity->hasLinkTemplate('disable')) {
$operations['disable'] = array(
'title' => t('Disable'),
'weight' => 40,
) + $entity->urlInfo('disable')->toArray();
'url' => $entity->urlInfo('disable'),
);
}
}
......
......@@ -213,7 +213,7 @@ protected function actions(array $form, FormStateInterface $form_state) {
'class' => array('button', 'button--danger'),
),
);
$actions['delete'] += $route_info->toRenderArray();
$actions['delete']['#url'] = $route_info;
}
return $actions;
......
......@@ -118,13 +118,15 @@ protected function getDefaultOperations(EntityInterface $entity) {
$operations['edit'] = array(
'title' => $this->t('Edit'),
'weight' => 10,
) + $entity->urlInfo('edit-form')->toArray();
'url' => $entity->urlInfo('edit-form'),
);
}
if ($entity->access('delete') && $entity->hasLinkTemplate('delete-form')) {
$operations['delete'] = array(
'title' => $this->t('Delete'),
'weight' => 100,
) + $entity->urlInfo('delete-form')->toArray();
'url' => $entity->urlInfo('delete-form'),
);
}
return $operations;
......
......@@ -9,6 +9,7 @@
use Drupal\Core\Field\FormatterBase;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Url;
/**
* Plugin implementation of the 'email_mailto' formatter.
......@@ -33,7 +34,7 @@ public function viewElements(FieldItemListInterface $items) {
$elements[$delta] = array(
'#type' => 'link',
'#title' => $item->value,
'#href' => 'mailto:' . $item->value,
'#url' => Url::fromUri('mailto:' . $item->value),
);
}
......
......@@ -9,6 +9,7 @@
use Drupal\Core\Field\FormatterBase;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Url;
/**
* Plugin implementation of the 'uri_link' formatter.
......@@ -30,11 +31,13 @@ public function viewElements(FieldItemListInterface $items) {
$elements = array();
foreach ($items as $delta => $item) {
$elements[$delta] = array(
'#type' => 'link',
'#href' => $item->value,
'#title' => $item->value,
);
if (!$item->isEmpty()) {
$elements[$delta] = [
'#type' => 'link',
'#url' => Url::fromUri($item->value),
'#title' => $item->value,
];
}
}
return $elements;
......
......@@ -61,4 +61,15 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
);
}
/**
* {@inheritdoc}
*/
public function isEmpty() {
$value = $this->getValue();
if (!isset($value['value']) || $value['value'] === '') {
return TRUE;
}
return parent::isEmpty();
}
}
......@@ -34,19 +34,20 @@ public static function buildCancelLink(ConfirmFormInterface $form, Request $requ
// If a destination is specified, that serves as the cancel link.
if ($query->has('destination')) {
$options = UrlHelper::parse($query->get('destination'));
$link = array(
'#href' => $options['path'],
'#options' => $options,
);
// @todo Use Url::fromPath() once https://www.drupal.org/node/2351379 is
// resolved.
$url = Url::fromUri('base://' . $options['path'], $options);
}
// Check for a route-based cancel link.
elseif ($url = $form->getCancelUrl()) {
$link = $url->toRenderArray();
else {
$url = $form->getCancelUrl();
}
$link['#type'] = 'link';
$link['#title'] = $form->getCancelText();
return $link;
return [
'#type' => 'link',
'#title' => $form->getCancelText(),
'#url' => $url,
];
}
}
......@@ -11,6 +11,7 @@
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\Core\StringTranslation\TranslationWrapper;
use Drupal\Core\Url;
/**
* Class responsible for providing language support on language-unaware sites.
......@@ -239,7 +240,7 @@ public function getFallbackCandidates(array $context = array()) {
/**
* {@inheritdoc}
*/
public function getLanguageSwitchLinks($type, $path) {
public function getLanguageSwitchLinks($type, Url $url) {
return array();
}
......
......@@ -8,6 +8,7 @@
namespace Drupal\Core\Language;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\Core\Url;
/**
* Common interface for the language manager service.
......@@ -181,13 +182,13 @@ public function getFallbackCandidates(array $context = array());
*
* @param string $type
* The language type.
* @param string $path
* The internal path the switch links will be relative to.
* @param \Drupal\Core\Url $url
* The URL the switch links will be relative to.
*
* @return array
* A keyed array of links ready to be themed.
*/
public function getLanguageSwitchLinks($type, $path);
public function getLanguageSwitchLinks($type, Url $url);
/**
* Sets the configuration override language.
......
......@@ -113,7 +113,8 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta
$link = array(
'#type' => 'link',
'#title' => $this->menuLink->getTitle(),
) + $this->menuLink->getUrlObject()->toRenderArray();
'#url' => $this->menuLink->getUrlObject(),
);
$form['path'] = array(
'link' => $link,
'#type' => 'item',
......
......@@ -16,6 +16,7 @@
use Drupal\Core\Plugin\Discovery\YamlDiscovery;
use Drupal\Core\Plugin\Factory\ContainerFactory;
use Drupal\Core\Routing\RouteProviderInterface;
use Drupal\Core\Url;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
use Drupal\Core\Session\AccountInterface;
......@@ -166,8 +167,7 @@ public function getActionsForRoute($route_appears) {
'#theme' => 'menu_local_action',
'#link' => array(
'title' => $this->getTitle($plugin),
'route_name' => $route_name,
'route_parameters' => $route_parameters,
'url' => Url::fromRoute($route_name, $route_parameters),
'localized_options' => $plugin->getOptions($request),
),
'#access' => $this->accessManager->checkNamedRoute($route_name, $route_parameters, $this->account),
......
......@@ -21,6 +21,7 @@
use Drupal\Core\Routing\RouteBuilderInterface;
use Drupal\Core\Routing\RouteProviderInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Symfony\Component\HttpFoundation\RequestStack;
/**
......@@ -306,8 +307,7 @@ public function getTasksBuild($current_route_name) {
$link = array(
'title' => $this->getTitle($child),
'route_name' => $route_name,
'route_parameters' => $route_parameters,
'url' => Url::fromRoute($route_name, $route_parameters),
'localized_options' => $child->getOptions($request),
);
$build[$level][$plugin_id] = array(
......
......@@ -218,9 +218,9 @@ public function getFormClass();
/**
* Returns route information for a route to delete the menu link.
*
* @return array|null
* An array with keys route_name and route_parameters, or NULL if there is
* no route (e.g. when the link is not deletable).
* @return \Drupal\Core\Url|null
* A Url object, or NULL if there is no route (e.g. when the link is not
* deletable).
*/
public function getDeleteRoute();
......@@ -231,18 +231,18 @@ public function getDeleteRoute();
* they need to define additional local tasks, local actions, etc. that are
* visible from the edit form.
*
* @return array|null
* An array with keys route_name and route_parameters, or NULL if there is
* no route because there is no custom edit route for this instance.
* @return \Drupal\Core\Url|null
* A Url object, or NULL if there is no route because there is no custom
* edit route for this instance.
*/
public function getEditRoute();
/**
* Returns route information for a route to translate the menu link.
*
* @return array
* An array with keys route_name and route_parameters, or NULL if there is
* no route (e.g. when the link is not translatable).
* @return \Drupal\Core\Url|null
* A Url object, or NULL if there is no route (e.g. when the link is not
* translatable).
*/
public function getTranslateRoute();
......
......@@ -7,7 +7,7 @@
namespace Drupal\Core\Render\Element;
use Drupal\Core\Url as UrlObject;
use Drupal\Component\Utility\NestedArray;
/**
* Provides a link render element.
......@@ -36,11 +36,7 @@ public function getInfo() {
* @param array $element
* A structured array whose keys form the arguments to _l():
* - #title: The link text to pass as argument to _l().
* - One of the following
* - #route_name and (optionally) a #route_parameters array; The route
* name and route parameters which will be passed into the link
* generator.
* - #href: The system path or URL to pass as argument to _l().
* - #url: The URL info either pointing to a route or a non routed path.
* - #options: (optional) An array of options to pass to _l() or the link
* generator.
*
......@@ -75,21 +71,12 @@ public static function preRenderLink($element) {
if (!isset($element['#id'])) {
$element['#id'] = $element['#options']['attributes']['id'] = drupal_html_id('ajax-link');
}
// If #ajax['path] was not specified, use the href as Ajax request URL.
if (!isset($element['#ajax']['path'])) {
$element['#ajax']['path'] = $element['#href'];
$element['#ajax']['options'] = $element['#options'];
}
$element = static::preRenderAjaxForm($element);
}
if (isset($element['#route_name'])) {
$element['#route_parameters'] = empty($element['#route_parameters']) ? array() : $element['#route_parameters'];
$element['#markup'] = \Drupal::l($element['#title'], new UrlObject($element['#route_name'], $element['#route_parameters'], $element['#options']));
}
else {
// @todo Convert to \Drupal::l(): https://www.drupal.org/node/2347045.
$element['#markup'] = _l($element['#title'], $element['#href'], $element['#options']);
if (!empty($element['#url'])) {
$options = NestedArray::mergeDeep($element['#url']->getOptions(), $element['#options']);
$element['#markup'] = \Drupal::l($element['#title'], $element['#url']->setOptions($options));
}
return $element;
}
......
......@@ -281,7 +281,7 @@ public static function validateTable(&$element, FormStateInterface $form_state,
* $form['table'][$row]['edit'] = array(
* '#type' => 'link',
* '#title' => t('Edit'),
* '#href' => 'thing/' . $row . '/edit',
* '#url' => Url::fromRoute('entity.test_entity.edit_form', ['test_entity' => $row]),
* );
* }
* @endcode
......
......@@ -7,6 +7,7 @@
namespace Drupal\Core;
use Drupal\Component\Utility\String;
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
use Drupal\Core\Routing\UrlGeneratorInterface;
use Drupal\Core\Session\AccountInterface;
......@@ -203,7 +204,7 @@ public static function fromRoute($route_name, $route_parameters = array(), $opti
*/
public static function fromUri($uri, $options = array()) {
if (!parse_url($uri, PHP_URL_SCHEME)) {
throw new \InvalidArgumentException('You must use a valid URI scheme. Use base:// for a path, e.g., to a Drupal file that needs the base path. Do not use this for internal paths controlled by Drupal.');
throw new \InvalidArgumentException(String::format('The URI "@uri" is invalid. You must use a valid URI scheme. Use base:// for a path, e.g., to a Drupal file that needs the base path. Do not use this for internal paths controlled by Drupal.', ['@uri' => $uri]));
}
$url = new static($uri, array(), $options);
......@@ -455,22 +456,16 @@ public function toString() {
*
* @return array
* An associative array containing all the properties of the route.
*
* @deprecated in Drupal 8.0.x-dev, will be removed before Drupal 9.0.
* Most usecases should use the URL object directly, like #type links. Other
* usecases should get the information from the URL object manually.
*/
public function toArray() {
if ($this->unrouted) {
return array(
// @todo Change 'path' to 'href': https://www.drupal.org/node/2347025.
'path' => $this->getUri(),
'options' => $this->getOptions(),
);
}
else {
return array(
'route_name' => $this->getRouteName(),
'route_parameters' => $this->getRouteParameters(),
'options' => $this->getOptions(),
);
}
return [
'url' => $this,
'options' => $this->getOptions(),
];
}
/**
......@@ -480,20 +475,14 @@ public function toArray() {
* An associative array suitable for a render array.
*/
public function toRenderArray() {
if ($this->unrouted) {
return array(
'#href' => $this->getUri(),
'#options' => $this->getOptions(),
);
}
else {
return array(
'#route_name' => $this->getRouteName(),
'#route_parameters' => $this->getRouteParameters(),
'#options' => $this->getOptions(),
'#access_callback' => array(get_class(), 'renderAccess'),
);
$render_array = [
'#url' => $this,
'#options' => $this->getOptions(),
];
if (!$this->unrouted) {
$render_array['#access_callback'] = [get_class(), 'renderAccess'];
}
return $render_array;
}
/**
......@@ -543,7 +532,7 @@ public function access(AccountInterface $account = NULL) {
* Returns TRUE if the current user has access to the url, otherwise FALSE.
*/
public static function renderAccess(array $element) {
return (new static($element['#route_name'], $element['#route_parameters'], $element['#options']))->access();
return $element['#url']->access();
}
/**
......
......@@ -109,7 +109,7 @@ public function generate($text, Url $url) {
// 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'])) {
if ($url->isRouted() && !isset($variables['options']['attributes']['data-drupal-link-system-path'])) {
// @todo System path is deprecated - use the route name and parameters.
$system_path = $url->getInternalPath();
// Special case for the front page.
......
......@@ -7,6 +7,7 @@
namespace Drupal\Core\Utility;
use Drupal\Component\Utility\String;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Config\ConfigFactoryInterface;
use Symfony\Component\HttpFoundation\RequestStack;
......@@ -56,7 +57,7 @@ public function assemble($uri, array $options = []) {
// UrlHelper::isExternal() only returns true for safe protocols.
return $this->buildExternalUrl($uri, $options);
}
throw new \InvalidArgumentException('You must use a valid URI scheme. Use base:// for a path e.g. to a Drupal file that needs the base path.');
throw new \InvalidArgumentException(String::format('The URI "@uri" is invalid. You must use a valid URI scheme. Use base:// for a path, e.g., to a Drupal file that needs the base path. Do not use this for internal paths controlled by Drupal.', ['@uri' => $uri]));
}
/**
......
......@@ -11,6 +11,7 @@
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Datetime\DateFormatter;
use Drupal\aggregator\FeedInterface;
use Drupal\Core\Url;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\DependencyInjection\ContainerInterface;
......@@ -128,25 +129,21 @@ public function adminOverview() {
$refresh_rate = $feed->getRefreshRate();
$row[] = ($last_checked ? $this->t('@time ago', array('@time' => $this->dateFormatter->formatInterval(REQUEST_TIME - $last_checked))) : $this->t('never'));
$row[] = ($last_checked && $refresh_rate ? $this->t('%time left', array('%time' => $this->dateFormatter->formatInterval($last_checked + $refresh_rate - REQUEST_TIME))) : $this->t('never'));
$links['edit'] = array(
$links['edit'] = [
'title' => $this->t('Edit'),
'route_name' => 'entity.aggregator_feed.edit_form',
'route_parameters' => array('aggregator_feed' => $feed->id()),
);
'url' => Url::fromRoute('entity.aggregator_feed.edit_form', ['aggregator_feed' => $feed->id()]),
];
$links['delete'] = array(
'title' => $this->t('Delete'),
'route_name' => 'entity.aggregator_feed.delete_form',
'route_parameters' => array('aggregator_feed' => $feed->id()),
'url' => Url::fromRoute('entity.aggregator_feed.delete_form', ['aggregator_feed' => $feed->id()]),
);
$links['delete_items'] = array(
'title' => $this->t('Delete items'),
'route_name' => 'aggregator.feed_items_delete',
'route_parameters' => array('aggregator_feed' => $feed->id()),
'url' => Url::fromRoute('aggregator.feed_items_delete', ['aggregator_feed' => $feed->id()]),
);
$links['update'] = array(
'title' => $this->t('Update items'),
'route_name' => 'aggregator.feed_refresh',
'route_parameters' => array('aggregator_feed' => $feed->id()),
'url' => Url::fromRoute('aggregator.feed_refresh', ['aggregator_feed' => $feed->id()])
);
$row[] = array(
'data' => array(
......
......@@ -12,6 +12,7 @@
use Drupal\Core\Entity\EntityViewBuilder;
use Drupal\Core\Config\Config;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
......@@ -99,7 +100,7 @@ public function buildComponents(array &$build, array $entities, array $displays,
$image_link = array(
'#type' => 'link',
'#title' => $link_title,
'#href' => $link_href,
'#url' => Url::fromUri($link_href),
'#options' => array(
'attributes' => array('class' => array('feed-image')),
'html' => TRUE,
......@@ -124,8 +125,7 @@ public function buildComponents(array &$build, array $entities, array $displays,
'#title' => t('More<span class="visually-hidden"> posts about @title</span>', array(
'@title' => $title_stripped,
)),
'#route_name' => 'entity.aggregator_feed.canonical',
'#route_parameters' => array('aggregator_feed' => $entity->id()),
'#url' => Url::fromRoute('entity.aggregator_feed.canonical', ['aggregator_feed' => $entity->id()]),
'#options' => array(
'html' => TRUE,
'attributes' => array(
......
......@@ -120,7 +120,7 @@ public function refresh(FeedInterface $feed) {
// Parse the feed.
try {
if ($this->parserManager->createInstance($this->config->get('parser'))->parse($feed)) {
if ($feed->getWebsiteUrl()) {
if (!$feed->getWebsiteUrl()) {
$feed->setWebsiteUrl($feed->getUrl());
}
$feed->setHash($hash);
......
......@@ -164,7 +164,7 @@ public function build() {
$more_link = array(
'#type' => 'more_link',
'#href' => 'aggregator/sources/' . $feed->id(),
'#url' => $feed->urlInfo(),
'#attributes' => array('title' => $this->t("View this feed's recent news.")),
);
$read_more = drupal_render($more_link);
......
......@@ -18,6 +18,7 @@ class AddFeedTest extends AggregatorTestBase {
*/
function testAddFeed() {
$feed = $this->createFeed();