/** * {@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_attachments(). * * @see system_page_attachments() */ public function generate($text, Url $url, $collect_cacheability_metadata = FALSE) { // Performance: avoid Url::toString() needing to retrieve the URL generator // service from the container. $url->setUrlGenerator($this->urlGenerator); // Start building a structured representation of our link to be altered later. $variables = array('text' => is_array($text) ? drupal_render($text) : $text, 'url' => $url, 'options' => $url->getOptions()); // Merge in default options. $variables['options'] += array('attributes' => array(), 'query' => array(), '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']->getId(); } // Set the "active" class if the 'set_active_class' option is not empty. if (!empty($variables['options']['set_active_class']) && !$url->isExternal()) { // 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']; ksort($query); $variables['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 ($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. $variables['options']['attributes']['data-drupal-link-system-path'] = $system_path == '' ? '<front>' : $system_path; } } // 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']); } // Allow other modules to modify the structure of the link. $this->moduleHandler->alter('link', $variables); // Move attributes out of options since generateFromRoute() doesn't need // them. Include a placeholder for the href. $attributes = array('href' => '') + $variables['options']['attributes']; unset($variables['options']['attributes']); $url->setOptions($variables['options']); if (!$collect_cacheability_metadata) { $url_string = $url->toString($collect_cacheability_metadata); } else { $generated_url = $url->toString($collect_cacheability_metadata); $url_string = $generated_url->getGeneratedUrl(); $generated_link = GeneratedLink::createFromObject($generated_url); } // The result of the URL generator is a plain-text URL to use as the href // attribute, and it is escaped by \Drupal\Core\Template\Attribute. $attributes['href'] = $url_string; $result = SafeMarkup::format('<a@attributes>@text</a>', array('@attributes' => new Attribute($attributes), '@text' => $variables['text'])); return $collect_cacheability_metadata ? $generated_link->setGeneratedLink($result) : $result; }
/** * {@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_attachments(). * * @see system_page_attachments() */ public function generate($text, Url $url) { // Performance: avoid Url::toString() needing to retrieve the URL generator // service from the container. $url->setUrlGenerator($this->urlGenerator); // Start building a structured representation of our link to be altered later. $variables = array('text' => is_array($text) ? drupal_render($text) : $text, 'url' => $url, 'options' => $url->getOptions()); // Merge in default options. $variables['options'] += array('attributes' => array(), 'query' => array(), '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']->getId(); } // Set the "active" class if the 'set_active_class' option is not empty. if (!empty($variables['options']['set_active_class']) && !$url->isExternal()) { // 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']; ksort($query); $variables['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 ($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. $variables['options']['attributes']['data-drupal-link-system-path'] = $system_path == '' ? '<front>' : $system_path; } } // 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']); } // Allow other modules to modify the structure of the link. $this->moduleHandler->alter('link', $variables); // 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($url->toString()); // Make sure the link text is sanitized. $safe_text = SafeMarkup::escape($variables['text']); return SafeMarkup::set('<a href="' . $url . '"' . $attributes . '>' . $safe_text . '</a>'); }
/** * Builds an a absolute URL from a system path or a URL object. * * @param string|\Drupal\Core\Url $path * A system path or a URL. * @param array $options * Options to be passed to Url::fromUri(). * * @return string * An absolute URL stsring. */ protected function buildUrl($path, array $options = array()) { if ($path instanceof Url) { $url_options = $path->getOptions(); $options = $url_options + $options; $path->setOptions($options); return $path->setAbsolute()->toString(); } elseif ($this->container->has('url_generator')) { $force_internal = isset($options['external']) && $options['external'] == FALSE; if (!$force_internal && UrlHelper::isExternal($path)) { return Url::fromUri($path, $options)->toString(); } else { $uri = $path === '<front>' ? 'base:/' : 'base:/' . $path; // Path processing is needed for language prefixing. Skip it when a // path that may look like an external URL is being used as internal. $options['path_processing'] = !$force_internal; return Url::fromUri($uri, $options)->setAbsolute()->toString(); } } else { return $this->getAbsoluteUrl($path); } }
/** * Tests link rendering with a URL and options. * * @dataProvider providerTestRenderAsLinkWithUrlAndOptions * @covers ::renderAsLink */ public function testRenderAsLinkWithUrlAndOptions(Url $url, $alter, Url $expected_url, $url_path, Url $expected_link_url, $link_html, $final_html = NULL) { $alter += ['make_link' => TRUE, 'url' => $url]; $final_html = isset($final_html) ? $final_html : $link_html; $this->setUpUrlIntegrationServices(); $this->setupDisplayWithEmptyArgumentsAndFields(); $field = $this->setupTestField(['alter' => $alter]); $field->field_alias = 'key'; $row = new ResultRow(['key' => 'value']); $expected_url->setOptions($expected_url->getOptions() + $this->defaultUrlOptions); $expected_link_url->setUrlGenerator($this->urlGenerator); $expected_url_options = $expected_url->getOptions(); unset($expected_url_options['attributes']); $this->urlGenerator->expects($this->once())->method('generateFromRoute')->with($expected_url->getRouteName(), $expected_url->getRouteParameters(), $expected_url_options)->willReturn($url_path); $result = $field->advancedRender($row); $this->assertEquals($final_html, $result); }
/** * Builds an a absolute URL from a system path or a URL object. * * @param string|\Drupal\Core\Url $path * A system path or a URL. * @param array $options * Options to be passed to Url::fromUri(). * * @return string * An absolute URL stsring. */ protected function buildUrl($path, array $options = array()) { if ($path instanceof Url) { $url_options = $path->getOptions(); $options = $url_options + $options; $path->setOptions($options); return $path->setAbsolute()->toString(); } else { if ($this->container->has('url_generator')) { $options['absolute'] = TRUE; return $this->container->get('url_generator')->generateFromPath($path, $options); } else { return $this->getAbsoluteUrl($path); } } }
/** * Tests the getOptions() method. * * @depends testCreateFromPath * * @covers ::getOptions() */ public function testGetOptions(Url $url) { $this->assertInternalType('array', $url->getOptions()); }
/** * {@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_attachments(). * * @see system_page_attachments() */ public function generate($text, Url $url) { // Performance: avoid Url::toString() needing to retrieve the URL generator // service from the container. $url->setUrlGenerator($this->urlGenerator); if (is_array($text)) { $text = $this->renderer->render($text); } // Start building a structured representation of our link to be altered later. $variables = array('text' => $text, 'url' => $url, 'options' => $url->getOptions()); // Merge in default options. $variables['options'] += array('attributes' => array(), 'query' => array(), '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']->getId(); } // Ensure that query values are strings. array_walk($variables['options']['query'], function (&$value) { if ($value instanceof MarkupInterface) { $value = (string) $value; } }); // Set the "active" class if the 'set_active_class' option is not empty. if (!empty($variables['options']['set_active_class']) && !$url->isExternal()) { // 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']; ksort($query); $variables['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 ($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. $variables['options']['attributes']['data-drupal-link-system-path'] = $system_path == '' ? '<front>' : $system_path; } } // 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']); } // Allow other modules to modify the structure of the link. $this->moduleHandler->alter('link', $variables); $url = $variables['url']; // Move attributes out of options since generateFromRoute() doesn't need // them. Make sure the "href" comes first for testing purposes. $attributes = array('href' => '') + $variables['options']['attributes']; unset($variables['options']['attributes']); $url->setOptions($variables['options']); // External URLs can not have cacheable metadata. if ($url->isExternal()) { $generated_link = new GeneratedLink(); $attributes['href'] = $url->toString(FALSE); } elseif ($url->isRouted() && $url->getRouteName() === '<nolink>') { $generated_link = new GeneratedNoLink(); unset($attributes['href']); } else { $generated_url = $url->toString(TRUE); $generated_link = GeneratedLink::createFromObject($generated_url); // The result of the URL generator is a plain-text URL to use as the href // attribute, and it is escaped by \Drupal\Core\Template\Attribute. $attributes['href'] = $generated_url->getGeneratedUrl(); } if (!$variables['text'] instanceof MarkupInterface) { $variables['text'] = Html::escape($variables['text']); } $attributes = new Attribute($attributes); // This is safe because Attribute does escaping and $variables['text'] is // either rendered or escaped. return $generated_link->setGeneratedLink('<' . $generated_link::TAG . $attributes . '>' . $variables['text'] . '</' . $generated_link::TAG . '>'); }
/** * Retrieves a Drupal path or an absolute path. * * @param string|\Drupal\Core\Url $path * Drupal path or URL to load into Mink controlled browser. * @param array $options * (optional) Options to be forwarded to the url generator. * * @return string * The retrieved HTML string, also available as $this->getRawContent() */ protected function drupalGet($path, array $options = array()) { $options['absolute'] = TRUE; if ($path instanceof Url) { $url_options = $path->getOptions(); $options = $url_options + $options; $path->setOptions($options); $url = $path->setAbsolute()->toString(); } // The URL generator service is not necessarily available yet; e.g., in // interactive installer tests. elseif ($this->container->has('url_generator')) { if (UrlHelper::isExternal($path)) { $url = Url::fromUri($path, $options)->toString(); } else { // This is needed for language prefixing. $options['path_processing'] = TRUE; $url = Url::fromUri('base:/' . $path, $options)->toString(); } } else { $url = $this->getAbsoluteUrl($path); } $session = $this->getSession(); $this->prepareRequest(); $session->visit($url); $out = $session->getPage()->getContent(); // Ensure that any changes to variables in the other thread are picked up. $this->refreshVariables(); if ($this->htmlOutputEnabled) { $html_output = 'GET request to: ' . $url . '<hr />Ending URL: ' . $this->getSession()->getCurrentUrl(); $html_output .= '<hr />' . $out; $html_output .= $this->getHtmlOutputHeaders(); $this->htmlOutput($html_output); } return $out; }