entity_mesh-1.1.1/src/Entity.php

src/Entity.php
<?php

namespace Drupal\entity_mesh;

use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Database\StatementInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\TranslatableInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Symfony\Component\Routing\Route;

/**
 * Service description.
 */
abstract class Entity {

  /**
   * The mesh type.
   *
   * @var string
   */
  protected $type;

  /**
   * Entity Mesh Repository.
   *
   * @var \Drupal\entity_mesh\RepositoryInterface
   */
  protected $entityMeshRepository;

  /**
   * The config factory manager.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $config;

  /**
   * The entity repository.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The language manager.
   *
   * @var \Drupal\Core\Language\LanguageManagerInterface
   */
  protected $languageManager;

  /**
   * The tracker manager.
   *
   * @var \Drupal\entity_mesh\TrackerManagerInterface
   */
  protected $trackerManager;

  /**
   * Constructs a Menu object.
   *
   * @param \Drupal\entity_mesh\RepositoryInterface $entity_mesh_repository
   *   The database connection.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity repository.
   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
   *   The language manager.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The config factory manager.
   * @param \Drupal\entity_mesh\TrackerManagerInterface $tracker_manager
   *   The tracker manager.
   */
  public function __construct(RepositoryInterface $entity_mesh_repository, EntityTypeManagerInterface $entity_type_manager, LanguageManagerInterface $language_manager, ConfigFactoryInterface $config_factory, TrackerManagerInterface $tracker_manager) {
    $this->entityMeshRepository = $entity_mesh_repository;
    $this->entityTypeManager = $entity_type_manager;
    $this->languageManager = $language_manager;
    $this->config = $config_factory;
    $this->trackerManager = $tracker_manager;
  }

  /**
   * Process entity and store source with targets in database.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The entity to process.
   */
  public function processEntity(EntityInterface $entity) {
    $this->trackerManager->setStatusProcessing($entity);

    $source = $this->createBasicSourceFromEntity($entity);
    if (!$source instanceof SourceInterface) {
      $this->trackerManager->setStatusFailed($entity);
      return;
    }

    // Delete source before process entities.
    $this->entityMeshRepository->deleteSource($source);

    if (!$this->shouldProcessEntity($entity)) {
      // If the entity should not be process, tracker as processed.
      $this->trackerManager->setStatusProcessed($entity);
      return;
    }

    // Check if entity is translatable.
    if ($entity instanceof TranslatableInterface && $entity->isTranslatable()) {
      if ($this->processTranslatableEntity($entity) === FALSE) {
        $this->trackerManager->setStatusFailed($entity);
      }
    }
    else {
      if ($this->processEntityItem($entity) === FALSE) {
        $this->trackerManager->setStatusFailed($entity);
      }
    }

    $this->trackerManager->setStatusProcessed($entity);
  }

  /**
   * Determines if an entity should be processed based on configuration.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The entity to check.
   *
   * @return bool
   *   TRUE if the entity should be processed, FALSE otherwise.
   */
  protected function shouldProcessEntity(EntityInterface $entity): bool {
    $config = $this->getMeshConfiguration();

    $enabled_types = $config->get('source_types') ?? [];
    if (!$enabled_types[$entity->getEntityTypeId()] || $enabled_types[$entity->getEntityTypeId()]['enabled'] !== TRUE) {
      return FALSE;
    }

    // Only check bundles if the entity type has bundles.
    if ($this->entityTypeHasBundles($entity->getEntityTypeId())) {
      $enabled_bundles = $enabled_types[$entity->getEntityTypeId()]['bundles'] ?? [];
      if (!empty($enabled_bundles) && !isset($enabled_bundles[$entity->bundle()]) || isset($enabled_bundles[$entity->bundle()]) && $enabled_bundles[$entity->bundle()] !== TRUE) {
        return FALSE;
      }
    }

    // Check if there are any enabled target_types.
    $target_types_internal = $config->get('target_types.internal') ?? [];
    $target_types_external = $config->get('target_types.external') ?? [];

    if (empty($target_types_internal) && empty($target_types_external)) {
      return FALSE;
    }

    return TRUE;
  }

  /**
   * Check if an entity type has bundles.
   *
   * @param string $entity_type_id
   *   The entity type ID to check.
   *
   * @return bool
   *   TRUE if the entity type has bundles, FALSE otherwise.
   */
  protected function entityTypeHasBundles(string $entity_type_id): bool {
    $entity_type = $this->entityTypeManager->getDefinition($entity_type_id);
    return $entity_type->hasKey('bundle');
  }

