/** * {@inheritdoc} */ public function validate($value, Constraint $constraint) { if (isset($value)) { $url_is_valid = FALSE; /** @var $link_item \Drupal\link\LinkItemInterface */ $link_item = $value; $link_type = $link_item->getFieldDefinition()->getSetting('link_type'); $url_string = $link_item->url; // Validate the url property. if ($url_string !== '') { if ($url = \Drupal::pathValidator()->getUrlIfValid($url_string)) { $url_is_valid = (bool) $url; if ($url->isExternal() && !($link_type & LinkItemInterface::LINK_EXTERNAL)) { $url_is_valid = FALSE; } } } if (!$url_is_valid) { $this->context->addViolation($this->message, array('%url' => $url_string)); } } }
/** * Creates a new Url object for 'internal:' URIs. * * Important note: the URI minus the scheme can NOT simply be validated by a * \Drupal\Core\Path\PathValidatorInterface implementation. The semantics of * the 'internal:' URI scheme are different: * - PathValidatorInterface accepts paths without a leading slash (e.g. * 'node/add') as well as 2 special paths: '<front>' and '<none>', which are * mapped to the correspondingly named routes. * - 'internal:' URIs store paths with a leading slash that represents the * root — i.e. the front page — (e.g. 'internal:/node/add'), and doesn't * have any exceptions. * * To clarify, a few examples of path plus corresponding 'internal:' URI: * - 'node/add' -> 'internal:/node/add' * - 'node/add?foo=bar' -> 'internal:/node/add?foo=bar' * - 'node/add#kitten' -> 'internal:/node/add#kitten' * - '<front>' -> 'internal:/' * - '<front>foo=bar' -> 'internal:/?foo=bar' * - '<front>#kitten' -> 'internal:/#kitten' * - '<none>' -> 'internal:' * - '<none>foo=bar' -> 'internal:?foo=bar' * - '<none>#kitten' -> 'internal:#kitten' * * Therefore, when using a PathValidatorInterface to validate 'internal:' * URIs, we must map: * - 'internal:' (path component is '') to the special '<none>' path * - 'internal:/' (path component is '/') to the special '<front>' path * - 'internal:/some-path' (path component is '/some-path') to 'some-path' * * @param array $uri_parts * Parts from an URI of the form internal:{path} as from parse_url(). * @param array $options * An array of options, see static::fromUri() for details. * * @return \Drupal\Core\Url * A new Url object for a 'internal:' URI. * * @throws \InvalidArgumentException * Thrown when the URI's path component doesn't have a leading slash. */ protected static function fromInternalUri(array $uri_parts, array $options) { // Both PathValidator::getUrlIfValidWithoutAccessCheck() and 'base:' URIs // only accept/contain paths without a leading slash, unlike 'internal:' // URIs, for which the leading slash means "relative to Drupal root" and // "relative to Symfony app root" (just like in Symfony/Drupal 8 routes). if (empty($uri_parts['path'])) { $uri_parts['path'] = '<none>'; } elseif ($uri_parts['path'] === '/') { $uri_parts['path'] = '<front>'; } else { if ($uri_parts['path'][0] !== '/') { throw new \InvalidArgumentException(SafeMarkup::format('The internal path component "@path" is invalid. Its path component must have a leading slash, e.g. internal:/foo.', ['@path' => $uri_parts['path']])); } // Remove the leading slash. $uri_parts['path'] = substr($uri_parts['path'], 1); } $url = \Drupal::pathValidator()->getUrlIfValidWithoutAccessCheck($uri_parts['path']) ?: static::fromUri('base:' . $uri_parts['path'], $options); // Allow specifying additional options. $url->setOptions($options + $url->getOptions()); return $url; }
/** * Normalizes the path aliases. * * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event */ public function globalredirectNormalizeAliases(GetResponseEvent $event) { if ($event->getRequestType() != HttpKernelInterface::MASTER_REQUEST || !$this->config->get('normalize_aliases') || !($path = trim($event->getRequest()->getPathInfo(), '/'))) { return; } $system_path = $this->aliasManager->getPathByAlias($path); $alias = $this->aliasManager->getAliasByPath($system_path, $this->languageManager->getCurrentLanguage()->getId()); // If the alias defined in the system is not the same as the one via which // the page has been accessed do a redirect to the one defined in the // system. if ($alias != $path) { if ($url = \Drupal::pathValidator()->getUrlIfValid($alias)) { $this->setResponse($event, $url); } } }
/** * Tests the pathValidator() method. * * @covers ::pathValidator */ public function testPathValidator() { $this->setMockContainerService('path.validator'); $this->assertNotNull(\Drupal::pathValidator()); }
/** * {@inheritdoc} */ public function massageFormValues(array $values, array $form, FormStateInterface $form_state) { foreach ($values as &$value) { if (!empty($value['url'])) { $url = \Drupal::pathValidator()->getUrlIfValid($value['url']); if (!$url) { return $values; } // @todo Don't use the toArray method here. Removed once it is // deprecated. $value += $url->toArray(); // Reset the URL value to contain only the path. if (!$url->isExternal() && $this->supportsInternalLinks()) { $value['url'] = substr($url->toString(), strlen(\Drupal::request()->getBasePath() . '/')); } } } return $values; }
/** * Breaks up a user-entered URL or path into all the relevant parts. * * @param string $url * The user-entered URL or path. * * @return array * The extracted parts. */ protected function extractUrl($url) { $extracted = UrlHelper::parse($url); $external = UrlHelper::isExternal($url); if ($external) { $extracted['url'] = $extracted['path']; $extracted['route_name'] = NULL; $extracted['route_parameters'] = []; } else { $extracted['url'] = ''; // If the path doesn't match a Drupal path, the route should end up empty. $extracted['route_name'] = NULL; $extracted['route_parameters'] = []; try { // Find the route_name. $url_obj = \Drupal::pathValidator()->getUrlIfValid($extracted['path']); if ($url_obj) { $extracted['route_name'] = $url_obj->getRouteName(); $extracted['route_parameters'] = $url_obj->getRouteParameters(); } } catch (MatchingRouteNotFoundException $e) { // The path doesn't match a Drupal path. } catch (ParamNotConvertedException $e) { // A path like node/99 matched a route, but the route parameter was // invalid (e.g. node with ID 99 does not exist). } } return $extracted; }