safedelete-1.0.0/src/AdminHelper.php

src/AdminHelper.php
<?php

namespace Drupal\safedelete;

use Drupal\block\BlockInterface;
use Drupal\block\Entity\Block;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Language\Language;
use Drupal\node\Entity\NodeType;
use Drupal\node\Entity\Node;
use Drupal\media\Entity\Media;
use Drupal\file\Entity\File;
use Drupal\Core\Link;
use Drupal\Core\Url;
use Drupal\Component\Utility\UrlHelper;
use Drupal\node\NodeInterface;
use Drupal\path_alias\Entity\PathAlias;
use HTMLPurifier;
use HTMLPurifier_Config;

/**
 *
 */
class AdminHelper {

  /**
   *
   */
  public static function addMessage($message) {
    \Drupal::messenger()->addMessage($message);
  }

  /**
   *
   */
  public static function addToLog($message, $DEBUG = FALSE) {
    // $DEBUG = TRUE;
    if ($DEBUG) {
      \Drupal::logger('safedelete')->notice($message);
    }
  }

  /**
   * Helper function to get all enabled languages, excluding current language.
   */
  public static function getOtherEnabledLanguages() {
    // Get the list of all languages.
    $language = \Drupal::languageManager()->getCurrentLanguage();
    $languages = \Drupal::languageManager()->getLanguages();
    $other_languages = [];

    // Add each enabled language, aside from the current language to an array.
    foreach ($languages as $field_language_code => $field_language) {
      if ($field_language_code != $language->getId()) {
        $other_languages[$field_language_code] = $field_language->getName();
      }
    }
    return $other_languages;
  }

  /**
   * Helper function get current language.
   */
  public static function getDefaultLangcode() {
    $language = \Drupal::languageManager()->getDefaultLanguage();
    return $language->getId();
  }

  /**
   * Helper function to get all enabled languages, including the current language.
   */
  public static function getAllEnabledLanguages() {
    // Get the list of all languages.
    $language = \Drupal::languageManager()->getCurrentLanguage();
    $languages = \Drupal::languageManager()->getLanguages();
    $other_languages = [];

    // Add each enabled language, aside from the current language to an array.
    foreach ($languages as $field_language_code => $field_language) {
      $other_languages[$field_language_code] = $field_language->getName();
    }
    return $other_languages;
  }

  /**
   * Get the latest revision.
   */
  public static function _latest_revision($nid, &$vid, $langcode) {
    // Change record below might be helpful for future improvements.
    // See change record here: https://www.drupal.org/node/2942013.
    $lang = \Drupal::languageManager()->getCurrentLanguage()->getId();
    if (!isset($langcode)) {
      $langcode = $lang;
    }
    if ($lang != $langcode) {
      $lang = $langcode;
    }
    $latestRevisionResult = \Drupal::entityTypeManager()->getStorage('node')->getQuery()
      ->accessCheck(FALSE)
      ->condition('nid', $nid, '=')
      ->execute();
    if (count($latestRevisionResult)) {
      $node_revision_id = key($latestRevisionResult);
      if ($node_revision_id == $vid) {
        // There is no pending revision, the current revision is the latest.
        return FALSE;
      }
      $vid = $node_revision_id;
      $latestRevision = \Drupal::entityTypeManager()->getStorage('node')->loadRevision($node_revision_id);
      if ($latestRevision->language()->getId() != $lang && $latestRevision->hasTranslation($lang)) {
        $latestRevision = $latestRevision->getTranslation($lang);
      }
      return $latestRevision;
    }
    return FALSE;
  }

  /**
   * Handle revision sync in all available languages.
   */
  public static function shutdownPostSubmit($entity_id, $state_id, $revision_log, $current_uid) {

    $other_languages = self::getOtherEnabledLanguages();
    foreach ($other_languages as $langcode => $languageName) {
      $entity = self::_latest_revision($entity_id, $vid, $langcode);
      if ($entity->hasTranslation($langcode)) {
        $translation = $entity->getTranslation($langcode);
        $revision = self::prepareNewRevision($translation, $revision_log . " for $langcode", $current_uid);
        $revision->setRevisionTranslationAffected(TRUE);
        $revision->setSyncing(TRUE);
        if ($revision->hasField('moderation_state')) {
          $revision->set('moderation_state', $state_id);
        }
        else {
          $revision->setPublished(TRUE);
        }
        $revision->save();
      }
    }
  }

  /**
   * Prepares a new revision of a given entity, if applicable.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   An entity.
   * @param string|\Drupal\Core\StringTranslation\TranslatableMarkup $message
   *   A revision log message to set.
   * @param integer $current_uid
   *  The current user id.
   *
   * @return \Drupal\Core\Entity\EntityInterface
   *   The moderation state for the given entity.
   */
  public static function prepareNewRevision(EntityInterface $entity, $message, $current_uid) {
    $storage = \Drupal::entityTypeManager()->getStorage($entity->getEntityTypeId());
    if ($storage instanceof ContentEntityStorageInterface) {
      $revision = $storage->createRevision($entity);
      if ($revision instanceof RevisionLogInterface) {
        $revision->setRevisionLogMessage($message);
        $revision->setRevisionCreationTime(\Drupal::time()->getRequestTime());
        $revision->setRevisionUserId($current_uid);
      }
      return $revision;
    }
    return $entity;
  }