  /**
   * Process a translatable Entity.
   *
   * @param \Drupal\Core\Entity\TranslatableInterface $entity
   *   The entity to process.
   *
   * @return bool
   *   TRUE if successful, FALSE otherwise.
   */
  protected function processTranslatableEntity(TranslatableInterface $entity) {
    $translations = $entity->getTranslationLanguages();
    $langcodes = array_keys($translations);
    foreach ($langcodes as $langcode) {
      $translation = $entity->getTranslation($langcode);
      if ($translation instanceof EntityInterface && $this->entityMeshRepository->checkViewAccessEntity($translation)) {
        if ($this->processEntityItem($translation) === FALSE) {
          return FALSE;
        }
      }
    }
    return TRUE;
  }

  /**
   * Process an Entity.
   *
   * Generate the source object with its targets and store it in the database.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The entity to process.
   *
   * @return bool
   *   TRUE if successful, FALSE otherwise.
   */
  protected function processEntityItem(EntityInterface $entity) {
    $source = $this->createSourceFromEntity($entity);
    if ($source instanceof SourceInterface) {
      return $this->entityMeshRepository->saveSource($source);
    }
    return FALSE;
  }

  /**
   * Delete an item from the database.
   *
   * @param string $entity_type
   *   The entity type of the source.
   * @param string $entity_id
   *   The entity id of the source.
   * @param string $type
   *   The type of the source.
   */
  public function deleteItem(string $entity_type, string $entity_id, string $type = '') {
    $source = $this->entityMeshRepository->instanceEmptySource();
    $source->setType($type);
    $source->setSourceEntityType($entity_type);
    $source->setSourceEntityId($entity_id);
    $this->entityMeshRepository->deleteSource($source);
  }

  /**
   * Build a Source object from an Entity, included its targets.
   *
   * Contain all the logic to get all the targets from the entity.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The entity to process.
   *
   * @return \Drupal\entity_mesh\SourceInterface|null
   *   The source object.
   */
  abstract public function createSourceFromEntity(EntityInterface $entity): ?SourceInterface;

  /**
   * Build a Source object from an Entity, without its targets.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The entity to process.
   *
   * @return \Drupal\entity_mesh\SourceInterface|null
   *   The source object.
   */
  protected function createBasicSourceFromEntity(EntityInterface $entity): ?SourceInterface {
    if ($this->entityMeshRepository->checkViewAccessEntity($entity) === FALSE) {
      return NULL;
    }

    $source = $this->entityMeshRepository->instanceEmptySource();
    $source->setType($this->type);
    $source->setSourceEntityType($entity->getEntityTypeId());
    $source->setSourceEntityBundle($entity->bundle());
    $source->setSourceEntityId((string) $entity->id());
    $source->setSourceEntityLangcode($entity->language()->getId());
    return $source;
  }

  /**
   * Get the front page entity.
   *
   * @return \Drupal\Core\Entity\EntityInterface|null
   *   The front page entity or NULL if not found.
   */
  public function frontPage() {
    $config = $this->config->get('system.site');
    $front = $config->get('page.front');
    $query = $this->entityMeshRepository->getDatabaseService()->select('path_alias', 'pa');
    $query->fields('pa', ['path']);
    $or = $query->orConditionGroup()
      ->condition('alias', $front)
      ->condition('path', $front);
    $query->condition($or);
    // @todo !
    // $query->condition('langcode', $langcode);
    $result = $query->execute();
    if (!$result instanceof StatementInterface) {
      return;
    }
    $record = $result->fetchObject();
    if ($record) {
      $path = explode('/', ltrim($record->path, '/'));
      $storage = $this->entityTypeManager->getStorage($path[0]);
      $entity = $storage->load($path[1]);
      if ($entity instanceof EntityInterface) {
        return $entity;
      }
    }
  }

  /**
   * Get the Entity Mesh configuration.
   *
   * @return \Drupal\Core\Config\ImmutableConfig
   *   The Entity Mesh configuration object.
   */
  protected function getMeshConfiguration() {
    return $this->config->get('entity_mesh.settings');
  }

