/** * {@inheritdoc} */ protected function preprocessVariables(Variables $variables, $hook, array $info) { // Retrieve the ID, generating one if needed. $id = $variables->getAttribute('id', Html::getUniqueId($variables->offsetGet('id', 'bootstrap-carousel'))); unset($variables['id']); // Build slides. foreach ($variables->slides as $key => &$slide) { if (!isset($slide['attributes'])) { $slide['attributes'] = []; } $slide['attributes'] = new Attribute($slide['attributes']); } // Build controls. if ($variables->controls) { $left_icon = Bootstrap::glyphicon('chevron-left'); $right_icon = Bootstrap::glyphicon('chevron-right'); $url = Url::fromUserInput("#{$id}"); $variables->controls = ['left' => ['#type' => 'link', '#title' => new FormattableMarkup(Element::create($left_icon)->render() . '<span class="sr-only">@text</span>', ['@text' => t('Previous')]), '#url' => $url, '#attributes' => ['class' => ['left', 'carousel-control'], 'role' => 'button', 'data-slide' => 'prev']], 'right' => ['#type' => 'link', '#title' => new FormattableMarkup(Element::create($right_icon)->render() . '<span class="sr-only">@text</span>', ['@text' => t('Next')]), '#url' => $url, '#attributes' => ['class' => ['right', 'carousel-control'], 'role' => 'button', 'data-slide' => 'next']]]; } // Build indicators. if ($variables->indicators) { $variables->indicators = ['#theme' => 'item_list__bootstrap_carousel_indicators', '#list_type' => 'ol', '#items' => array_keys($variables->slides), '#target' => "#{$id}", '#start_index' => $variables->start_index]; } // Ensure all attributes are proper objects. $this->preprocessAttributes($variables, $hook, $info); }
/** * {@inheritdoc} * * Find the parent link GUID. */ public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) { $parent_id = array_shift($value); if (!$parent_id) { // Top level item. return ''; } try { $already_migrated_id = $this->migrationPlugin->transform($parent_id, $migrate_executable, $row, $destination_property); if ($already_migrated_id && ($link = $this->menuLinkStorage->load($already_migrated_id))) { return $link->getPluginId(); } } catch (MigrateSkipRowException $e) { } if (isset($value[1])) { list($menu_name, $parent_link_path) = $value; $url = Url::fromUserInput("/{$parent_link_path}"); if ($url->isRouted()) { $links = $this->menuLinkManager->loadLinksByRoute($url->getRouteName(), $url->getRouteParameters(), $menu_name); if (count($links) == 1) { /** @var \Drupal\Core\Menu\MenuLinkInterface $link */ $link = reset($links); return $link->getPluginId(); } } } throw new MigrateSkipRowException(); }
public function get_custom_links($custom_paths, $language) { $links = array(); foreach ($custom_paths as $custom_path) { if ($custom_path['index']) { $links[] = SitemapGenerator::add_xml_link_markup(Url::fromUserInput($custom_path['path'], array('language' => $language, 'absolute' => TRUE))->toString(), $custom_path['priority']); } } return $links; }
/** * {@inheritdoc} */ public function render(ResultRow $values) { $value = $this->getValue($values); if (!empty($this->options['display_as_link'])) { // @todo Views should expect and store a leading /. See: // https://www.drupal.org/node/2423913 return \Drupal::l($this->sanitizeValue($value), CoreUrl::fromUserInput('/' . $value)); } else { return $this->sanitizeValue($value, 'url'); } }
/** * Gets the displayable path of a page entity. * * @param \Drupal\page_manager\PageInterface $entity * The page entity. * * @return array|string * The value of the path. */ protected function getPath(PageInterface $entity) { // If the page is enabled and not dynamic, show the path as a link, // otherwise as plain text. $path = $entity->getPath(); if ($entity->status() && strpos($path, '%') === FALSE) { return ['data' => ['#type' => 'link', '#url' => Url::fromUserInput(rtrim($path, '/')), '#title' => $path]]; } else { return $path; } }
/** * Confirms that invalid URLs are filtered in link generating functions. */ function testLinkXSS() { // Test \Drupal::l(). $text = $this->randomMachineName(); $path = "<SCRIPT>alert('XSS')</SCRIPT>"; $encoded_path = "3CSCRIPT%3Ealert%28%27XSS%27%29%3C/SCRIPT%3E"; $link = \Drupal::l($text, Url::fromUserInput('/' . $path)); $this->assertTrue(strpos($link, $encoded_path) !== FALSE && strpos($link, $path) === FALSE, format_string('XSS attack @path was filtered by \\Drupal\\Core\\Utility\\LinkGeneratorInterface::generate().', array('@path' => $path))); // Test \Drupal\Core\Url. $link = Url::fromUri('base:' . $path)->toString(); $this->assertTrue(strpos($link, $encoded_path) !== FALSE && strpos($link, $path) === FALSE, format_string('XSS attack @path was filtered by #theme', ['@path' => $path])); }
/** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { if (!$form_state->isValueEmpty('redirection')) { if (!$form_state->isValueEmpty('destination')) { // The destination is a random URL, so we can't use routed URLs. // @todo Revist this in https://www.drupal.org/node/2418219. $form_state->setRedirectUrl(Url::fromUserInput('/' . $form_state->getValue('destination'))); } } else { $form_state->disableRedirect(); } }
/** * Confirms that invalid URLs are filtered in link generating functions. */ function testLinkXSS() { // Test \Drupal::l(). $text = $this->randomMachineName(); $path = "<SCRIPT>alert('XSS')</SCRIPT>"; $link = \Drupal::l($text, Url::fromUserInput('/' . $path)); $sanitized_path = check_url(Url::fromUri('base:' . $path)->toString()); $this->assertTrue(strpos($link, $sanitized_path) !== FALSE, format_string('XSS attack @path was filtered by _l().', array('@path' => $path))); // Test \Drupal\Core\Url. $link = Url::fromUri('base:' . $path)->toString(); $sanitized_path = check_url(Url::fromUri('base:' . $path)->toString()); $this->assertTrue(strpos($link, $sanitized_path) !== FALSE, format_string('XSS attack @path was filtered by #theme', ['@path' => $path])); }
/** * Builds the cancel link for a confirmation form. * * @param \Drupal\Core\Form\ConfirmFormInterface $form * The confirmation form. * @param \Symfony\Component\HttpFoundation\Request $request * The current request. * * @return array * The link render array for the cancel form. */ public static function buildCancelLink(ConfirmFormInterface $form, Request $request) { // Prepare cancel link. $query = $request->query; // If a destination is specified, that serves as the cancel link. if ($query->has('destination')) { $options = UrlHelper::parse($query->get('destination')); // @todo Revisit this in https://www.drupal.org/node/2418219. $url = Url::fromUserInput('/' . $options['path'], $options); } else { $url = $form->getCancelUrl(); } return ['#type' => 'link', '#title' => $form->getCancelText(), '#attributes' => ['class' => ['button']], '#url' => $url]; }
/** * {@inheritdoc} */ public function getUrlObject($title_attribute = TRUE) { if ($this->getEntity()->getUrlObject()) { $options = $this->getOptions(); if ($title_attribute && ($description = $this->getDescription())) { $options['attributes']['title'] = $description; } if (empty($this->pluginDefinition['url'])) { return new Url($this->pluginDefinition['route_name'], $this->pluginDefinition['route_parameters'], $options); } else { return Url::fromUri($this->pluginDefinition['url'], $options); } } else { // Because the edit link has custom access control we need to return a link the anon user has access to. return Url::fromUserInput('/'); } }
/** * {@inheritdoc} */ public function preprocessVariables(Variables $variables, $hook, array $info) { if (!empty($variables['description'])) { $variables['description'] = FieldFilteredMarkup::create($variables['description']); } $descriptions = []; $cardinality = $variables['cardinality']; if (isset($cardinality)) { if ($cardinality == -1) { $descriptions[] = t('Unlimited number of files can be uploaded to this field.'); } else { $descriptions[] = \Drupal::translation()->formatPlural($cardinality, 'One file only.', 'Maximum @count files.'); } } $upload_validators = $variables['upload_validators']; if (isset($upload_validators['file_validate_size'])) { $descriptions[] = t('@size limit.', ['@size' => format_size($upload_validators['file_validate_size'][0])]); } if (isset($upload_validators['file_validate_extensions'])) { $extensions = new FormattableMarkup('<code>@extensions</code>', ['@extensions' => implode(', ', explode(' ', $upload_validators['file_validate_extensions'][0]))]); $descriptions[] = t('Allowed types: @extensions.', ['@extensions' => $extensions]); } if (isset($upload_validators['file_validate_image_resolution'])) { $max = $upload_validators['file_validate_image_resolution'][0]; $min = $upload_validators['file_validate_image_resolution'][1]; if ($min && $max && $min == $max) { $descriptions[] = t('Images must be exactly <strong>@size</strong> pixels.', ['@size' => $max]); } elseif ($min && $max) { $descriptions[] = t('Images must be larger than <strong>@min</strong> pixels. Images larger than <strong>@max</strong> pixels will be resized.', ['@min' => $min, '@max' => $max]); } elseif ($min) { $descriptions[] = t('Images must be larger than <strong>@min</strong> pixels.', ['@min' => $min]); } elseif ($max) { $descriptions[] = t('Images larger than <strong>@max</strong> pixels will be resized.', ['@max' => $max]); } } $variables['descriptions'] = $descriptions; if ($descriptions) { $build = array(); $id = Html::getUniqueId('upload-instructions'); $build['toggle'] = ['#type' => 'link', '#title' => t('Upload requirements'), '#url' => Url::fromUserInput("#{$id}"), '#icon' => Bootstrap::glyphicon('question-sign'), '#attributes' => ['class' => ['icon-before'], 'data-toggle' => 'popover', 'data-html' => 'true', 'data-placement' => 'bottom', 'data-title' => t('Upload requirements')]]; $build['requirements'] = ['#type' => 'container', '#theme_wrappers' => ['container__file_upload_help'], '#attributes' => ['id' => $id, 'class' => ['hidden', 'help-block'], 'aria-hidden' => 'true']]; $build['requirements']['descriptions'] = ['#theme' => 'item_list__file_upload_help', '#items' => $descriptions]; $variables['popover'] = $build; } }
/** * Returns the next redirect path in a multipage sequence. * * @param array $destinations * An array of destinations to redirect to. * * @return \Drupal\Core\Url * The next destination to redirect to. */ public static function getNextDestination(array $destinations) { $next_destination = array_shift($destinations); if (is_array($next_destination)) { $next_destination['options']['query']['destinations'] = $destinations; $next_destination += array('route_parameters' => array()); $next_destination = Url::fromRoute($next_destination['route_name'], $next_destination['route_parameters'], $next_destination['options']); } else { $options = UrlHelper::parse($next_destination); if ($destinations) { $options['query']['destinations'] = $destinations; } // Redirect to any given path within the same domain. // @todo Revisit this in https://www.drupal.org/node/2418219. $next_destination = Url::fromUserInput('/' . $options['path']); } return $next_destination; }
/** * Index. * @param \Drupal\user\UserInterface $user * @return array * @throws \Exception * @internal param string $uid */ public function index(UserInterface $user) { // See if the user already has an API key. $q = $this->database->select('api_keys', 'a')->fields('a'); $q->condition('a.uid', $user->id()); $user_key_object = $q->execute()->fetchObject(); if (!$user_key_object) { // The user does not have a key. Generate one for them. $user_key = sha1(uniqid()); // Insert it to the database. $this->database->insert('api_keys')->fields(array('uid' => $user->id(), 'user_key' => $user_key))->execute(); } else { $user_key = $user_key_object->user_key; } // Generate the URL which we should use in the CURL explaination. // @todo return ['#theme' => 'api-keys-user-keys', '#api_key' => $user_key, '#post_url' => 'example.com/entity/log', '#base_url' => Url::fromUserInput('/')->setOption('absolute', TRUE), '#markup' => $this->t('URL : !url and key: !key', ['!url' => $post_url, '!key' => $user_key])]; }
/** * Displays the path administration overview page. * * @param \Symfony\Component\HttpFoundation\Request $request * The request object. * * @return array * A render array as expected by drupal_render(). */ public function adminOverview(Request $request) { $keys = $request->query->get('search'); // Add the filter form above the overview table. $build['path_admin_filter_form'] = $this->formBuilder()->getForm('Drupal\\path\\Form\\PathFilterForm', $keys); // Enable language column if language.module is enabled or if we have any // alias with a language. $multilanguage = $this->moduleHandler()->moduleExists('language') || $this->aliasStorage->languageAliasExists(); $header = array(); $header[] = array('data' => $this->t('Alias'), 'field' => 'alias', 'sort' => 'asc'); $header[] = array('data' => $this->t('System'), 'field' => 'source'); if ($multilanguage) { $header[] = array('data' => $this->t('Language'), 'field' => 'langcode'); } $header[] = $this->t('Operations'); $rows = array(); $destination = $this->getDestinationArray(); foreach ($this->aliasStorage->getAliasesForAdminListing($header, $keys) as $data) { $row = array(); // @todo Should Path module store leading slashes? See // https://www.drupal.org/node/2430593. $row['data']['alias'] = $this->l(Unicode::truncate($data->alias, 50, FALSE, TRUE), Url::fromUserInput($data->source, array('attributes' => array('title' => $data->alias)))); $row['data']['source'] = $this->l(Unicode::truncate($data->source, 50, FALSE, TRUE), Url::fromUserInput($data->source, array('alias' => TRUE, 'attributes' => array('title' => $data->source)))); if ($multilanguage) { $row['data']['language_name'] = $this->languageManager()->getLanguageName($data->langcode); } $operations = array(); $operations['edit'] = array('title' => $this->t('Edit'), 'url' => Url::fromRoute('path.admin_edit', ['pid' => $data->pid], ['query' => $destination])); $operations['delete'] = array('title' => $this->t('Delete'), 'url' => Url::fromRoute('path.delete', ['pid' => $data->pid], ['query' => $destination])); $row['data']['operations'] = array('data' => array('#type' => 'operations', '#links' => $operations)); // If the system path maps to a different URL alias, highlight this table // row to let the user know of old aliases. if ($data->alias != $this->aliasManager->getAliasByPath($data->source, $data->langcode)) { $row['class'] = array('warning'); } $rows[] = $row; } $build['path_table'] = array('#type' => 'table', '#header' => $header, '#rows' => $rows, '#empty' => $this->t('No URL aliases available. <a href=":link">Add URL alias</a>.', array(':link' => $this->url('path.admin_add')))); $build['path_pager'] = array('#type' => 'pager'); return $build; }
public function submitForm(array &$form, FormStateInterface $form_state) { try { if (!empty($form_state->getBuildInfo()['args'][0]) && !empty($form_state->getBuildInfo()['args'][1])) { $smfSessionId = $form_state->getBuildInfo()['args'][0]; /** * @var \Drupal\smfbridge\Smf\Member $smfMember */ $smfMember = \Drupal::service('smfbridge.smfmember'); if ($smfMember->setAdminTime($smfSessionId)) { $form_state->setRedirectUrl(Url::fromUserInput($form_state->getBuildInfo()['args'][1])); } else { throw new \Exception($this->t('Failed to get access to SMF admin area.')); } } else { throw new \Exception($this->t('Failed to get access to SMF admin area.')); } } catch (\Exception $e) { drupal_set_message($e->getMessage(), 'error'); } }
/** * Builds the cancel link for a confirmation form. * * @param \Drupal\Core\Form\ConfirmFormInterface $form * The confirmation form. * @param \Symfony\Component\HttpFoundation\Request $request * The current request. * * @return array * The link render array for the cancel form. */ public static function buildCancelLink(ConfirmFormInterface $form, Request $request) { // Prepare cancel link. $query = $request->query; $url = NULL; // If a destination is specified, that serves as the cancel link. if ($query->has('destination')) { $options = UrlHelper::parse($query->get('destination')); // @todo Revisit this in https://www.drupal.org/node/2418219. try { $url = Url::fromUserInput('/' . ltrim($options['path'], '/'), $options); } catch (\InvalidArgumentException $e) { // Suppress the exception and fall back to the form's cancel url. } } // Check for a route-based cancel link. if (!$url) { $url = $form->getCancelUrl(); } return ['#type' => 'link', '#title' => $form->getCancelText(), '#attributes' => ['class' => ['button']], '#url' => $url]; }
/** * Render this field as a link, with the info from a fieldset set by * the user. */ protected function renderAsLink($alter, $text, $tokens) { $options = array('absolute' => !empty($alter['absolute']) ? TRUE : FALSE, 'alias' => FALSE, 'entity' => NULL, 'entity_type' => NULL, 'fragment' => NULL, 'language' => NULL, 'query' => []); $alter += ['path' => NULL]; $path = $alter['path']; if (empty($alter['url'])) { if (!parse_url($path, PHP_URL_SCHEME)) { // @todo Views should expect and store a leading /. See // https://www.drupal.org/node/2423913. $alter['url'] = CoreUrl::fromUserInput('/' . ltrim($path, '/')); } else { $alter['url'] = CoreUrl::fromUri($path); } } $options = $alter['url']->getOptions() + $options; $path = $alter['url']->setOptions($options)->toUriString(); // strip_tags() removes <front>, so check whether its different to front. if ($path != 'route:<front>') { // Unescape Twig delimiters that may have been escaped by the // Url::toUriString() call above, because we support twig tokens in // rewrite settings of views fields. // In that case the original path looks like // internal:/admin/content/files/usage/{{ fid }}, which will be escaped by // the toUriString() call above. $path = preg_replace(['/(\\%7B){2}(\\%20)*/', '/(\\%20)*(\\%7D){2}/'], ['{{', '}}'], $path); // Use strip tags as there should never be HTML in the path. // However, we need to preserve special characters like " that // were removed by SafeMarkup::checkPlain(). $path = strip_tags(Html::decodeEntities($this->viewsTokenReplace($path, $tokens))); if (!empty($alter['path_case']) && $alter['path_case'] != 'none' && !$alter['url']->isRouted()) { $path = str_replace($alter['path'], $this->caseTransform($alter['path'], $this->options['alter']['path_case']), $path); } if (!empty($alter['replace_spaces'])) { $path = str_replace(' ', '-', $path); } } // Parse the URL and move any query and fragment parameters out of the path. $url = UrlHelper::parse($path); // Seriously malformed URLs may return FALSE or empty arrays. if (empty($url)) { return $text; } // If the path is empty do not build a link around the given text and return // it as is. // http://www.example.com URLs will not have a $url['path'], so check host as well. if (empty($url['path']) && empty($url['host']) && empty($url['fragment']) && empty($url['url'])) { return $text; } // If we get to here we have a path from the url parsing. So assign that to // $path now so we don't get query strings or fragments in the path. $path = $url['path']; // If no scheme is provided in the $path, assign the default 'http://'. // This allows a url of 'www.example.com' to be converted to 'http://www.example.com'. // Only do this on for external URLs. if ($alter['external']) { if (!isset($url['scheme'])) { // There is no scheme, add the default 'http://' to the $path. // Use the original $alter['path'] instead of the parsed version. $path = "http://" . $alter['path']; // Reset the $url array to include the new scheme. $url = UrlHelper::parse($path); } } if (isset($url['query'])) { // Remove query parameters that were assigned a query string replacement // token for which there is no value available. foreach ($url['query'] as $param => $val) { if ($val == '%' . $param) { unset($url['query'][$param]); } // Replace any empty query params from URL parsing with NULL. So the // query will get built correctly with only the param key. // @see \Drupal\Component\Utility\UrlHelper::buildQuery(). if ($val === '') { $url['query'][$param] = NULL; } } $options['query'] = $url['query']; } if (isset($url['fragment'])) { $path = strtr($path, array('#' . $url['fragment'] => '')); // If the path is empty we want to have a fragment for the current site. if ($path == '') { $options['external'] = TRUE; } $options['fragment'] = $url['fragment']; } $alt = $this->viewsTokenReplace($alter['alt'], $tokens); // Set the title attribute of the link only if it improves accessibility if ($alt && $alt != $text) { $options['attributes']['title'] = Html::decodeEntities($alt); } $class = $this->viewsTokenReplace($alter['link_class'], $tokens); if ($class) { $options['attributes']['class'] = array($class); } if (!empty($alter['rel']) && ($rel = $this->viewsTokenReplace($alter['rel'], $tokens))) { $options['attributes']['rel'] = $rel; } // Not sure if this SafeMarkup::checkPlain() is needed here? $target = SafeMarkup::checkPlain(trim($this->viewsTokenReplace($alter['target'], $tokens))); if (!empty($target)) { $options['attributes']['target'] = $target; } // Allow the addition of arbitrary attributes to links. Additional attributes // currently can only be altered in preprocessors and not within the UI. if (isset($alter['link_attributes']) && is_array($alter['link_attributes'])) { foreach ($alter['link_attributes'] as $key => $attribute) { if (!isset($options['attributes'][$key])) { $options['attributes'][$key] = $this->viewsTokenReplace($attribute, $tokens); } } } // If the query and fragment were programmatically assigned overwrite any // parsed values. if (isset($alter['query'])) { // Convert the query to a string, perform token replacement, and then // convert back to an array form for _l(). $options['query'] = UrlHelper::buildQuery($alter['query']); $options['query'] = $this->viewsTokenReplace($options['query'], $tokens); $query = array(); parse_str($options['query'], $query); $options['query'] = $query; } if (isset($alter['alias'])) { // Alias is a boolean field, so no token. $options['alias'] = $alter['alias']; } if (isset($alter['fragment'])) { $options['fragment'] = $this->viewsTokenReplace($alter['fragment'], $tokens); } if (isset($alter['language'])) { $options['language'] = $alter['language']; } // If the url came from entity_uri(), pass along the required options. if (isset($alter['entity'])) { $options['entity'] = $alter['entity']; } if (isset($alter['entity_type'])) { $options['entity_type'] = $alter['entity_type']; } // The path has been heavily processed above, so it should be used as-is. $final_url = CoreUrl::fromUri($path, $options); // Build the link based on our altered Url object, adding on the optional // prefix and suffix $value = ''; if (!empty($alter['prefix'])) { $value .= Xss::filterAdmin($this->viewsTokenReplace($alter['prefix'], $tokens)); } $value .= $this->linkGenerator()->generate($text, $final_url); if (!empty($alter['suffix'])) { $value .= Xss::filterAdmin($this->viewsTokenReplace($alter['suffix'], $tokens)); } return $value; }
/** * Tests the generate() method with a url containing double quotes. * * @covers ::generate */ public function testGenerateUrlWithQuotes() { $this->urlAssembler->expects($this->once())->method('assemble')->with('base:example', array('query' => array('foo' => '"bar"', 'zoo' => 'baz')) + $this->defaultOptions)->willReturn((new GeneratedUrl())->setGeneratedUrl('/example?foo=%22bar%22&zoo=baz')); $path_validator = $this->getMock('Drupal\\Core\\Path\\PathValidatorInterface'); $container_builder = new ContainerBuilder(); $container_builder->set('path.validator', $path_validator); \Drupal::setContainer($container_builder); $path = '/example?foo="bar"&zoo=baz'; $url = Url::fromUserInput($path); $url->setUrlGenerator($this->urlGenerator); $url->setUnroutedUrlAssembler($this->urlAssembler); $result = $this->linkGenerator->generate('Drupal', $url); $this->assertLink(array('attributes' => array('href' => '/example?foo=%22bar%22&zoo=baz'), 'content' => 'Drupal'), $result, 1); }
/** * Render this field as a link, with the info from a fieldset set by * the user. */ protected function renderAsLink($alter, $text, $tokens) { $options = array( 'absolute' => !empty($alter['absolute']) ? TRUE : FALSE, 'alias' => FALSE, 'entity' => NULL, 'entity_type' => NULL, 'fragment' => NULL, 'language' => NULL, 'query' => [], ); $alter += [ 'path' => NULL ]; $path = $alter['path']; // strip_tags() and viewsTokenReplace remove <front>, so check whether it's // different to front. if ($path != '<front>') { // Use strip_tags as there should never be HTML in the path. // However, we need to preserve special characters like " that were // removed by SafeMarkup::checkPlain(). $path = Html::decodeEntities($this->viewsTokenReplace($alter['path'], $tokens)); // Tokens might contain <front>, so check for <front> again. if ($path != '<front>') { $path = strip_tags($path); } // Tokens might have resolved URL's, as is the case for tokens provided by // Link fields, so all internal paths will be prefixed by base_path(). For // proper further handling reset this to internal:/. if (strpos($path, base_path()) === 0) { $path = 'internal:/' . substr($path, strlen(base_path())); } // If we have no $path and no $alter['url'], we have nothing to work with, // so we just return the text. if (empty($path) && empty($alter['url'])) { return $text; } // If no scheme is provided in the $path, assign the default 'http://'. // This allows a url of 'www.example.com' to be converted to // 'http://www.example.com'. // Only do this when flag for external has been set, $path doesn't contain // a scheme and $path doesn't have a leading /. if ($alter['external'] && !parse_url($path, PHP_URL_SCHEME) && strpos($path, '/') !== 0) { // There is no scheme, add the default 'http://' to the $path. $path = "http://" . $path; } } if (empty($alter['url'])) { if (!parse_url($path, PHP_URL_SCHEME)) { // @todo Views should expect and store a leading /. See // https://www.drupal.org/node/2423913. $alter['url'] = CoreUrl::fromUserInput('/' . ltrim($path, '/')); } else { $alter['url'] = CoreUrl::fromUri($path); } } $options = $alter['url']->getOptions() + $options; $path = $alter['url']->setOptions($options)->toUriString(); if (!empty($alter['path_case']) && $alter['path_case'] != 'none' && !$alter['url']->isRouted()) { $path = str_replace($alter['path'], $this->caseTransform($alter['path'], $this->options['alter']['path_case']), $path); } if (!empty($alter['replace_spaces'])) { $path = str_replace(' ', '-', $path); } // Parse the URL and move any query and fragment parameters out of the path. $url = UrlHelper::parse($path); // Seriously malformed URLs may return FALSE or empty arrays. if (empty($url)) { return $text; } // If the path is empty do not build a link around the given text and return // it as is. // http://www.example.com URLs will not have a $url['path'], so check host as well. if (empty($url['path']) && empty($url['host']) && empty($url['fragment']) && empty($url['url'])) { return $text; } // If we get to here we have a path from the url parsing. So assign that to // $path now so we don't get query strings or fragments in the path. $path = $url['path']; if (isset($url['query'])) { // Remove query parameters that were assigned a query string replacement // token for which there is no value available. foreach ($url['query'] as $param => $val) { if ($val == '%' . $param) { unset($url['query'][$param]); } // Replace any empty query params from URL parsing with NULL. So the // query will get built correctly with only the param key. // @see \Drupal\Component\Utility\UrlHelper::buildQuery(). if ($val === '') { $url['query'][$param] = NULL; } } $options['query'] = $url['query']; } if (isset($url['fragment'])) { $path = strtr($path, array('#' . $url['fragment'] => '')); // If the path is empty we want to have a fragment for the current site. if ($path == '') { $options['external'] = TRUE; } $options['fragment'] = $url['fragment']; } $alt = $this->viewsTokenReplace($alter['alt'], $tokens); // Set the title attribute of the link only if it improves accessibility if ($alt && $alt != $text) { $options['attributes']['title'] = Html::decodeEntities($alt); } $class = $this->viewsTokenReplace($alter['link_class'], $tokens); if ($class) { $options['attributes']['class'] = array($class); } if (!empty($alter['rel']) && $rel = $this->viewsTokenReplace($alter['rel'], $tokens)) { $options['attributes']['rel'] = $rel; } $target = trim($this->viewsTokenReplace($alter['target'], $tokens)); if (!empty($target)) { $options['attributes']['target'] = $target; } // Allow the addition of arbitrary attributes to links. Additional attributes // currently can only be altered in preprocessors and not within the UI. if (isset($alter['link_attributes']) && is_array($alter['link_attributes'])) { foreach ($alter['link_attributes'] as $key => $attribute) { if (!isset($options['attributes'][$key])) { $options['attributes'][$key] = $this->viewsTokenReplace($attribute, $tokens); } } } // If the query and fragment were programmatically assigned overwrite any // parsed values. if (isset($alter['query'])) { // Convert the query to a string, perform token replacement, and then // convert back to an array form for // \Drupal\Core\Utility\LinkGeneratorInterface::generate(). $options['query'] = UrlHelper::buildQuery($alter['query']); $options['query'] = $this->viewsTokenReplace($options['query'], $tokens); $query = array(); parse_str($options['query'], $query); $options['query'] = $query; } if (isset($alter['alias'])) { // Alias is a boolean field, so no token. $options['alias'] = $alter['alias']; } if (isset($alter['fragment'])) { $options['fragment'] = $this->viewsTokenReplace($alter['fragment'], $tokens); } if (isset($alter['language'])) { $options['language'] = $alter['language']; } // If the url came from entity_uri(), pass along the required options. if (isset($alter['entity'])) { $options['entity'] = $alter['entity']; } if (isset($alter['entity_type'])) { $options['entity_type'] = $alter['entity_type']; } // The path has been heavily processed above, so it should be used as-is. $final_url = CoreUrl::fromUri($path, $options); // Build the link based on our altered Url object, adding on the optional // prefix and suffix $render = [ '#type' => 'link', '#title' => $text, '#url' => $final_url, ]; if (!empty($alter['prefix'])) { $render['#prefix'] = $this->viewsTokenReplace($alter['prefix'], $tokens); } if (!empty($alter['suffix'])) { $render['#suffix'] = $this->viewsTokenReplace($alter['suffix'], $tokens); } return $this->getRenderer()->render($render); }
public function render($row) { static $row_index; if (!isset($row_index)) { $row_index = 0; } if (function_exists('rdf_get_namespaces')) { // Merge RDF namespaces in the XML namespaces in case they are used // further in the RSS content. $xml_rdf_namespaces = array(); foreach (rdf_get_namespaces() as $prefix => $uri) { $xml_rdf_namespaces['xmlns:' . $prefix] = $uri; } $this->view->style_plugin->namespaces += $xml_rdf_namespaces; } // Create the RSS item object. $item = new \stdClass(); $item->title = $this->getField($row_index, $this->options['title_field']); // @todo Views should expect and store a leading /. See: // https://www.drupal.org/node/2423913 $item->link = Url::fromUserInput('/' . $this->getField($row_index, $this->options['link_field']))->setAbsolute()->toString(); $field = $this->getField($row_index, $this->options['description_field']); $item->description = is_array($field) ? $field : ['#markup' => $field]; $item->elements = array(array('key' => 'pubDate', 'value' => $this->getField($row_index, $this->options['date_field'])), array('key' => 'dc:creator', 'value' => $this->getField($row_index, $this->options['creator_field']), 'namespace' => array('xmlns:dc' => 'http://purl.org/dc/elements/1.1/'))); $guid_is_permalink_string = 'false'; $item_guid = $this->getField($row_index, $this->options['guid_field_options']['guid_field']); if ($this->options['guid_field_options']['guid_field_is_permalink']) { $guid_is_permalink_string = 'true'; // @todo Enforce GUIDs as system-generated rather than user input? See // https://www.drupal.org/node/2430589. $item_guid = Url::fromUserInput('/' . $item_guid)->setAbsolute()->toString(); } $item->elements[] = array('key' => 'guid', 'value' => $item_guid, 'attributes' => array('isPermaLink' => $guid_is_permalink_string)); $row_index++; foreach ($item->elements as $element) { if (isset($element['namespace'])) { $this->view->style_plugin->namespaces = array_merge($this->view->style_plugin->namespaces, $element['namespace']); } } $build = array('#theme' => $this->themeFunctions(), '#view' => $this->view, '#options' => $this->options, '#row' => $item, '#field_alias' => isset($this->field_alias) ? $this->field_alias : ''); return $build; }
/** * Tests the fromUserInput method with invalid paths. * * @covers ::fromUserInput * @expectedException \InvalidArgumentException * @dataProvider providerFromInvalidInternalUri */ public function testFromInvalidUserInput($path) { $url = Url::fromUserInput($path); }
/** * Tests rewriting the output to a link. */ public function testAlterUrl() { /** @var \Drupal\Core\Render\RendererInterface $renderer */ $renderer = \Drupal::service('renderer'); $view = Views::getView('test_view'); $view->setDisplay(); $view->initHandlers(); $this->executeView($view); $row = $view->result[0]; $id_field = $view->field['id']; // Setup the general settings required to build a link. $id_field->options['alter']['make_link'] = TRUE; $id_field->options['alter']['path'] = $path = $this->randomMachineName(); // Tests that the suffix/prefix appears on the output. $id_field->options['alter']['prefix'] = $prefix = $this->randomMachineName(); $id_field->options['alter']['suffix'] = $suffix = $this->randomMachineName(); $output = $renderer->executeInRenderContext(new RenderContext(), function () use($id_field, $row) { return $id_field->theme($row); }); $this->assertSubString($output, $prefix); $this->assertSubString($output, $suffix); unset($id_field->options['alter']['prefix']); unset($id_field->options['alter']['suffix']); $output = $renderer->executeInRenderContext(new RenderContext(), function () use($id_field, $row) { return $id_field->theme($row); }); $this->assertSubString($output, $path, 'Make sure that the path is part of the output'); // Some generic test code adapted from the UrlTest class, which tests // mostly the different options for the path. foreach (array(FALSE, TRUE) as $absolute) { $alter =& $id_field->options['alter']; $alter['path'] = 'node/123'; $expected_result = \Drupal::url('entity.node.canonical', ['node' => '123'], ['absolute' => $absolute]); $alter['absolute'] = $absolute; $result = $renderer->executeInRenderContext(new RenderContext(), function () use($id_field, $row) { return $id_field->theme($row); }); $this->assertSubString($result, $expected_result); $expected_result = \Drupal::url('entity.node.canonical', ['node' => '123'], ['fragment' => 'foo', 'absolute' => $absolute]); $alter['path'] = 'node/123#foo'; $result = $renderer->executeInRenderContext(new RenderContext(), function () use($id_field, $row) { return $id_field->theme($row); }); $this->assertSubString($result, $expected_result); $expected_result = \Drupal::url('entity.node.canonical', ['node' => '123'], ['query' => ['foo' => NULL], 'absolute' => $absolute]); $alter['path'] = 'node/123?foo'; $result = $renderer->executeInRenderContext(new RenderContext(), function () use($id_field, $row) { return $id_field->theme($row); }); $this->assertSubString($result, $expected_result); $expected_result = \Drupal::url('entity.node.canonical', ['node' => '123'], ['query' => ['foo' => 'bar', 'bar' => 'baz'], 'absolute' => $absolute]); $alter['path'] = 'node/123?foo=bar&bar=baz'; $result = $renderer->executeInRenderContext(new RenderContext(), function () use($id_field, $row) { return $id_field->theme($row); }); $this->assertSubString(Html::decodeEntities($result), Html::decodeEntities($expected_result)); // @todo The route-based URL generator strips out NULL attributes. // $expected_result = \Drupal::url('entity.node.canonical', ['node' => '123'], ['query' => ['foo' => NULL], 'fragment' => 'bar', 'absolute' => $absolute]); $expected_result = Url::fromUserInput('/node/123', array('query' => array('foo' => NULL), 'fragment' => 'bar', 'absolute' => $absolute))->toString(); $alter['path'] = 'node/123?foo#bar'; $result = $renderer->executeInRenderContext(new RenderContext(), function () use($id_field, $row) { return $id_field->theme($row); }); $this->assertSubString(Html::decodeEntities($result), Html::decodeEntities($expected_result)); $expected_result = \Drupal::url('<front>', [], ['absolute' => $absolute]); $alter['path'] = '<front>'; $result = $renderer->executeInRenderContext(new RenderContext(), function () use($id_field, $row) { return $id_field->theme($row); }); $this->assertSubString($result, $expected_result); } // Tests the replace spaces with dashes feature. $id_field->options['alter']['replace_spaces'] = TRUE; $id_field->options['alter']['path'] = $path = $this->randomMachineName() . ' ' . $this->randomMachineName(); $output = $renderer->executeInRenderContext(new RenderContext(), function () use($id_field, $row) { return $id_field->theme($row); }); $this->assertSubString($output, str_replace(' ', '-', $path)); $id_field->options['alter']['replace_spaces'] = FALSE; $output = $renderer->executeInRenderContext(new RenderContext(), function () use($id_field, $row) { return $id_field->theme($row); }); // The url has a space in it, so to check we have to decode the url output. $this->assertSubString(urldecode($output), $path); // Tests the external flag. // Switch on the external flag should output an external url as well. $id_field->options['alter']['external'] = TRUE; $id_field->options['alter']['path'] = $path = 'www.drupal.org'; $output = $renderer->executeInRenderContext(new RenderContext(), function () use($id_field, $row) { return $id_field->theme($row); }); $this->assertSubString($output, 'http://www.drupal.org'); // Setup a not external url, which shouldn't lead to an external url. $id_field->options['alter']['external'] = FALSE; $id_field->options['alter']['path'] = $path = 'www.drupal.org'; $output = $renderer->executeInRenderContext(new RenderContext(), function () use($id_field, $row) { return $id_field->theme($row); }); $this->assertNotSubString($output, 'http://www.drupal.org'); // Tests the transforming of the case setting. $id_field->options['alter']['path'] = $path = $this->randomMachineName(); $id_field->options['alter']['path_case'] = 'none'; $output = $renderer->executeInRenderContext(new RenderContext(), function () use($id_field, $row) { return $id_field->theme($row); }); $this->assertSubString($output, $path); // Switch to uppercase and lowercase. $id_field->options['alter']['path_case'] = 'upper'; $output = $renderer->executeInRenderContext(new RenderContext(), function () use($id_field, $row) { return $id_field->theme($row); }); $this->assertSubString($output, strtoupper($path)); $id_field->options['alter']['path_case'] = 'lower'; $output = $renderer->executeInRenderContext(new RenderContext(), function () use($id_field, $row) { return $id_field->theme($row); }); $this->assertSubString($output, strtolower($path)); // Switch to ucfirst and ucwords. $id_field->options['alter']['path_case'] = 'ucfirst'; $id_field->options['alter']['path'] = 'drupal has a great community'; $output = $renderer->executeInRenderContext(new RenderContext(), function () use($id_field, $row) { return $id_field->theme($row); }); $this->assertSubString($output, UrlHelper::encodePath('Drupal has a great community')); $id_field->options['alter']['path_case'] = 'ucwords'; $output = $renderer->executeInRenderContext(new RenderContext(), function () use($id_field, $row) { return $id_field->theme($row); }); $this->assertSubString($output, UrlHelper::encodePath('Drupal Has A Great Community')); unset($id_field->options['alter']['path_case']); // Tests the linkclass setting and see whether it actually exists in the // output. $id_field->options['alter']['link_class'] = $class = $this->randomMachineName(); $output = $renderer->executeInRenderContext(new RenderContext(), function () use($id_field, $row) { return $id_field->theme($row); }); $elements = $this->xpathContent($output, '//a[contains(@class, :class)]', array(':class' => $class)); $this->assertTrue($elements); // @fixme link_class, alt, rel cannot be unset, which should be fixed. $id_field->options['alter']['link_class'] = ''; // Tests the alt setting. $id_field->options['alter']['alt'] = $rel = $this->randomMachineName(); $output = $renderer->executeInRenderContext(new RenderContext(), function () use($id_field, $row) { return $id_field->theme($row); }); $elements = $this->xpathContent($output, '//a[contains(@title, :alt)]', array(':alt' => $rel)); $this->assertTrue($elements); $id_field->options['alter']['alt'] = ''; // Tests the rel setting. $id_field->options['alter']['rel'] = $rel = $this->randomMachineName(); $output = $renderer->executeInRenderContext(new RenderContext(), function () use($id_field, $row) { return $id_field->theme($row); }); $elements = $this->xpathContent($output, '//a[contains(@rel, :rel)]', array(':rel' => $rel)); $this->assertTrue($elements); $id_field->options['alter']['rel'] = ''; // Tests the target setting. $id_field->options['alter']['target'] = $target = $this->randomMachineName(); $output = $renderer->executeInRenderContext(new RenderContext(), function () use($id_field, $row) { return $id_field->theme($row); }); $elements = $this->xpathContent($output, '//a[contains(@target, :target)]', array(':target' => $target)); $this->assertTrue($elements); unset($id_field->options['alter']['target']); }
/** * Redirects on 403 Access Denied kernel exceptions. * * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event * The Event to process. */ public function onKernelException(GetResponseEvent $event) { $exception = $event->getException(); if (!$exception instanceof AccessDeniedHttpException) { return; } $config = $this->configFactory->get('r4032login.settings'); $options = array(); $options['query'] = $this->redirectDestination->getAsArray(); $options['absolute'] = TRUE; $code = $config->get('default_redirect_code'); if ($this->currentUser->isAnonymous()) { // Show custom access denied message if set. if ($config->get('display_denied_message')) { $message = $config->get('access_denied_message'); $message_type = $config->get('access_denied_message_type'); drupal_set_message(Xss::filterAdmin($message), $message_type); } // Handle redirection to the login form. $login_route = $config->get('user_login_route'); $url = Url::fromRoute($login_route, array(), $options)->toString(); $response = new RedirectResponse($url, $code); $event->setResponse($response); } else { // Check to see if we are to redirect the user. $redirect = $config->get('redirect_authenticated_users_to'); if ($redirect) { // Custom access denied page for logged in users. $url = Url::fromUserInput($redirect, $options)->toString(); $response = new RedirectResponse($url, $code); $event->setResponse($response); } } }
/** * Helper function to get the display details section of the edit UI. * * @param $display * * @return array * A renderable page build array. */ public function getDisplayDetails($view, $display) { $display_title = $this->getDisplayLabel($view, $display['id'], FALSE); $build = array('#theme_wrappers' => array('container'), '#attributes' => array('id' => 'edit-display-settings-details')); $is_display_deleted = !empty($display['deleted']); // The master display cannot be duplicated. $is_default = $display['id'] == 'default'; // @todo: Figure out why getOption doesn't work here. $is_enabled = $view->getExecutable()->displayHandlers->get($display['id'])->isEnabled(); if ($display['id'] != 'default') { $build['top']['#theme_wrappers'] = array('container'); $build['top']['#attributes']['id'] = 'edit-display-settings-top'; $build['top']['#attributes']['class'] = array('views-ui-display-tab-actions', 'edit-display-settings-top', 'views-ui-display-tab-bucket', 'clearfix'); // The Delete, Duplicate and Undo Delete buttons. $build['top']['actions'] = array('#theme_wrappers' => array('dropbutton_wrapper')); // Because some of the 'links' are actually submit buttons, we have to // manually wrap each item in <li> and the whole list in <ul>. $build['top']['actions']['prefix']['#markup'] = '<ul class="dropbutton">'; if (!$is_display_deleted) { if (!$is_enabled) { $build['top']['actions']['enable'] = array('#type' => 'submit', '#value' => $this->t('Enable @display_title', ['@display_title' => $display_title]), '#limit_validation_errors' => array(), '#submit' => array('::submitDisplayEnable', '::submitDelayDestination'), '#prefix' => '<li class="enable">', "#suffix" => '</li>'); } elseif ($view->status() && $view->getExecutable()->displayHandlers->get($display['id'])->hasPath()) { $path = $view->getExecutable()->displayHandlers->get($display['id'])->getPath(); if ($path && strpos($path, '%') === FALSE) { if (!parse_url($path, PHP_URL_SCHEME)) { // @todo Views should expect and store a leading /. See: // https://www.drupal.org/node/2423913 $url = Url::fromUserInput('/' . ltrim($path, '/')); } else { $url = Url::fromUri("base:{$path}"); } $build['top']['actions']['path'] = array('#type' => 'link', '#title' => $this->t('View @display_title', ['@display_title' => $display_title]), '#options' => array('alt' => array($this->t("Go to the real page for this display"))), '#url' => $url, '#prefix' => '<li class="view">', "#suffix" => '</li>'); } } if (!$is_default) { $build['top']['actions']['duplicate'] = array('#type' => 'submit', '#value' => $this->t('Duplicate @display_title', ['@display_title' => $display_title]), '#limit_validation_errors' => array(), '#submit' => array('::submitDisplayDuplicate', '::submitDelayDestination'), '#prefix' => '<li class="duplicate">', "#suffix" => '</li>'); } // Always allow a display to be deleted. $build['top']['actions']['delete'] = array('#type' => 'submit', '#value' => $this->t('Delete @display_title', ['@display_title' => $display_title]), '#limit_validation_errors' => array(), '#submit' => array('::submitDisplayDelete', '::submitDelayDestination'), '#prefix' => '<li class="delete">', "#suffix" => '</li>'); foreach (Views::fetchPluginNames('display', NULL, array($view->get('storage')->get('base_table'))) as $type => $label) { if ($type == $display['display_plugin']) { continue; } $build['top']['actions']['duplicate_as'][$type] = array('#type' => 'submit', '#value' => $this->t('Duplicate as @type', ['@type' => $label]), '#limit_validation_errors' => array(), '#submit' => array('::submitDuplicateDisplayAsType', '::submitDelayDestination'), '#prefix' => '<li class="duplicate">', '#suffix' => '</li>'); } } else { $build['top']['actions']['undo_delete'] = array('#type' => 'submit', '#value' => $this->t('Undo delete of @display_title', ['@display_title' => $display_title]), '#limit_validation_errors' => array(), '#submit' => array('::submitDisplayUndoDelete', '::submitDelayDestination'), '#prefix' => '<li class="undo-delete">', "#suffix" => '</li>'); } if ($is_enabled) { $build['top']['actions']['disable'] = array('#type' => 'submit', '#value' => $this->t('Disable @display_title', ['@display_title' => $display_title]), '#limit_validation_errors' => array(), '#submit' => array('::submitDisplayDisable', '::submitDelayDestination'), '#prefix' => '<li class="disable">', "#suffix" => '</li>'); } $build['top']['actions']['suffix']['#markup'] = '</ul>'; // The area above the three columns. $build['top']['display_title'] = array('#theme' => 'views_ui_display_tab_setting', '#description' => $this->t('Display name'), '#link' => $view->getExecutable()->displayHandlers->get($display['id'])->optionLink($display_title, 'display_title')); } $build['columns'] = array(); $build['columns']['#theme_wrappers'] = array('container'); $build['columns']['#attributes'] = array('id' => 'edit-display-settings-main', 'class' => array('clearfix', 'views-display-columns')); $build['columns']['first']['#theme_wrappers'] = array('container'); $build['columns']['first']['#attributes'] = array('class' => array('views-display-column', 'first')); $build['columns']['second']['#theme_wrappers'] = array('container'); $build['columns']['second']['#attributes'] = array('class' => array('views-display-column', 'second')); $build['columns']['second']['settings'] = array(); $build['columns']['second']['header'] = array(); $build['columns']['second']['footer'] = array(); $build['columns']['second']['empty'] = array(); $build['columns']['second']['pager'] = array(); // The third column buckets are wrapped in details. $build['columns']['third'] = array('#type' => 'details', '#title' => $this->t('Advanced'), '#theme_wrappers' => array('details'), '#attributes' => array('class' => array('views-display-column', 'third'))); // Collapse the details by default. $build['columns']['third']['#open'] = \Drupal::config('views.settings')->get('ui.show.advanced_column'); // Each option (e.g. title, access, display as grid/table/list) fits into one // of several "buckets," or boxes (Format, Fields, Sort, and so on). $buckets = array(); // Fetch options from the display plugin, with a list of buckets they go into. $options = array(); $view->getExecutable()->displayHandlers->get($display['id'])->optionsSummary($buckets, $options); // Place each option into its bucket. foreach ($options as $id => $option) { // Each option self-identifies as belonging in a particular bucket. $buckets[$option['category']]['build'][$id] = $this->buildOptionForm($view, $id, $option, $display); } // Place each bucket into the proper column. foreach ($buckets as $id => $bucket) { // Let buckets identify themselves as belonging in a column. if (isset($bucket['column']) && isset($build['columns'][$bucket['column']])) { $column = $bucket['column']; } else { $column = 'third'; } if (isset($bucket['build']) && is_array($bucket['build'])) { $build['columns'][$column][$id] = $bucket['build']; $build['columns'][$column][$id]['#theme_wrappers'][] = 'views_ui_display_tab_bucket'; $build['columns'][$column][$id]['#title'] = !empty($bucket['title']) ? $bucket['title'] : ''; $build['columns'][$column][$id]['#name'] = $id; } } $build['columns']['first']['fields'] = $this->getFormBucket($view, 'field', $display); $build['columns']['first']['filters'] = $this->getFormBucket($view, 'filter', $display); $build['columns']['first']['sorts'] = $this->getFormBucket($view, 'sort', $display); $build['columns']['second']['header'] = $this->getFormBucket($view, 'header', $display); $build['columns']['second']['footer'] = $this->getFormBucket($view, 'footer', $display); $build['columns']['second']['empty'] = $this->getFormBucket($view, 'empty', $display); $build['columns']['third']['arguments'] = $this->getFormBucket($view, 'argument', $display); $build['columns']['third']['relationships'] = $this->getFormBucket($view, 'relationship', $display); return $build; }
/** * Tests that an url alias works correctly. */ public function testUrlAlias() { $facet_id = 'ab_facet'; $facet_name = 'ab>Facet'; $facet_edit_page = '/admin/config/search/facets/' . $facet_id . '/edit'; $this->createFacet($facet_name, $facet_id); $this->drupalGet('search-api-test-fulltext'); $this->assertLink('item'); $this->assertLink('article'); $this->clickLink('item'); $url = Url::fromUserInput('/search-api-test-fulltext', ['query' => ['f[0]' => 'ab_facet:item']]); $this->assertUrl($url); $this->drupalGet($facet_edit_page); $this->drupalPostForm(NULL, ['facet_settings[url_alias]' => 'llama'], $this->t('Save')); $this->drupalGet('search-api-test-fulltext'); $this->assertLink('item'); $this->assertLink('article'); $this->clickLink('item'); $url = Url::fromUserInput('/search-api-test-fulltext', ['query' => ['f[0]' => 'llama:item']]); $this->assertUrl($url); }
/** * Batch function which generates urls to custom paths. * * @param array $custom_paths * @param array $batch_info * @param array &$context * * @see https://api.drupal.org/api/drupal/core!includes!form.inc/group/batch/8 */ public static function generateCustomUrls($custom_paths, $batch_info, &$context) { $languages = \Drupal::languageManager()->getLanguages(); $anon_user = User::load(self::ANONYMOUS_USER_ID); // Initialize batch if not done yet. if (self::needsInitialization($context)) { self::initializeBatch($batch_info, count($custom_paths), $context); } foreach ($custom_paths as $i => $custom_path) { if (self::isBatch($batch_info)) { self::setCurrentId($i, $context); } if (!\Drupal::service('path.validator')->isValid($custom_path['path'])) { //todo: Change to different function, as this also checks if current user has access. The user however varies depending if process was started from the web interface or via cron/drush. self::registerError(self::PATH_DOES_NOT_EXIST_OR_NO_ACCESS, ['@path' => $custom_path['path']], 'warning'); continue; } $url_object = Url::fromUserInput($custom_path['path'], ['absolute' => TRUE]); if (!$url_object->access($anon_user)) { continue; } $path = $url_object->getInternalPath(); if ($batch_info['remove_duplicates'] && self::pathProcessed($path, $context)) { continue; } // Load entity object if this is an entity route. $route_parameters = $url_object->getRouteParameters(); $entity = !empty($route_parameters) ? \Drupal::entityTypeManager()->getStorage(key($route_parameters))->load($route_parameters[key($route_parameters)]) : NULL; $path_data = ['path' => $path, 'lastmod' => method_exists($entity, 'getChangedTime') ? date_iso8601($entity->getChangedTime()) : NULL, 'priority' => isset($custom_path['priority']) ? $custom_path['priority'] : NULL]; if (!is_null($entity)) { $path_data['entity_info'] = ['entity_type' => $entity->getEntityTypeId(), 'id' => $entity->id()]; } $alternate_urls = []; foreach ($languages as $language) { $langcode = $language->getId(); if (!$batch_info['skip_untranslated'] || is_null($entity) || $entity->hasTranslation($langcode) || $language->isDefault()) { $url_object->setOption('language', $language); $alternate_urls[$langcode] = $url_object->toString(); } } foreach ($alternate_urls as $langcode => $url) { $context['results']['generate'][] = $path_data + ['langcode' => $langcode, 'url' => $url, 'alternate_urls' => $alternate_urls]; } } if (self::isBatch($batch_info)) { self::setProgressInfo($context); } self::processSegment($context, $batch_info); }
/** * Gets a list of paths assigned to the view. * * @param \Drupal\Core\Entity\EntityInterface $view * The view entity. * * @return array * An array of paths for this view. */ protected function getDisplayPaths(EntityInterface $view) { $all_paths = array(); $executable = $view->getExecutable(); $executable->initDisplay(); foreach ($executable->displayHandlers as $display) { if ($display->hasPath()) { $path = $display->getPath(); if ($view->status() && strpos($path, '%') === FALSE) { // @todo Views should expect and store a leading /. See: // https://www.drupal.org/node/2423913 $all_paths[] = \Drupal::l('/' . $path, Url::fromUserInput('/' . $path)); } else { $all_paths[] = '/' . $path; } } } return array_unique($all_paths); }
public function getUrl() { // Generate the internal url based on the user input. // See Url::fromUserInput() for more information. return Url::fromUserInput('/' . $this->getValue() . $this->getUrlSuffix()); }
/** * {@inheritdoc} */ public function renderMoreLink() { if ($this->isMoreEnabled() && ($this->useMoreAlways() || !empty($this->view->pager) && $this->view->pager->hasMoreRecords())) { // If the user has supplied a custom "More" link path, replace any // argument tokens and use that for the URL. if ($this->getOption('link_display') == 'custom_url' && ($override_path = $this->getOption('link_url'))) { $tokens = $this->getArgumentsTokens(); $path = $this->viewsTokenReplace($override_path, $tokens); // @todo Views should expect and store a leading /. See: // https://www.drupal.org/node/2423913 $url = Url::fromUserInput('/' . $path); } else { $url = $this->view->getUrl(NULL, $this->display['id']); } // If a URL is available (either from the display or a custom path), // render the "More" link. if ($url) { $url_options = array(); if (!empty($this->view->exposed_raw_input)) { $url_options['query'] = $this->view->exposed_raw_input; } $url->setOptions($url_options); return array('#type' => 'more_link', '#url' => $url, '#title' => $this->useMoreText(), '#view' => $this->view); } } }
/** * {@inheritdoc} */ public function getRedirectUrl() { if ($this->redirect) { $url = Url::fromUserInput($this->redirect); } else { $url = Url::fromRoute('<front>'); } return $url; }