Skip to content
Snippets Groups Projects
Commit be6f0a74 authored by Igor Biki's avatar Igor Biki Committed by Kevin Paxman
Browse files

ISTWCMS-7266: Refactor link handling logic in UwCblLinks block.

parent df26e726
No related branches found
No related tags found
1 merge request!265ISTWCMS-7266: Refactor link handling logic in UwCblLinks block.
...@@ -8,6 +8,7 @@ use Drupal\Core\Entity\EntityTypeManagerInterface; ...@@ -8,6 +8,7 @@ use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Path\PathValidatorInterface; use Drupal\Core\Path\PathValidatorInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Url;
use Drupal\media\Entity\Media; use Drupal\media\Entity\Media;
use Drupal\path_alias\AliasManager; use Drupal\path_alias\AliasManager;
use Drupal\uw_cfg_common\Service\UWService; use Drupal\uw_cfg_common\Service\UWService;
...@@ -266,13 +267,8 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface { ...@@ -266,13 +267,8 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface {
// If this is not an external link, get the friendly path // If this is not an external link, get the friendly path
// to the page. If it is external, just use the value. // to the page. If it is external, just use the value.
elseif (!UrlHelper::isExternal($value)) { elseif (!UrlHelper::isExternal($value)) {
// Get the base path of the site, this is required for Pantheon.
$base_path = $this->requestStack
->getCurrentRequest()
?->getBasePath();
// Add the url to the links array. // Add the url to the links array.
$links['items'][$count][$index] = $this->prepareLink($value, $base_path); $links['items'][$count][$index] = $this->cleanUpLink($value, TRUE, FALSE);
} }
else { else {
...@@ -284,10 +280,10 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface { ...@@ -284,10 +280,10 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface {
// See if link title needs to be modified. // See if link title needs to be modified.
if (empty($item['title'])) { if (empty($item['title'])) {
$links['items'][$count]['title'] = $this->getTitleOverride($item['uri'], $base_path); $links['items'][$count][$index] = $this->getTitleOverride($item['uri']);
} }
else { else {
$links['items'][$count]['title'] = $value; $links['items'][$count][$index] = $value;
} }
} }
else { else {
...@@ -312,11 +308,6 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface { ...@@ -312,11 +308,6 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface {
// Array to store the links. // Array to store the links.
$links = []; $links = [];
// Base path if exists.
$base_path = $this->requestStack
->getCurrentRequest()
?->getBasePath();
// Attach the js library. // Attach the js library.
$form['#attached']['library'][] = 'uw_custom_blocks/uw_cbl_links'; $form['#attached']['library'][] = 'uw_custom_blocks/uw_cbl_links';
...@@ -472,7 +463,7 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface { ...@@ -472,7 +463,7 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface {
// If there is a link already set, setup the details to // If there is a link already set, setup the details to
// have the link in the title so when it is closed, // have the link in the title so when it is closed,
// we can see what the actual is. // we can see what the actual is.
$value_uri = $this->cleanUpLink($links['items'][$i]['uri'] ?? '', $base_path); $value_uri = $this->cleanUpLink($links['items'][$i]['uri'] ?? '');
if (isset($links['items'][$i]['uri'])) { if (isset($links['items'][$i]['uri'])) {
$link = $this->t('Link (@uri)', ['@uri' => $value_uri]); $link = $this->t('Link (@uri)', ['@uri' => $value_uri]);
...@@ -696,7 +687,7 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface { ...@@ -696,7 +687,7 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface {
// set the form error. // set the form error.
if ( if (
$value !== '' && $value !== '' &&
!preg_match('/^(http(s):\/\/.)/', $value) && !preg_match('/^(https?:\/\/.)/i', $value) &&
!preg_match('/^[\/#]/', $value) !preg_match('/^[\/#]/', $value)
) { ) {
...@@ -784,6 +775,9 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface { ...@@ -784,6 +775,9 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface {
) { ) {
$links['items'][$count][$key] = NULL; $links['items'][$count][$key] = NULL;
} }
elseif ($key === 'uri') {
$links['items'][$count][$key] = $this->cleanUpLink($item['link_info'][$key]);
}
else { else {
$links['items'][$count][$key] = $item['link_info'][$key]; $links['items'][$count][$key] = $item['link_info'][$key];
} }
...@@ -928,17 +922,24 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface { ...@@ -928,17 +922,24 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface {
* *
* @param string $raw_link * @param string $raw_link
* The original link that needs to be cleaned up. * The original link that needs to be cleaned up.
* @param string|null $base_path * @param bool $return_alias
* The base path to remove from the link if it exists, default NULL. * Should alias be returned instead of an internal url.
* @param bool $prefix_base_path
* Should base_path be concateneted before url.
* *
* @return string * @return string
* The cleaned link with specified prefixes removed. * The cleaned link with specified prefixes removed.
*/ */
private function cleanUpLink(string $raw_link, ?string $base_path = NULL): string { private function cleanUpLink(string $raw_link, bool $return_alias = FALSE, bool $prefix_base_path = TRUE): string {
if (empty($raw_link)) { if (empty($raw_link)) {
return $raw_link; return $raw_link;
} }
// Get the base path of the site, this is required for Pantheon.
$base_path = $this->requestStack
->getCurrentRequest()
?->getBasePath();
// Function to modify its own variable, leaving function argument unchanged. // Function to modify its own variable, leaving function argument unchanged.
$link = $raw_link; $link = $raw_link;
...@@ -949,17 +950,8 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface { ...@@ -949,17 +950,8 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface {
$link = substr_replace($link, '', 0, strlen('internal:')); $link = substr_replace($link, '', 0, strlen('internal:'));
} }
// If a link starts with base_path, remove it, but only when base_path // In some cases, the external link is prefixed with a leading slash. This
// is not NULL. And make sure the resulting link starts with slash. // removes that leading slash.
if ($base_path && str_starts_with($link, $base_path)) {
$link = substr_replace($link, '', 0, strlen($base_path));
if (!str_starts_with($link, '/')) {
$link = '/' . $link;
}
}
// If an external link is prefix with leading slash.
$updated = preg_replace(self::LEADING_SLASH_REPLACE_REGEX, '$1', $link); $updated = preg_replace(self::LEADING_SLASH_REPLACE_REGEX, '$1', $link);
// In case match is not found, unchanged value is returned. // In case match is not found, unchanged value is returned.
...@@ -968,38 +960,40 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface { ...@@ -968,38 +960,40 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface {
$link = $updated; $link = $updated;
} }
return $link; $path = $this->getInternalUrlIfValid($link, $base_path);
}
/** // If node alias is used, modify it so a canonical link is used.
* Prepares and sanitizes a link by removing specific base path prefixes. if ($path && !$path->isExternal()) {
* if ($return_alias) {
* This method removes the base path and 'internal:/' prefix from the $canonical = $path->toString();
* provided link to ensure it is in the desired format. }
* else {
* @param string $link $canonical = $path->getInternalPath();
* The link to be sanitized.
* @param string|null $base_path
* The base path to be removed if the link starts with it.
*
* @return string
* The sanitized link without the specified prefixes.
*/
private function prepareLink(string $link, ?string $base_path = NULL): string {
if (empty($link)) { // Detects if there is a fragment or query string.
return $link; $fragment_query = preg_replace('/^[^#?]+/', '', $path->toString());
}
$url = $this->cleanUpLink($link, $base_path); // Need to check if fragment/query starts with # or ?, to avoid
// a scenario where the link is returned unchanged.
if (!empty($fragment_query) && (str_starts_with($fragment_query, '#') || str_starts_with($fragment_query, '?'))) {
$canonical .= $fragment_query;
}
}
$path = $this->pathValidator->getUrlIfValidWithoutAccessCheck($url); if (!str_starts_with($canonical, '/')) {
$canonical = '/' . $canonical;
}
if ($path && !$path->isExternal()) { if ($base_path && $prefix_base_path) {
return $path->toString(); $canonical = $base_path . $canonical;
}
if ($link !== $canonical) {
$link = $canonical;
}
} }
return $url; return $link;
} }
/** /**
...@@ -1011,17 +1005,15 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface { ...@@ -1011,17 +1005,15 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface {
* *
* @param string $url * @param string $url
* The URL to validate and extract the title from. * The URL to validate and extract the title from.
* @param string|null $base_path
* Base path.
* *
* @return string * @return string
* The overridden title is if available, or an empty string * The overridden title is if available, or an empty string
* if no title can be determined. * if no title can be determined.
*/ */
private function getTitleOverride(string $url, ?string $base_path = NULL): string { private function getTitleOverride(string $url): string {
$title = ""; $title = "";
$link = $this->cleanUpLink($url, $base_path); $link = $this->cleanUpLink($url, prefix_base_path: FALSE);
/** @var \Drupal\Core\Url|bool $route_check */ /** @var \Drupal\Core\Url|bool $route_check */
$path = $this->pathValidator->getUrlIfValidWithoutAccessCheck($link); $path = $this->pathValidator->getUrlIfValidWithoutAccessCheck($link);
...@@ -1036,8 +1028,10 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface { ...@@ -1036,8 +1028,10 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface {
->load($params['view_id']); ->load($params['view_id']);
if ($view) { if ($view) {
$view->getDisplay($params['display_id']); $display = $view->getDisplay($params['display_id']);
$title = $view->label();
// Get display id title, if that fails, use view title.
$title = $display['display_options']['title'] ?? $view->label();
} }
} }
// This part should take care of nodes, taxonomy terms and webforms. // This part should take care of nodes, taxonomy terms and webforms.
...@@ -1060,4 +1054,34 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface { ...@@ -1060,4 +1054,34 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface {
return $title ?? ""; return $title ?? "";
} }
/**
* Validates and retrieves an internal URL if applicable.
*
* Checks if the provided URL starts with the specified base path
* and attempts to validate it as an internal path without access checks.
*
* @param string $url
* The URL to be validated.
* @param string $base_path
* The base path to check against.
*
* @return \Drupal\Core\Url|null
* The valid internal URL object if the URL is valid and matches the
* base path, or NULL otherwise.
*/
private function getInternalUrlIfValid(string $url, string $base_path): ?Url {
$link = $url;
// Remove base path, this will be used to validate url.
if ($base_path && str_starts_with(strtolower($link), $base_path . '/')) {
$link = substr_replace($link, '', 0, strlen($base_path));
}
if ($path = $this->pathValidator->getUrlIfValidWithoutAccessCheck($link)) {
return $path;
}
return NULL;
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment