link_fix_absolute_urls-1.0.2/src/LinkProcessor.php
src/LinkProcessor.php
<?php
namespace Drupal\link_fix_absolute_urls;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Url;
use Drupal\path_alias\AliasManagerInterface;
/**
* The secret sauce of the Link: Fix Absolute URLs module.
*/
class LinkProcessor {
/**
* Wrapper for the Path Alias system.
*
* @var \Drupal\path_alias\AliasManagerInterface
*/
protected $aliasManager;
/**
* Constructor for LinkProcessor.
*
* @param \Drupal\path_alias\AliasManagerInterface $alias_manager
* The alias manager service.
*/
public function __construct(AliasManagerInterface $alias_manager) {
$this->aliasManager = $alias_manager;
}
/**
* Process the link fields in an entity.
*
* @param Drupal\Core\Entity\ContentEntityInterface $entity
* The entity to check for link fields.
*
* @return bool
* Whether anything was changed.
*/
public function process(ContentEntityInterface $entity) {
// Track whether a field was changed.
$changed = FALSE;
// Only load this once.
// @todo If the alias manager isn't available will this fail?
$alias_manager = \Drupal::service('path_alias.manager');
// Get the base URL for the home page, it'll be needed later.
$base_url = Url::fromRoute('<front>', [], ['absolute' => TRUE])->toString();
// Remove the protocol from the URL, to make it easier to compare later.
$base_url = $this->stripPrefixes($base_url);
// Check over each field on this entity.
foreach ($entity->getFieldDefinitions() as $field_name => $field) {
// Make sure that the getType() method exists, just to be safe.
if (!method_exists($field, 'getType')) {
continue;
}
// Only worry about 'link' fields.
if ($field->getType() == 'link' && $entity->hasField($field_name)) {
// Process each item, allowing for multiple links.
foreach ($entity->get($field_name) as $item) {
$url = $item->getUrl();
// Only deal with fully qualified URLs, other types of paths don't
// need to be worried about.
if ($url->isExternal()) {
$uri = $url->getUri();
// Strip off the protocol and "www." prefix.
$uri = $this->stripPrefixes($uri);
// Check if the URL provided starts with the site's base URL.
if (strpos($uri, $base_url) === 0) {
$new_path = FALSE;
// Strip off the base URL, leaving the bare path.
$bare_path = str_replace($base_url, '', $uri);
// Check for physical files.
if (file_exists($bare_path)) {
$new_path = 'internal:/' . $bare_path;
}
// If the path is empty it means the path was for the site's front
// page, so replace it with the system value "/".
elseif (empty($bare_path)) {
$new_path = 'internal:/';
}
// Other paths.
else {
// Add a leading slash to the bare path so that it can be
// checked in Drupal's path_alias system.
$path = '/' . $bare_path;
// Check to see if the path provided was an alias.
$raw_path = '';
if (!empty($this->aliasManager)) {
$raw_path = $this->aliasManager->getPathByAlias($path);
}
// If the raw path from the alias table was different to the
// value passed in, process the raw path.
if (!empty($raw_path) && $raw_path != $path) {
$new_path = $this->getInternalPath($raw_path);
}
// This wasn't a path alias.
else {
$new_path = $this->getInternalPath($path);
}
}
// Update the path if it was changed above.
if ($new_path !== FALSE) {
$item->setValue([
'uri' => $new_path,
'title' => $item->get('title')->getValue(),
]);
$changed = TRUE;
}
}
}
}
}
}
// Let the caller know whether anything was changed.
return $changed;
}
/**
* Get the internal equivalent of a given path.
*
* @param string $path
* The path to check.
*
* @return string|bool
* FALSE if no path could be worked out, otherwise a string.
*/
protected function getInternalPath($path) {
$new_path = FALSE;
// Test to see if the path is an internal path.
$url = Url::fromUri("internal:" . $path);
if ($url->isRouted()) {
// Check to see if this is an entity path, which is handled
// differently to an "internal" path.
$params = $url->getRouteParameters();
if (!empty($params)) {
// The results from ::fromUri will be an array the the
// format $entity_type => $entity_id.
$entity_type = key($params);
// Nodes are stored using the "entity" prefix type.
if ($entity_type == 'node') {
// Make sure this is actually a valid entity type.
$entity_storage = \Drupal::entityTypeManager()->getStorage($entity_type);
if (!empty($entity_storage)) {
// Load the entity.
$entity = $entity_storage->load($params[$entity_type]);
// Make sure the entity exists and can be loaded.
if (!empty($entity)) {
// Update the URL with the entity's path.
$new_path = 'entity:' . $entity_type . '/' . $params[$entity_type];
}
}
}
// Other entity types are stored differently, e.g. taxonomy
// terms are stored as 'internal' paths.
else {
$new_path = 'internal:' . $path;
}
}
}
else {
// Arriving here likely means the path is invalid, e.g. a
// path that doesn't exist, so just use it as-is.
$new_path = 'internal:' . $path;
}
return $new_path;
}
/**
* Strip off the "http://", "https://" and "www." prefixes from a URL.
*
* This makes it easier to compare URLs.
*
* @param string $url
* The URl to strip prefixes from.
*
* @return string
* The URL with "http://", "https://" and "www." removed.
*/
protected function stripPrefixes($url) {
$url = str_replace('http://', '', $url);
$url = str_replace('https://', '', $url);
$url = str_replace('www.', '', $url);
return $url;
}
}
