Skip to content
Snippets Groups Projects
Commit 7cb9968f authored by Kevin Paxman's avatar Kevin Paxman
Browse files

Merge branch 'feature/ISTWCMS-7266-ibiki-links_and_titles' into '1.1.x'

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

See merge request !265
parents df26e726 be6f0a74
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;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Path\PathValidatorInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Url;
use Drupal\media\Entity\Media;
use Drupal\path_alias\AliasManager;
use Drupal\uw_cfg_common\Service\UWService;
......@@ -266,13 +267,8 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface {
// If this is not an external link, get the friendly path
// to the page. If it is external, just use the 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.
$links['items'][$count][$index] = $this->prepareLink($value, $base_path);
$links['items'][$count][$index] = $this->cleanUpLink($value, TRUE, FALSE);
}
else {
......@@ -284,10 +280,10 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface {
// See if link title needs to be modified.
if (empty($item['title'])) {
$links['items'][$count]['title'] = $this->getTitleOverride($item['uri'], $base_path);
$links['items'][$count][$index] = $this->getTitleOverride($item['uri']);
}
else {
$links['items'][$count]['title'] = $value;
$links['items'][$count][$index] = $value;
}
}
else {
......@@ -312,11 +308,6 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface {
// Array to store the links.
$links = [];
// Base path if exists.
$base_path = $this->requestStack
->getCurrentRequest()
?->getBasePath();
// Attach the js library.
$form['#attached']['library'][] = 'uw_custom_blocks/uw_cbl_links';
......@@ -472,7 +463,7 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface {
// If there is a link already set, setup the details to
// have the link in the title so when it is closed,
// 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'])) {
$link = $this->t('Link (@uri)', ['@uri' => $value_uri]);
......@@ -696,7 +687,7 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface {
// set the form error.
if (
$value !== '' &&
!preg_match('/^(http(s):\/\/.)/', $value) &&
!preg_match('/^(https?:\/\/.)/i', $value) &&
!preg_match('/^[\/#]/', $value)
) {
......@@ -784,6 +775,9 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface {
) {
$links['items'][$count][$key] = NULL;
}
elseif ($key === 'uri') {
$links['items'][$count][$key] = $this->cleanUpLink($item['link_info'][$key]);
}
else {
$links['items'][$count][$key] = $item['link_info'][$key];
}
......@@ -928,17 +922,24 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface {
*
* @param string $raw_link
* The original link that needs to be cleaned up.
* @param string|null $base_path
* The base path to remove from the link if it exists, default NULL.
* @param bool $return_alias
* Should alias be returned instead of an internal url.
* @param bool $prefix_base_path
* Should base_path be concateneted before url.
*
* @return string
* 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)) {
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.
$link = $raw_link;
......@@ -949,17 +950,8 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface {
$link = substr_replace($link, '', 0, strlen('internal:'));
}
// If a link starts with base_path, remove it, but only when base_path
// is not NULL. And make sure the resulting link starts with 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.
// In some cases, the external link is prefixed with a leading slash. This
// removes that leading slash.
$updated = preg_replace(self::LEADING_SLASH_REPLACE_REGEX, '$1', $link);
// In case match is not found, unchanged value is returned.
......@@ -968,38 +960,40 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface {
$link = $updated;
}
return $link;
}
$path = $this->getInternalUrlIfValid($link, $base_path);
/**
* Prepares and sanitizes a link by removing specific base path prefixes.
*
* This method removes the base path and 'internal:/' prefix from the
* provided link to ensure it is in the desired format.
*
* @param string $link
* 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 node alias is used, modify it so a canonical link is used.
if ($path && !$path->isExternal()) {
if ($return_alias) {
$canonical = $path->toString();
}
else {
$canonical = $path->getInternalPath();
if (empty($link)) {
return $link;
}
// Detects if there is a fragment or query string.
$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()) {
return $path->toString();
if ($base_path && $prefix_base_path) {
$canonical = $base_path . $canonical;
}
if ($link !== $canonical) {
$link = $canonical;
}
}
return $url;
return $link;
}
/**
......@@ -1011,17 +1005,15 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface {
*
* @param string $url
* The URL to validate and extract the title from.
* @param string|null $base_path
* Base path.
*
* @return string
* The overridden title is if available, or an empty string
* if no title can be determined.
*/
private function getTitleOverride(string $url, ?string $base_path = NULL): string {
private function getTitleOverride(string $url): string {
$title = "";
$link = $this->cleanUpLink($url, $base_path);
$link = $this->cleanUpLink($url, prefix_base_path: FALSE);
/** @var \Drupal\Core\Url|bool $route_check */
$path = $this->pathValidator->getUrlIfValidWithoutAccessCheck($link);
......@@ -1036,8 +1028,10 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface {
->load($params['view_id']);
if ($view) {
$view->getDisplay($params['display_id']);
$title = $view->label();
$display = $view->getDisplay($params['display_id']);
// 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.
......@@ -1060,4 +1054,34 @@ class UwCblLinks extends BlockBase implements ContainerFactoryPluginInterface {
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