  /**
   * Safe delete validation and message prep.
   * @param integer $fid
   *   Id of file.
   * @param string $bundle
   *   An entity.
   * @param bool $show_button
   *   Flag for logic flow and form control.
   * @param string|\Drupal\Core\StringTranslation\TranslatableMarkup &$markup
   * @param string $type
   *   The action type (delete|add|edit)
   * @param integer $limit
   *
   * @return void
   *
   */
  public static function checkFileReferencesMessage($fid = NULL, &$bundle = 'image', &$show_button = TRUE, &$markup = '', $type = 'delete', $limit = 20) {
    $action_result = 'deleted';
    if ($type == 'archived') {
      $action_result = $type;
    }
    if (is_null($fid) || empty($fid)) {
      $message = t('Error');
      return;
    }

    $langcode = \Drupal::languageManager()->getCurrentLanguage()->getId();
    $file = File::load($fid);
    $file_usage = \Drupal::service('file.usage');
    $usage = $file_usage->listUsage($file);

    if (!empty($usage)) {
      // Set error message
      // display error.
      // Prevent delete.
      $show_button = FALSE;
      $entity_type = $file->getEntityTypeId();
      $id = $file->id();
    }

    $iterate_limit = $limit;
    $result = [];
    $items_count = 0;
    $entities = [];
    foreach ($usage as $key => $use) {
      foreach ($use as $type => $id_and_count) {
        $id = key($id_and_count);
        $entity = \Drupal::entityTypeManager()->getStorage($type)->load($id);
        if (is_null($entity)) {
          continue;
        }
        if ($entity instanceOf \Drupal\user\Entity\User) {
          continue;
        }
        $moderation_state = 'published';
        if (!$entity->isPublished()) {
          $moderation_state = 'unpublished';
        }
        if ($entity->hasField('moderation_state')) {
          $moderation_state = $entity->get('moderation_state')->getString();
        }
        if ($moderation_state != 'published') {
          continue;
        }
        $entities[$entity->getEntityTypeId()][$entity->id()]['entity'] = $entity;
        $entities[$entity->getEntityTypeId()][$entity->id()]['count'] = $id_and_count[$entity->id()];
        $entities[$entity->getEntityTypeId()][$entity->id()]['type'] = $type;
        $items_count++;
        if (empty($entities)) {
          $show_button = TRUE;
        }
        else {
          if (count($entities) > 0) {
            $result = $result + $entities;
          }
        }
      }
    }
    // Begin logic here:
    if (count($result) <= 0) {
      $show_button = TRUE;
      $msg_type = t('Safe Delete verification check status');
      $message_ok = t('Other nodes were searched for uuid or linkit link with the node id in their body content, none were found. Improperly referenced url aliases were also checked (via linkit integration in the Safe Delete module).');
      $markup = <<<EOT
<div role="contentinfo" aria-labelledby="message-status-title" class="messages-list__item messages messages--warning">
  <div class="messages__header">
    <h2 id="message-status-title" class="messages__title">
      $msg_type
    </h2>
  </div>
  <div class="messages__content">
    $message_ok
  </div>
</div>
EOT;
    }
    if (count($result) > 0) {
      $show_button = FALSE;
      $msg_type = t('Safe Delete verification check status');
      $temp = 'This file is being used in entities and cannot be %action. Please edit the following content first and remove the reference or delete that entity which is relying on this file:';
      $markup = t($temp, ['%action' => $action_result]) . '<ul>';
      $list_count = 0;
      foreach ($result as $entity_type => $results) {

        foreach ($results as $key => $entity_loaded) {
          if ($iterate_limit <= $list_count) {
            continue;
          }
          $entity_obj = $entity_loaded['entity'];
          if (!$entity_obj) {
            continue;
          }
          $slug = str_replace("_", "/", $entity_type);
          $optional = '';
          if ($entity_type == 'media') {
            $optional = '/edit';
          }
          $markup .= '<li>' . Link::fromTextAndUrl($entity_obj->label(), Url::fromUri('internal:/' . $slug . '/' . $entity_obj->id() . $optional), ['attributes' => ['target' => '_blank']])->toString() . '<span> ' . t('Type') . ': <b>' . $entity_loaded['type'] . ' x ' . $entity_loaded['count'] . '</b></span></li>';
          $list_count++;
        }
      }
      $markup .= '<li>' . Link::fromTextAndUrl(t('Review all usage of this file here.'), Url::fromUri('internal:/admin/content/files/usage/' . $fid), ['attributes' => ['target' => '_blank']])->toString() . '</li>';
      if ($list_count >= $iterate_limit) {
        $markup .= '<li>' . t("... only the first @limit results are displayed.", ['@limit' => $limit]) . '</li>';
      }
      else {
        $markup .= '<li>' . t("... all @list_count results are displayed.", ['@list_count' => $list_count]) . '</li>';
      }
      $markup .= '</ul>';
      $markup = <<<EOT
<div role="contentinfo" aria-labelledby="message-status-title" class="messages-list__item messages messages--warning">
  <div class="messages__header">
    <h2 id="message-status-title" class="messages__title">
      $msg_type
    </h2>
  </div>
  <div class="messages__content">
    $markup
  </div>
</div>
EOT;
    }

  }

  /**
   * Safe delete validation and message prep.
   *
   * @param integer|string $mid
   *   Id of media entity.
   * @param string $bundle
   *   An entity.
   * @param bool $show_button
   *   Flag for logic flow and form control.
   * @param string|\Drupal\Core\StringTranslation\TranslatableMarkup &$markup
   * @param string $type
   *   The action type (delete|add|edit)
   * @param integer $limit
   *
   * @return void
   */
  public static function checkMediaReferencesMessage($mid = NULL, &$bundle = 'image', &$show_button = TRUE, &$markup = '', $type = 'delete', $limit = 20) {
    $action_result = 'deleted';
    if ($type == 'archived') {
      $action_result = $type;
    }
    if (is_null($mid) || empty($mid)) {
      $message = t('Error');
      return;
    }

    $langcode = \Drupal::languageManager()->getCurrentLanguage()->getId();
    $media = Media::load($mid);
    $iterate_limit = $limit;
    $result = [];
    $node_storage = \Drupal::entityTypeManager()->getStorage('node');
    $query = \Drupal::entityQuery('node');
    $and1 = $query->accessCheck(FALSE)
      ->orConditionGroup()
      ->condition('body', $media->uuid(), 'CONTAINS');

    $query->condition($and1);
    $nids = $query->accessCheck(FALSE)
      ->latestRevision()->execute();
    $entities = [];
    $items_count = 0;
    foreach ($nids as $nid) {
      $entity = \Drupal::entityTypeManager()->getStorage('node')->load($nid);
      $moderation_state = 'published';
      if (!$entity->isPublished()) {
        $moderation_state = 'unpublished';
      }
      if ($entity->hasField('moderation_state')) {
        $moderation_state = $entity->get('moderation_state')->getString();
      }
      if ($moderation_state == 'published') {
        $entities[$entity->getEntityTypeId()][$entity->id()] = $entity;
        $items_count++;
      }
    }
    if (empty($nids)) {
      $show_button = TRUE;
    }
    else {
      if (count($entities) > 0) {
        $result = $result + $entities;
      }
    }
    // Begin logic here:
    if (count($result) <= 0) {
      $show_button = TRUE;
      $msg_type = t('Safe Delete verification check status');
      $message_ok = t('Other nodes were searched for uuid or linkit link with the node id in their body content, none were found. Improperly referenced url aliases were also checked (via linkit integration in the Safe Delete module).');
      $markup = <<<EOT
<div role="contentinfo" aria-labelledby="message-status-title" class="messages-list__item messages messages--warning">
  <div class="messages__header">
    <h2 id="message-status-title" class="messages__title">
      $msg_type
    </h2>
  </div>
  <div class="messages__content">
    $message_ok
  </div>
</div>
EOT;
    }
    if (count($result) > 0) {
      $show_button = FALSE;
      $msg_type = t('Safe Delete verification check status');
      $temp = 'This media is being used in entities and cannot be %action. Please edit the following content first and remove the link:';
      $markup = t($temp, ['%action' => $action_result]) . '<ul>';
      $list_count = 0;
      foreach ($result as $entity_type => $results) {

        foreach ($results as $key => $entity_loaded) {
          if ($iterate_limit <= $list_count) {
            continue;
          }
          $entity_obj = $entity_loaded;
          if (!$entity_obj) {
            continue;
          }
          $slug = str_replace("_", "/", $entity_type);
          $markup .= '<li>' . Link::fromTextAndUrl($entity_obj->label(), Url::fromUri('internal:/' . $slug . '/' . $entity_obj->id()), ['attributes' => ['target' => '_blank']])->toString() . '</li>';
          $list_count++;
        }
      }
      if ($list_count >= $iterate_limit) {
        $markup .= '<li>' . t("... only the first @limit results are displayed.", ['@limit' => $limit]) . '</li>';
      }
      else {
        $markup .= '<li>' . t("... all @list_count results are displayed.", ['@list_count' => $list_count]) . '</li>';
      }
      $markup .= '</ul>';
      $markup = <<<EOT
<div role="contentinfo" aria-labelledby="message-status-title" class="messages-list__item messages messages--warning">
  <div class="messages__header">
    <h2 id="message-status-title" class="messages__title">
      $msg_type
    </h2>
  </div>
  <div class="messages__content">
    $markup
  </div>
</div>
EOT;
    }
  }