  /**
   * Check if the internal target should be processed.
   *
   * @return bool
   *   TRUE if internal targets should be processed, FALSE otherwise.
   */
  protected function ifProcessInternalTarget() {
    $config = $this->getMeshConfiguration();
    $target_types = $config->get('target_types.internal') ?? [];
    return !empty($target_types);
  }

  /**
   * Check if the external target should be processed.
   *
   * @return bool
   *   TRUE if external targets should be processed, FALSE otherwise.
   */
  protected function ifProcessExternalTarget() {
    $config = $this->getMeshConfiguration();
    $target_types_external = $config->get('target_types.external') ?? [];
    return !empty($target_types_external);
  }

  /**
   * Check if the route match belongs to a entity route.
   *
   * @param array $route_match
   *   The route match.
   *
   * @return \Drupal\Core\Entity\EntityInterface|null
   *   The entity or NULL.
   */
  protected function checkAndGetEntityFromEntityRoute(array $route_match):? EntityInterface {
    $entity = NULL;

    // Check that we have the parameters that we need.
    if (!isset($route_match['_route']) ||
      !isset($route_match['_route_object']) ||
      !$route_match['_route_object'] instanceof Route
    ) {
      return $entity;
    }

    // Check if the route start with the string 'entity.'.
    // If it is the case, it is probably an entity route.
    if (strpos($route_match['_route'], 'entity.') !== 0) {
      return $entity;
    }

    // If it is an entity route, we can get from parameters of the Route object
    // the name of the parameter.
    /** @var \Symfony\Component\Routing\Route $route_object */
    $route_object = $route_match['_route_object'];
    $parameters = is_array($route_object->getOption('parameters')) ? $route_object->getOption('parameters') : [];

    foreach ($parameters as $name => $value) {
      // There has to be a converter and it has to be the entity converter.
      if (isset($value['converter']) && $value['converter'] === 'paramconverter.entity') {
        $entity = (isset($route_match[$name]) && $route_match[$name] instanceof EntityInterface) ? $route_match[$name] : NULL;
        break;
      }
    }

    return $entity;
  }

  /**
   * Determines if a target should be registered based on configuration.
   *
   * @param \Drupal\entity_mesh\TargetInterface $target
   *   The target to check.
   *
   * @return bool
   *   TRUE if the target should be registered, FALSE otherwise.
   */
  protected function shouldRegisterTarget(TargetInterface $target): bool {
    $config = $this->getMeshConfiguration();
    $target_types = $config->get('target_types') ?? [];

    // Handle external links.
    if ($target->getLinkType() === 'external') {
      if (!$this->ifProcessExternalTarget()) {
        return FALSE;
      }

      $external_config = $target_types['external'];

      // If bundles are defined, check if the scheme is explicitly enabled.
      if (!empty($external_config['scheme'])) {
        $scheme = $target->getScheme();
        // Protocol-relative URLs (e.g., //example.com) have empty scheme.
        // Treat them as http/https.
        if (empty($scheme)) {
          $scheme = 'http';
        }
        $scheme = $scheme == 'https' ? 'http' : $scheme;
        return isset($external_config['scheme'][$scheme]) && $external_config['scheme'][$scheme] === TRUE;
      }

      // Cover category iframe.
      if (!empty($external_config['categories'])) {
        $category = $target->getCategory();
        return isset($external_config['categories'][$category]) && $external_config['categories'][$category] === TRUE;
      }

      return TRUE;
    }

    // Handle internal links.
    if ($target->getLinkType() === 'internal') {
      if (!$this->ifProcessInternalTarget()) {
        return FALSE;
      }

      if ($target->getSubcategory() === 'broken-link') {
        // If the target is a broken link, we always register it.
        return TRUE;
      }

      $entity_type = $target->getEntityType();

      if (!empty(!empty($entity_type))) {
        // Check if entity type is enabled.
        if (!isset($target_types['internal'][$entity_type]['enabled']) ||
          $target_types['internal'][$entity_type]['enabled'] !== TRUE) {
          return FALSE;
        }

        // If bundles are defined, check if the target bundle is enabled.
        $bundles = $target_types['internal'][$entity_type]['bundles'] ?? [];
        if (!empty($bundles)) {
          $bundle = $target->getEntityBundle();
          return isset($bundles[$bundle]) && $bundles[$bundle] === TRUE;
        }
      }

      return TRUE;
    }

    return FALSE;
  }

}

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

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