Skip to content
Snippets Groups Projects

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

Merged Igor Biki requested to merge feature/ISTWCMS-7266-ibiki-links_and_titles into 1.1.x
@@ -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;
 
}
 
}
}
Loading