  /**
   * Safe delete validation and message prep.
   *
   * @param integer|string $nid
   *   Id of node entity.
   * @param string $bundle
   *   An entity.
   * @param bool $show_button
   *   Flag for logic flow and form control.
   * @param string|\Drupal\Core\StringTranslation\TranslatableMarkup &$markup
   * @param string $type
   *   The action type (delete|add|edit)
   * @param integer $limit
   *
   * @return void
   *
   */
  public static function checkNodeReferencesMessage($nid = NULL, &$bundle = 'page', &$show_button = TRUE, &$markup = '', $type = 'delete', $limit = 20) {
    $root_nid = $nid;
    $action_result = 'deleted';
    if ($type == 'archived') {
      $action_result = $type;
    }
    if ($type == 'archived_archived') {
      $action_result = $type;
    }
    if ($type == 'delete') {
      $action_result = $type;
    }
    if (is_null($nid) || empty($nid)) {
      $message = t('Error');
      return;
    }

    $langcode = \Drupal::languageManager()->getCurrentLanguage()->getId();
    $node = Node::load($nid);
    if (!$node instanceof NodeInterface) {
      $message = t('Error: Safe Delete cannot check references for missing node with id %id.', ['%id' => $nid]);
      self::addMessage($message);
      return;
    }
    $root_entity_title = $node->label();
    $bundle = $node->getType();
    $iterate_limit = $limit;
    $result = [];
    $node_storage = \Drupal::entityTypeManager()->getStorage('node');
    $query = \Drupal::entityQuery('node');
    $and1 = $query->accessCheck(FALSE)
      ->orConditionGroup()
      ->condition('body', $node->uuid(), 'CONTAINS');

    $query->condition($and1);
    $nids = $query->accessCheck(FALSE)
      ->latestRevision()->execute();
    $entities = [];
    $items_count = 0;
    foreach ($nids as $nid) {
      $entity = \Drupal::entityTypeManager()->getStorage('node')->load($nid);
      $moderation_state = 'published';
      if (!$entity->isPublished()) {
        $moderation_state = 'unpublished';
      }
      if ($entity->hasField('moderation_state')) {
        $moderation_state = $entity->get('moderation_state')->getString();
      }
      if ($moderation_state == 'published') {
        $entities[$entity->getEntityTypeId()][$entity->id()] = $entity;
        $items_count++;
      }
      if ($action_result == 'archived_archived' && $moderation_state == 'archived') {
        $entities[$entity->getEntityTypeId()][$entity->id()] = $entity;
        $items_count++;
      }
      if ($action_result == 'archived_archived' && $moderation_state == 'draft') {
        $entities[$entity->getEntityTypeId()][$entity->id()] = $entity;
        $items_count++;
      }
      if ($action_result == 'archived_archived' && $moderation_state == 'published') {
        $entities[$entity->getEntityTypeId()][$entity->id()] = $entity;
        $items_count++;
      }
      if ($action_result == 'archived' && $moderation_state == 'draft') {
        $entities[$entity->getEntityTypeId()][$entity->id()] = $entity;
        $items_count++;
      }
      if ($action_result == 'archived' && $moderation_state == 'published') {
        $entities[$entity->getEntityTypeId()][$entity->id()] = $entity;
        $items_count++;
      }
      if ($action_result == 'delete' && $moderation_state == 'draft') {
        $entities[$entity->getEntityTypeId()][$entity->id()] = $entity;
        $items_count++;
      }
      if ($action_result == 'delete' && $moderation_state == 'archived') {
        $entities[$entity->getEntityTypeId()][$entity->id()] = $entity;
        $items_count++;
      }
      if ($action_result == 'delete' && $moderation_state == 'published') {
        $entities[$entity->getEntityTypeId()][$entity->id()] = $entity;
        $items_count++;
      }
    }
    if (empty($nids)) {
      $show_button = TRUE;
    }
    else {
      if (count($entities) > 0) {
        $result = $result + $entities;
      }
    }
    // Begin logic here:
    if (count($result) <= 0) {
      $show_button = TRUE;
      $msg_type = t('Safe Delete verification check status');
      $message_ok = t('Other nodes were searched for uuid or linkit link with the node id in their body content, none were found.  Improperly referenced url aliases were verified (via linkit integration in the Safe Delete module).');
      $markup = <<<EOT
<div role="contentinfo" aria-labelledby="message-status-title" class="messages-list__item messages messages--warning">
  <div class="messages__header">
    <h2 id="message-status-title" class="messages__title">
      $msg_type
    </h2>
  </div>
  <div class="messages__content">
    $message_ok
  </div>
</div>
EOT;
    }
    if (count($result) > 0) {
      $show_button = FALSE;
      $msg_type = t('Safe Delete verification check status');
      if ($action_result == 'archived_archived') {
        $temp = 'The %action candidate page "%root_entity_title" (node %nid) is linked from other pages.';
        $markup = t($temp, [
          '%root_entity_title' => $root_entity_title,
          '%nid' => $root_nid,
          '%action' => 'archived',
        ]);
      }
      else {
        $action = $action_result;
        if ($action_result == 'delete') {
          $action = 'deleted';
        }
        $temp = 'The page "%root_entity_title" (node %nid) is linked from other pages on the site and cannot be %action. Please remove the links to "%root_entity_title" from the following pages:';
        $markup = t($temp, [
          '%root_entity_title' => $root_entity_title,
          '%nid' => $root_nid,
          '%action' => $action,
        ]);
      }
      $list_count = 0;
      // Collect by moderation state first.
      $draft_entities = [];
      $archived_entities = [];
      $archived_archived_entities = [];
      $published_entities = [];

      foreach ($result as $entity_type => $results) {
        foreach ($results as $key => $entity_loaded) {
          $entity_obj = $entity_loaded;
          if (!$entity_obj) {
            continue;
          }

          // Determine moderation state:
          // Prefer explicit 'moderation_state' field if present.
          // Otherwise, if it's a Node and isPublished() === FALSE, treat as draft.
          // Fallback: assume published.
          $state = 'published';
          if ($entity_obj instanceof \Drupal\Core\Entity\ContentEntityInterface && $entity_obj->hasField('moderation_state')) {
            $value = $entity_obj->get('moderation_state')->value;
            if ($value === 'draft') {
              $state = 'draft';
            }
            if ($value === 'archived') {
              $state = 'archived';
            }
          }
          else {
            // Sensible fallback for nodes without the field but using status.
            if ($entity_obj instanceof \Drupal\node\NodeInterface && !$entity_obj->isPublished()) {
              $state = 'draft';
            }
          }

          if ($state === 'draft') {
            $draft_entities[] = [$entity_type, $entity_obj];
          }
          else if ($state === 'archived') {
            if ($action_result == 'archived_archived') {
              $archived_archived_entities[] = [$entity_type, $entity_obj];
            }
            else {
              $archived_entities[] = [$entity_type, $entity_obj];
	    }
          }
          else {
            $published_entities[] = [$entity_type, $entity_obj];
          }
        }
      }

      // Render: drafts section first (if any), then published.
      $render_section = function (array $items, string $header) use (&$markup, &$list_count, $iterate_limit) {
        if (empty($items)) {
          return;
        }

        // Only add the header if we still have room to render at least one item.
        if ($list_count < $iterate_limit) {
          $markup .= '<h6>' . $header . '</h6>';
        }
        else {
          return;
        }
        $markup .= '<ul>';

        foreach ($items as [$entity_type, $entity_obj]) {
          if ($list_count >= $iterate_limit) {
            break;
          }
          $slug = str_replace('_', '/', $entity_type);
          $markup .= '<li>' . Link::fromTextAndUrl(
            $entity_obj->label(),
            Url::fromUri('internal:/' . $slug . '/' . $entity_obj->id()),
            ['attributes' => ['target' => '_blank']]
          )->toString() . '</li>';
          $list_count++;
        }
        $markup .= '</ul>';
      };

      if (!empty($archived_archived_entities)) {
        if (empty($draft_entities) && empty($published_entities)) {
          $show_button = TRUE;
	}
      }

      // Drafts first (only if any).
      $render_section($draft_entities, '<strong>Draft nodes</strong> with references to this that need to be dereferenced:');

      // Then published (only if any).
      $render_section($published_entities, '<strong>Published nodes</strong> with references to this that need to be dereferenced:');

      // Archived archived first (only if any).
      $render_section($archived_archived_entities, '<strong>Archived nodes</strong> referencing this (For your information only):');

      // Archived first (only if any).
      $render_section($archived_entities, '<strong>Archived nodes</strong> that need to be dereferenced or deleted first:');

      if ($list_count >= $iterate_limit) {
        $markup .= '<h6>' . t("... only the first @limit results are displayed.", ['@limit' => $limit]) . '</h6>';
      }
      else {
        $markup .= '<h6>' . t("... all @list_count results are displayed.", ['@list_count' => $list_count]) . '</h6>';
      }
      $markup = <<<EOT
<div role="contentinfo" aria-labelledby="message-status-title" class="messages-list__item messages messages--warning">
  <div class="messages__header">
    <h2 id="message-status-title" class="messages__title">
      $msg_type
    </h2>
  </div>
  <div class="messages__content">
    $markup
  </div>
</div>
EOT;
    }
  }

  /**
   * Search for a menu link.
   *
   * @param integer|string $nid
   *
   * @return bool
   *   True if a menu has a link.
   */
  public static function hasMenuLink($nid) {
    static::addToLog(__function__);
    $parentMenuLink = NULL;

    $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
    $results = $menu_link_manager->loadLinksByRoute('entity.node.canonical', ['node' => $nid]);

    foreach ($results as $item) {
      $route = '';
      if ($item->getUrlObject()->isRouted()) {
        $route = $item->getUrlObject()->getRouteName();
      }
      if ('entity.node.canonical' == $route && $item->getUrlObject()->isRouted()) {
        $params = $item->getUrlObject()->getRouteParameters();
        $linkNodeId = $params['node'];

        if ($linkNodeId == $nid) {
          return TRUE;
        }
      }
    } // End of foreach.
    return FALSE;
  }

  /**
   * Search the page without being refered in other pages.
   */
  public static function findOtherLinkedReferences($uuid, $nid): bool {
    if (empty($nid) || !is_numeric($nid)) {
      return FALSE;
    }
    // @todo later,also in case not using linkit also check for /node/{id} links in case NOT using linkit correctly.
    $node_storage = \Drupal::entityTypeManager()->getStorage('node');
    $query = \Drupal::entityQuery('node');
    $and1 = $query->accessCheck(FALSE)
      ->orConditionGroup()
      ->condition('body', 'node/' . $nid . '"', 'CONTAINS');
    $query->condition($and1);
    $nids = $query->accessCheck(FALSE)
      ->latestRevision()->execute();
    if (!empty($nids)) {
      return TRUE;
    }
    return FALSE;
  }

  /**
   * Search the page without being refered in other pages.
   */
  public static function findLinkitReferences($uuid, $nid): bool {
    if (strlen($uuid) < 15 || empty($uuid)) {
      return FALSE;
    }
    $node_storage = \Drupal::entityTypeManager()->getStorage('node');
    $query = \Drupal::entityQuery('node');
    $and1 = $query->accessCheck(FALSE)
      ->orConditionGroup()
      ->condition('body', $uuid, 'CONTAINS');
    $query->condition($and1);
    $nids = $query->accessCheck(FALSE)
      ->execute();

    if (empty($nids)) {
      return FALSE;
    }

    $config = \Drupal::config('safedelete.settings');
    $value = $config->get('check_published_only');
    $checkPublishedOnly = is_bool($value) ? $value : FALSE;

    if ($checkPublishedOnly) {
      // Only treat as “referenced” if at least one target node is published.
      $nodes = $node_storage->loadMultiple($nids);
      foreach ($nodes as $node) {
        if (!$node) {
          continue;
        }

        $is_published = FALSE;

        if ($node->hasField('moderation_state')) {
          $is_published = $node->get('moderation_state')->getString() === 'published';
        }
        else {
          // Standard Drupal 10/11 publish check.
          $is_published = $node->isPublished();
        }

        if ($is_published) {
          return TRUE;
        }
      }

      // No published nodes found.
      return FALSE;
    }

    return TRUE;
  }

  /**
   * Helper function to delete all records associated to node id in file_usage
   * table including the default record (type = media).
   *
   * @param int $entityid
   *   The entity id.
   */
  public static function deleteRecordsInFileUsage($entityid = 0): void {
    $database = \Drupal::database();
    $query = $database->select('file_usage', 'fu')
      ->condition('fu.id', $entityid, '=')
      ->condition('fu.type', 'node', '=')
      ->fields('fu', ['fid']);
    $result = $query->execute();
    foreach ($result as $record) {
      $fid = $record->fid;
      if ($fid > 0) {
        $querydelete = $database->delete('file_usage')
          ->condition('id', $entityid, '=')
          ->condition('type', 'node', '=')
          ->execute();
        // Break from the loop due to deleting all records associated to node id.
        break;
      }
    }
  }

  /**
   *
   */
  public static function listOrphanedNodes(&$reporteddate = '', &$orphanedpages_results = [], $filedirectory = '', $database = NULL) {
    $node_types = NodeType::loadMultiple();
    if (empty($node_types)) {
      return NULL;
    }

    // A safe default value is required.
    $first_bundle = '';
    foreach ($node_types as $node_type_test => $type_test) {
      // A safe default value.
      $first_bundle = $node_type_test;
      break;
    }

    $exceptidsconfig = \Drupal::config('safedelete.settings')->get('exceptionofnodes');
    $exceptionarray = [];
    if (is_array($exceptidsconfig)) {
      $exceptionarray = $exceptidsconfig;
    }
    else {
      $exceptionarray = explode(',', (string) $exceptidsconfig);
    }
    if (empty($exceptionarray)) {
      $exceptionarray = [];
    }
    $super_type = \Drupal::config('safedelete.settings')->get('orphanedpagewithoutmenulink');
    if (empty($super_type)) {
      // Use the safe default value.
      $super_type = $first_bundle;
    }
    $defconfig = \Drupal::config('safedelete.settings')->get('orphanedpagedefinition');
    if (empty($defconfig)) {
      // Use the safe default value.
      $defconfig = [];
      $defconfig[] = $first_bundle;
    }
    $arrayoftypes = [];
    $count = 0;

    $query = \Drupal::entityQuery('node');
    $query->accessCheck(FALSE)
      ->condition('type', $defconfig, 'IN');
    $nodeids = $query->accessCheck(FALSE)
      ->sort('nid', 'ASC')->execute();

    foreach ($defconfig as $type) {
      if (strlen($type) > 1) {
        $count = $count + 1;
        $arrayoftypes[$count] = $type;
      }
    }
    $directoryexists = \Drupal::service('file_system')->prepareDirectory($filedirectory);
    if (!$directoryexists) {
      \Drupal::service('file_system')->mkdir($filedirectory);
    }
    else {
      // Clean up old json files before new json files are generated.
      $files = \Drupal::service('file_system')->scanDirectory($filedirectory, '/.json/');
      $filearraynid = [];
      foreach ($files as $file) {
        $fileuri = $file->uri;
        \Drupal::service('file_system')->deleteRecursive($fileuri);
      }
    }
    foreach ($nodeids as $nid) {
      // Reset flag.
      $resultflag = FALSE;
      $entity_manager = \Drupal::entityTypeManager();
      $node = $entity_manager->getStorage('node')->load($nid);
      if (isset($node) && sizeof($exceptionarray) >= 0 && !in_array($nid, $exceptionarray)) {
        $nmstate = 'published';
        if (!$node->isPublished()) {
          $moderation_state = 'unpublished';
        }
        if ($node->hasField('moderation_state')) {
          $nmstate = $node->get('moderation_state')->getString();
        }
        if ($nmstate == 'published') {
          $uuid = AdminHelper::getUuidFromNid($nid, $database);
          $type = AdminHelper::getNodeTypeFromNid($nid, $database);
          $resultreason = "";
          if ($type == $super_type && !AdminHelper::hasMenuLink($nid)) {
            // Do further check if the page is linked by other pages.
            if (!AdminHelper::findLinkitReferences($uuid, $nid)) {
              $resultflag = TRUE;
              $resultreason = t('No Menu Link and No Other Pages linked');
            }
          }
          elseif ($type != $super_type) {
            // Check if the special page type is linked by other pages.
            if (!AdminHelper::findLinkitReferences($uuid, $nid)) {
              $resultflag = TRUE;
              $resultreason = t('No Other Pages linked to this.');
            }
          }
        }
      }

      if ($resultflag) {
        // @todo Performance and scalability improvement suggestion:
        // Build a custom pager and do the node load only for the current page.
        // Refactor this so that the nid is stored in an array in this forloop,
        // then just after the for loop process the nid array do the node load for only the current 'page'.
        $langcode = \Drupal::languageManager()->getCurrentLanguage()->getId();
        $ntype = $node->bundle();
        $ntitle = $node->getTitle();
        $reporteddateobj = new \DateTime('now');
        $reporteddate = $reporteddateobj->format('Y-m-d H:i:s');
        $orphanedpages_results[$nid]['nid'] = $nid;
        $orphanedpages_results[$nid]['title'] = $ntitle;
        $orphanedpages_results[$nid]['href'] = AdminHelper::getUrlForNode($nid, $langcode);
        $orphanedpages_results[$nid]['type'] = $node->type->entity->label();
        $orphanedpages_results[$nid]['reason'] = $resultreason;
        $orphanedpages_results[$nid]['reporteddate'] = $reporteddate;

        // Save date into the json file.
        $arrayforjsonobj = [
          'nid' => $nid,
          'title' => $ntitle,
          'type' => $node->type->entity->label(),
          'href' => AdminHelper::getUrlForNode($nid, $langcode),
          'reason' => $resultreason,
          'reporteddate' => $reporteddate,
        ];
        $json = json_encode($arrayforjsonobj, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        $fp = $filedirectory . $nid . '.json';
        $file = \Drupal::service('file.repository')->writeData($json, $fp, FileSystemInterface::EXISTS_REPLACE);
      }
    }
  }

  /**
   *
   */
  public static function getUuidFromNid($nid, $database) {
    $result = $database->query('select uuid from node where nid = :node_id', [':node_id' => $nid])
      ->fetchAllAssoc('uuid', \PDO::FETCH_ASSOC);
    $uuid = array_keys($result);
    return reset($uuid);
  }

  /**
   *
   */
  public static function getNodeTypeFromNid($nid, $database) {
    $result = $database->query('select type from node where nid = :node_id', [':node_id' => $nid])
      ->fetchAllAssoc('type', \PDO::FETCH_ASSOC);
    $type = array_keys($result);
    return reset($type);
  }

  /**
   * Gets the url for a node.
   *
   * @param mixed $nid
   *   The node id.
   * @param string $langcode
   *   The two letter language code string.
   *
   * @returns (string) $url
   *   The url for a node.
   */
  public static function getUrlForNode($nid, $lang = 'en'): string {
    $host_path = \Drupal::request()->getSchemeAndHttpHost();
    $base_path = \Drupal::request()->getBasePath();
    $is_multilingual = (int) \Drupal::languageManager()->isMultilingual();
    $has_langprefix = FALSE;

    if ($is_multilingual) {
      static::addToLog($is_multilingual . ' = multilingual', FALSE);
      $config = \Drupal::configFactory()->get('language.negotiation');
      $prefix_config = $config->get('url.prefixes');
      if (isset($prefix_config[$lang])) {
        if ($prefix_config[$lang] == $lang) {
          $has_langprefix = TRUE;
        }
      }
    }
    if (strlen($base_path) > 0) {
      if (stripos(strval($base_path), '/') < 0) {
        $host_path = $host_path . '/' . $base_path;
      }
      else {
        $host_path = $host_path . $base_path;
      }
    }
    $relative = \Drupal::service('path_alias.manager')->getAliasByPath('/node/' . $nid, $lang);

    if ($has_langprefix && isset($relative['alias'])) {
      $url = $host_path . '/' . $lang . $relative['alias'];
    }
    elseif ($has_langprefix) {
      $url = $host_path . '/' . $lang . '/node/' . $nid;
    }
    else {
      $url = $host_path . '/node/' . $nid;
    }
    return $url;
  }

  /**
   * Check if the href contains a token before user publishes the current page.
   *
   * @param (string) $bodyval
   *   The body to process.
   * @param (bool) $foundtokenhref
   *   Flag to identify as found.
   * @param (string) $markup
   *   The message to output.
   *
   * @returns (bool) $foundtokenhref
   *   Flag.
   */
  public static function checkUrlToken($bodyval, &$foundtokenhref = FALSE, &$markup = '') {
    $regex_token = '/\?auHash=/';
    preg_match_all($regex_token, $bodyval, $matches, PREG_SET_ORDER);
    foreach ($matches as $match_token) {
      $tokenhref = reset($match_token);
      if (isset($tokenhref) && strlen($tokenhref) == 8) {
        if (!$foundtokenhref) {
          $foundtokenhref = TRUE;
          $msg = t('Please remove any links to Preview/Draft pages (pages whose URL contains "auHash").');
          $markup = '<p style="color:#e0ac00; font-size:16px;"><strong>' . $msg . '</strong></p>';
          break;
        }
      }
    }
  }

  /**
   * Verify if the page is published or not.
   */
  public static function checkPagePublished($formbody, &$foundunpublishingnode = FALSE, &$markup = '') {
    $temparry = [];
    $regex_mediaobj = "/data-entity-type=\"node\" data-entity-uuid=\"([a-z]|[0-9]){8}-(([0-9]|[a-z]){4}-){3}([0-9]|[a-z]){12}\"/";
    $regex_uuid = "/([a-z]|[0-9]){8}-(([0-9]|[a-z]){4}-){3}([0-9]|[a-z]){12}/";
    preg_match_all($regex_mediaobj, $formbody, $matches, PREG_SET_ORDER);
    foreach ($matches as $match) {
      $tmpmsg = '';
      $node = reset($match);
      preg_match_all($regex_uuid, $node, $id_match, PREG_SET_ORDER);
      $nodeuuid = $id_match[0][0];
      $nentity = \Drupal::service('entity.repository')->loadEntityByUuid('node', $nodeuuid);
      if (is_null($nentity)) {
        continue;
      }
      $nodeid = $nentity->id();
      $nmstate = 'published';
      if (!$nentity->isPublished()) {
        $moderation_state = 'unpublished';
      }
      if ($nentity->hasField('moderation_state')) {
        $nmstate = $nentity->get('moderation_state')->getString();
      }
      if ($nmstate != 'published') {
        if (!$foundunpublishingnode) {
          $foundunpublishingnode = TRUE;
          $msg = t('Please publish the identified pages first and then publish the current one.');
          $markup = '<p style="color:#e0ac00; font-size:16px;"><strong>' . $msg . '</strong></p>';
          $markup = $markup . '<ul>';
        }
        $tmpmsg = '<li>' . $node . " /node/" . $nodeid . '</li>';
        if (!in_array($tmpmsg, $temparry, TRUE)) {
          $markup = $markup . $tmpmsg;
          array_push($temparry, $tmpmsg);
        }
      }
    }
    if ($foundunpublishingnode) {
      $markup = $markup . '</ul>';
    }
  }

  /**
   * Verify if the url in the form body is absolute or not.
   *
   * Returns (bool)
   *   True or false.
   */
  public static function checkInternalAnchors($formbody, &$found_relative_url = FALSE, &$markup = '', $langcode = 'en') {
    // Skip comments.
    $config = HTMLPurifier_Config::createDefault();
    // Activate the removal of comments.
    $config->set('Core.RemoveProcessingInstructions', TRUE);
    // Create an instance of HTML Purifier with the specified configuration.
    $config->set('HTML.AllowedAttributes', [
      'a.href',
      'a.data-entity-substitution',
      'a.data-entity-type',
      'a.data-entity-uuid',
    ]);

    // Extend the HTML Definition to explicitly allow these attributes.
    $config->set('HTML.DefinitionID', 'custom-attributes');
    // Increment this if updating definitions.
    $config->set('HTML.DefinitionRev', 1);

    if ($def = $config->maybeGetRawHTMLDefinition()) {
      // Add custom data attributes to <a> elements.
      $def->addAttribute('a', 'data-entity-substitution', 'Text');
      $def->addAttribute('a', 'data-entity-type', 'Text');
      $def->addAttribute('a', 'data-entity-uuid', 'Text');
    }
    $original_error_reporting = error_reporting();
    error_reporting($original_error_reporting & ~E_WARNING);
    $purifier = new HTMLPurifier($config);
    // Clean the HTML content.
    $formbody = $purifier->purify($formbody);
    error_reporting($original_error_reporting);

    // Retrieve the base path dynamically.
    $base_path = \Drupal::request()->getBasePath();

    $regex_tokenabspath = '/<a (data-entity-substitution|data-entity-type|data-entity-uuid|href)*.+>/mU';
    preg_match_all($regex_tokenabspath, $formbody, $pathmatches, PREG_SET_ORDER, 0);
    $temparry = [];
    $language = new Language([
      'id' => $langcode,
    ]);
    $url_options = [
      'absolute' => TRUE,
      'language' => $language,
    ];
    $url_options_path = [
      'absolute' => FALSE,
      'language' => $language,
    ];
    $test_base_url = Url::fromRoute('<front>', [], $url_options)->toString();
    $test_base_path = Url::fromRoute('<front>', [], $url_options_path)->toString();
    foreach ($pathmatches as $match) {
      $tmpmsg = '';
      $hrefpath = reset($match);
      // Ignore the token case.
      $tokenhead = "?auHash=";
      if (empty($hrefpath)) {
        continue;
      }
      $anchor = $hrefpath . '</a>';
      // Ignore error/warning.
      $xmlEl = simplexml_load_string($anchor, "SimpleXMLElement", LIBXML_NOERROR | LIBXML_NOWARNING);
      if (is_bool($xmlEl) || !isset($xmlEl->attributes()->{'href'})) {
        continue;
      }
      $hrefvalue = $xmlEl->attributes()->{'href'}->__toString();

      // Ensure the href value includes the base path if it's missing.
      if (!str_starts_with($hrefvalue, $base_path)) {
        $hrefvalue = $base_path . ltrim($hrefvalue, '/');
      }

      $uuid = $xmlEl->attributes()->{'data-entity-uuid'};
      if (!is_null($uuid)) {
        $uuid = $uuid->__toString();
        if (strlen($uuid) > 10) {
          $uuid = '';
          continue;
        }
      }

      if (is_string($hrefvalue) && strpos($hrefvalue, $tokenhead) == FALSE) {
        $path = $hrefvalue;
        if (UrlHelper::isValid($path, FALSE)) {
          $relativepathstring = $path;

          $path = urldecode(trim($path, '/'));
          self::removeBasePath($path, $test_base_path, $language);
          $path_args = explode('/', $path);
          $path = str_replace('/' . $langcode . '/', '', '/' . $path);
          $path = urldecode(trim($path, '/'));
          $prefix = array_shift($path_args);
          if (empty($prefix)) {
            $prefix = $langcode;
          }

          $safeenableprefix = \Drupal::config('safedelete.settings')->get('safeenableprefix');
          if ($safeenableprefix) {
            $safeprefix = \Drupal::config('safedelete.settings')->get('safeprefix');
            $path = str_replace('/' . $safeprefix, '', $path);
          }
          if ($path == $langcode) {
            $nodpath = \Drupal::configFactory()->get('system.site')->get('page.front');
          }
          else {
            $nodpath = \Drupal::service('path_alias.manager')->getPathByAlias($path, $langcode);
            if (!str_starts_with($nodpath, 'node')) {
              $nodpath = '/node/' . self::getNodeIdByAlias($path, $langcode);
            }
          }

          if (preg_match('/node\/(\d+)/', $nodpath, $matches)) {
            $hrefnode = Node::load($matches[1]);
            if (isset($hrefnode)) {
              if (!$found_relative_url) {
                $found_relative_url = TRUE;
                $msg = t('Please use Linkit to complete the reference.');
                $markup = '<p style="color:#e0ac00; font-size:16px;"><strong>' . $msg . '</strong></p>';
                $markup = $markup . '<ul>';
              }
              $tmpmsg = '<li>' . $relativepathstring . '</li>';
              if (!in_array($tmpmsg, $temparry, TRUE)) {
                $markup = $markup . $tmpmsg;
                array_push($temparry, $tmpmsg);
              }
            }
          }
        }
      }
    }
    if ($found_relative_url) {
      $markup = $markup . '</ul>';
    }
  }

  /**
   * Verify if the url in the form body is absolute or not.
   *
   * Returns (bool)
   *   True or false.
   */
  public static function checkAbsoluteUrlPlus($formbody, &$found_absolute_url = FALSE, &$markup = '', $langcode = 'en') {
    $regex_tokenabspath = '/href=\".*\"/m';
    preg_match_all($regex_tokenabspath, $formbody, $pathmatches, PREG_SET_ORDER);
    $temparry = [];
    $language = new Language([
      'id' => $langcode,
    ]);
    $url_options = [
      'absolute' => TRUE,
      'language' => $language,
    ];
    foreach ($pathmatches as $match) {
      $tmpmsg = '';
      $hrefpath = reset($match);
      // Ignore the token case.
      $tokenhead = "?auHash=";
      if (strpos($hrefpath, $tokenhead) == FALSE) {
        $path = str_replace("href=\"", "", $hrefpath);
        $path = str_replace("\"", "", $path);
        $path = self::removeBasePath($path, NULL, $language);
        self::replaceOtherSafeBaseUrls($path, $langcode);
        if (UrlHelper::isExternal($path) && UrlHelper::isValid($path, TRUE)) {
          if (UrlHelper::externalIsLocal($path, \Drupal::request()->getSchemeAndHttpHost())) {
            $absolutepathstring = $path;
            $base_path = \Drupal::request()->getBasePath();
            $host = parse_url($path, PHP_URL_HOST);
            $host_end = strpos($path, $host) + strlen($host) + strlen($base_path);
            $path = substr($path, $host_end);
            $path = urldecode(trim($path, '/'));
            $path_args = explode('/', $path);
            $prefix = array_shift($path_args);
            $path = '/' . implode('/', $path_args);
            $nodpath = \Drupal::service('path_alias.manager')->getPathByAlias($path, $prefix);
            if (!str_starts_with($nodpath, '/node')) {
              self::addToLog('$path:' . $path, TRUE);
              $nodpath = '/node/' . self::getNodeIdByAlias($path, $langcode);
            }
            if (is_null($nodpath)) {
              continue;
            }
            if (preg_match('/node\/(\d+)/', $nodpath, $matches)) {
              $hrefnode = Node::load($matches[1]);
              if (isset($hrefnode)) {
                if (!$found_absolute_url) {
                  $found_absolute_url = TRUE;
                  $msg = t('Please use Linkit to replace the absolute url reference.');
                  $markup = '<p style="color:#e0ac00; font-size:16px;"><strong>' . $msg . '</strong></p>';
                  $markup = $markup . '<ul>';
                }
                $tmpmsg = '<li>' . $absolutepathstring . '</li>';
                if (!in_array($tmpmsg, $temparry, TRUE)) {
                  $markup = $markup . $tmpmsg;
                  array_push($temparry, $tmpmsg);
                }
              }
            }
          }
        }
      }
    }
    if ($found_absolute_url) {
      $markup = $markup . '</ul>';
    }
  }

  /**
   * Verify if the url in the form body is absolute or not.
   *
   * Returns (bool)
   *   True or false.
   */
  public static function checkAbsoluteUrl($formbody, &$found_absolute_url = FALSE, &$markup = '') {
    $regex_tokenabspath = '/href=\".*\"/m';
    preg_match_all($regex_tokenabspath, $formbody, $pathmatches, PREG_SET_ORDER);
    $temparry = [];
    foreach ($pathmatches as $match) {
      $tmpmsg = '';
      $hrefpath = reset($match);
      // Ignore the token case.
      $tokenhead = "?auHash=";
      if (strpos($hrefpath, $tokenhead) == FALSE) {
        $path = str_replace("href=\"", "", $hrefpath);
        $path = str_replace("\"", "", $path);
        if (UrlHelper::isExternal($path) && UrlHelper::isValid($path, TRUE)) {
          if (UrlHelper::externalIsLocal($path, \Drupal::request()->getSchemeAndHttpHost())) {
            $absolutepathstring = $path;
            $base_path = \Drupal::request()->getBasePath();
            $host = parse_url($path, PHP_URL_HOST);
            $host_end = strpos($path, $host) + strlen($host) + strlen($base_path);
            $path = substr($path, $host_end);
            $path = urldecode(trim($path, '/'));
            $path_args = explode('/', $path);
            $prefix = array_shift($path_args);
            $path = '/' . implode('/', $path_args);
            $nodpath = \Drupal::service('path_alias.manager')->getPathByAlias($path, $prefix);
            if (preg_match('/node\/(\d+)/', $nodpath, $matches)) {
              $hrefnode = Node::load($matches[1]);
              if (isset($hrefnode)) {
                if (!$found_absolute_url) {
                  $found_absolute_url = TRUE;
                  $msg = t('Please use Linkit to complete the reference.');
                  $markup = '<p style="color:#e0ac00; font-size:16px;"><strong>' . $msg . '</strong></p>';
                  $markup = $markup . '<ul>';
                }
                $tmpmsg = '<li>' . $absolutepathstring . '</li>';
                if (!in_array($tmpmsg, $temparry, TRUE)) {
                  $markup = $markup . $tmpmsg;
                  array_push($temparry, $tmpmsg);
                }
              }
            }
          }
        }
      }
    }
    if ($found_absolute_url) {
      $markup = $markup . '</ul>';
    }
  }

  /**
   * @param string $alias
   *   An alias to load.
   * @return int|string
   *   Returns a node id.
   */
  public static function getNodeIdByAlias(string $alias, $langcode = 'en') {
    $data = NULL;
    try {
      $query = \Drupal::entityQuery('path_alias');
      $query->condition('alias', '/' . $alias, '=')
        ->condition('langcode', $langcode)
        ->accessCheck(FALSE);
      $aliasIds = $query->execute();
      foreach ($aliasIds as $id) {
        $path = PathAlias::load($id)->getPath();
        $data = (int) str_replace("/node/", "", $path);
      }
    }
    catch (\Exception $e) {
      $data = $e->getMessage();
    }
    return $data;
  }

  /**
   * Handle other base paths for edge case site builds like this.
   *
   * @param string $path
   *   A path to compare.
   * @param string $langcode
   *   The two letter language code string.
   */
  public static function replaceOtherSafeBaseUrls(&$path = '', $langcode = 'en'): void {
    if (!str_starts_with($path, 'http')) {
      return;
    }
    $language = new Language([
      'id' => $langcode,
    ]);
    $url_options_path = [
      'absolute' => FALSE,
      'language' => $language,
    ];
    $test_base_path = Url::fromRoute('<front>', [], $url_options_path)->toString();
    self::addToLog('test_base_path:' . $test_base_path . ' : ' . $path, TRUE);
    if (strlen($test_base_path) > strlen('/' . $langcode)) {
      return;
    }
    // Continue.
    $url_options = [
      'absolute' => TRUE,
      'language' => $language,
    ];
    $test_base_url = Url::fromRoute('<front>', [], $url_options)->toString();
    $baseother_enable = \Drupal::config('safedelete.settings')->get('safeenablebaseurlother');
    $baseother2_enable = \Drupal::config('safedelete.settings')->get('safeenablebaseurlother2');
    if ($baseother_enable) {
      $baseother = \Drupal::config('safedelete.settings')->get('safebaseurlother');
      $path = str_replace($baseother . '/' . $langcode, $test_base_url, $path);
      $path = str_replace($baseother, $test_base_url, $path);
    }
    if ($baseother2_enable) {
      $baseother2 = \Drupal::config('safedelete.settings')->get('safebaseurlother2');
      $path = str_replace($baseother2 . '/' . $langcode, $test_base_url, $path);
      $path = str_replace($baseother2, $test_base_url, $path);
    }
  }

  /**
   *
   * @param string $path
   * @param Drupal\Core\Language\Language $language
   * @param string $base_path
   * @return string $cleaned
   */
  public static function removeBasePath($path, $base_path = NULL, $language = NULL) {
    if (is_null($base_path)) {
      if (is_null($language)) {
        $language = new Language([
          'id' => $langcode,
        ]);
      }
      $url_options = [
        'absolute' => FALSE,
        'language' => $language,
      ];
      $base_path = Url::fromRoute('<front>', [], $url_options)->toString();
    }
    $cleaned = str_replace($base_path, '', $path);
    return $cleaned;
  }
}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc