entity_mesh-1.1.1/src/Repository.php

src/Repository.php
<?php

namespace Drupal\entity_mesh;

use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\TranslatableInterface;
use Drupal\Core\StreamWrapper\AssetsStream;
use Drupal\file\FileInterface;
use Drupal\media\MediaInterface;
use Drupal\redirect\Entity\Redirect;
use Drupal\redirect\Exception\RedirectLoopException;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\RequestStack;

/**
 * Service to perform database operations.
 */
class Repository implements RepositoryInterface {

  /**
   * The database connection.
   *
   * @var \Drupal\Core\Database\Connection
   */
  protected $database;

  /**
   * The logger service.
   *
   * @var \Psr\Log\LoggerInterface
   */
  protected $logger;

  /**
   * The request stack.
   *
   * @var \Symfony\Component\HttpFoundation\RequestStack
   */
  protected $requestStack;

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

  /**
   * The entity field manager.
   *
   * @var \Drupal\Core\Entity\EntityFieldManagerInterface
   */
  protected $entityFieldManager;

  /**
   * Url language prefixes.
   *
   * @var array
   */
  protected array $prefixes;

  /**
   * Config factory service.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $configFactory;

  /**
   * Cached mesh account.
   *
   * @var \Drupal\entity_mesh\DummyAccount|null
   */
  protected $meshAccount;

  /**
   * Constructs a new Repository object.
   *
   * @param \Drupal\Core\Database\Connection $database
   *   The database connection.
   * @param \Psr\Log\LoggerInterface $logger
   *   The logger service.
   * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
   *   The request stack.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
   *   The entity field manager.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   Config factory.
   */
  public function __construct(
    Connection $database,
    LoggerInterface $logger,
    RequestStack $request_stack,
    EntityTypeManagerInterface $entity_type_manager,
    EntityFieldManagerInterface $entity_field_manager,
    ConfigFactoryInterface $config_factory,
  ) {
    $this->database = $database;
    $this->logger = $logger;
    $this->requestStack = $request_stack;
    $this->entityTypeManager = $entity_type_manager;
    $this->entityFieldManager = $entity_field_manager;
    $this->configFactory = $config_factory;
    $this->prefixes = $config_factory->get('language.negotiation')->get('url.prefixes');
  }

  /**
   * {@inheritdoc}
   */
  public function getDatabaseService() {
    return $this->database;
  }

  /**
   * {@inheritdoc}
   */
  public function getLogger() {
    return $this->logger;
  }

  /**
   * {@inheritdoc}
   */
  public function insertSource(SourceInterface $source): bool {
    $rows = [];

    // We ensure that the Source object has the Hash ID.
    if ($source->getHashId() === NULL) {
      $source->setHashId();
    }

    // We ensure that the Source object has the title.
    $this->setTitleSourceTarget($source);

    $targets = $source->getTargets();
    if (empty($targets)) {
      return TRUE;
    }
    $source_properties = $source->toArray();

    foreach ($targets as $target) {
      $row = [];
      // We ensure that the Target object has the Hash ID.
      if ($target->getHashId() === NULL) {
        $target->setHashId();
      }
      // We ensure that the Target object has the title.
      $this->setTitleSourceTarget($target);

      $row = array_merge($source_properties, $target->toArray());

      $rows[] = $row;
    }

    $transaction = $this->database->startTransaction();

    try {
      $query = $this->database->insert(self::ENTITY_MESH_TABLE)
        ->fields(array_keys(reset($rows)));

      foreach ($rows as $row) {
        $query->values($row);
      }

      $query->execute();
    }
    catch (\Exception $e) {
      $transaction->rollback();
      $this->logger->error($e->getMessage());
      return FALSE;
    }

    return TRUE;
  }

  /**
   * Build label for objects.
   *
   * @param object $object
   *   Source or Target object.
   */
  protected function setTitleSourceTarget($object) {
    $title_segment_1 = '';

    if ($object instanceof SourceInterface) {
      if (!empty($object->getTitle())) {
        return;
      }
      $entity_type = $object->getSourceEntityType();
      $id = $object->getSourceEntityId();
      $langcode = $object->getSourceEntityLangcode();
      $title_segment_1 = $this->getLabel($entity_type, $id, $langcode) ?? '';
    }
    elseif ($object instanceof TargetInterface) {
      if (!empty($object->getTitle())) {
        return;
      }
      if ($object->getLinkType() === 'external') {
        $entity_type = 'external';
        $id = NULL;
      }
      else {
        $entity_type = $object->getEntityType();
        $id = $object->getEntityId();
        $langcode = $object->getEntityLangcode();
        $title_segment_1 = $this->getLabel($entity_type, $id, $langcode);
      }
      if (empty($title_segment_1)) {
        $title_segment_1 = $object->getHref() ?? '';
      }
    }
    else {
      return;
    }

    $label = $title_segment_1;
    $label .= ' (' . $entity_type;
    $label .= empty($id) ? ')' : ' - ' . $id . ')';
    if ($label === ' ()') {
      return;
    }
    $label = mb_substr($label, 0, 255);

    $object->setTitle($label);
  }

  /**
   * Get label from an entity.
   *
   * @param string|null $entity_type
   *   The entity type.
   * @param string|null $entity_id
   *   The entity id.
   * @param string|null $langcode
   *   The langcode.
   *
   * @return string|null
   *   The string of the link or entity id.
   */
  protected function getLabel(?string $entity_type, ?string $entity_id, ?string $langcode): ?string {

    if (empty($entity_id) || empty($entity_type)) {
      return NULL;
    }

    try {
      $storage = $this->entityTypeManager->getStorage($entity_type);
    }
    catch (PluginNotFoundException $e) {
      return NULL;
    }

    /** @var \Drupal\Core\Entity\EntityInterface $entity */
    $entity = $storage->load($entity_id);
    if (!$entity instanceof EntityInterface) {
      return NULL;
    }

    return !empty($langcode) && $entity instanceof TranslatableInterface && $entity->isTranslatable() && $entity->hasTranslation($langcode) ? $entity->getTranslation($langcode)->label() : $entity->label();
  }

  /**
   * {@inheritdoc}
   */
  public function deleteSource(SourceInterface $source): bool {
    try {
      $this->database
        ->delete(self::ENTITY_MESH_TABLE)
        ->condition('type', $source->getType())
        ->condition('source_entity_type', $source->getSourceEntityType())
        ->condition('source_entity_id', $source->getSourceEntityId())
        ->execute();
    }
    catch (\Exception $e) {
      $this->logger->error($e->getMessage());
      return FALSE;
    }
    return TRUE;
  }

  /**
   * {@inheritdoc}
   */
  public function deleteSourceByType(string $type, array $conditions): bool {
    try {
      $query = $this->database->delete(self::ENTITY_MESH_TABLE);
      $query->condition('type', $type);
      foreach ($conditions as $field => $value) {
        $query->condition($field, $value);
      }
      $query->execute();
    }
    catch (\Exception $e) {
      $this->logger->error($e->getMessage());
      return FALSE;
    }
    return TRUE;
  }

  /**
   * {@inheritdoc}
   */
  public function deleteAllSourceTarget(): bool {
    try {
      $this->database
        ->delete(self::ENTITY_MESH_TABLE)
        ->execute();
    }
    catch (\Exception $e) {
      $this->logger->error($e->getMessage());
      return FALSE;
    }
    return TRUE;
  }

  /**
   * {@inheritdoc}
   */
  public function saveSource(SourceInterface $source): bool {
    if (!$this->insertSource($source)) {
      return FALSE;
    }
    return TRUE;
  }

  /**
   * {@inheritdoc}
   */
  public function instanceEmptySource(): SourceInterface {
    return Source::create();
  }

  /**
   * {@inheritdoc}
   */
  public function instanceEmptyTarget(): TargetInterface {
    $self_domain_internal = $this->configFactory->get('entity_mesh.settings')->get('self_domain_internal');
    return Target::create($this->requestStack, $self_domain_internal);
  }

  /**
   * {@inheritdoc}
   */
  public function getPathFromFileUrl(string $path): ?string {
    $public_base_path = AssetsStream::basePath() . '/';
    $path = trim($path, '/');
    if (strpos($path, $public_base_path) !== 0) {
      return NULL;
    }
    return str_replace($public_base_path, 'public://', $path);
  }

  /**
   * {@inheritdoc}
   */
  public function getFileFromUrl($path): ?FileInterface {
    $file = $this->entityTypeManager->getStorage('file')->loadByProperties(['uri' => $path]);
    if (empty($file)) {
      return NULL;
    }
    return reset($file);
  }

  /**
   * {@inheritdoc}
   */
  public function getMediaFileByEntityFile(FileInterface $file): ?MediaInterface {
    $media_types_with_tile_fields = $this->getMediaFieldTypeWithFileFields();
    if (empty($media_types_with_tile_fields)) {
      return NULL;
    }
    $media_query = $this->entityTypeManager->getStorage('media')->getQuery();
    $media_query->accessCheck(FALSE);
    $or_condition = $media_query->orConditionGroup();
    foreach ($media_types_with_tile_fields as $media_type_file_field) {
      $or_condition->condition($media_type_file_field['field_name'] . '.target_id', $file->id());
    }
    $media_query->condition($or_condition);
    $results = $media_query->execute();
    if (empty($results)) {
      return NULL;
    }
    return $this->entityTypeManager->getStorage('media')->load(reset($results));
  }

  /**
   * Get media types with file fields.
   *
   * @return array
   *   Array with the media type and the field name.
   */
  protected function getMediaFieldTypeWithFileFields() {
    $medias_type_reference_to_file = [];
    $media_types = $this->entityTypeManager->getStorage('media_type')->loadMultiple();
    foreach ($media_types as $media_type) {
      $fields = $this->entityFieldManager->getFieldDefinitions('media', (string) $media_type->id());
      foreach ($fields as $field) {
        if (in_array($field->getType(), ['file', 'image'])) {
          $medias_type_reference_to_file[] = [
            'field_name' => $field->getName(),
            'field_type' => $media_type->id(),
          ];
        }
      }
    }
    return $medias_type_reference_to_file;
  }

  /**
   * {@inheritdoc}
   */
  public function ifRedirectionForPath($path, $langcode, $count = 0) {
    $service_redirect = 'redirect.repository';
    // @phpstan-ignore-next-line
    $container = \Drupal::getContainer();
    if (!$container->has($service_redirect)) {
      return NULL;
    }
    $path = trim($path, '/');
    $redirect_repository = $container->get($service_redirect);
    try {

      if (!empty($langcode)) {
        $redirect_object = $redirect_repository->findMatchingRedirect($path, [], $langcode);
      }
      else {
        $redirect_object = $redirect_repository->findMatchingRedirect($path, []);
      }

    }
    catch (RedirectLoopException $e) {
      $this->logger->error($e->getMessage());
      return NULL;
    }
    if (!($redirect_object instanceof Redirect)) {
      return NULL;
    }

    $redirect = $redirect_object->getRedirect();
    $uri = $redirect['uri'] ?? NULL;
    if ($uri === NULL) {
      return NULL;
    }

    // Check if te redirection has a redirection and avoid infinite loop.
    if ($count > 5) {
      return $uri;
    }
    $filtered_uri = $this->handlePrefixFromRedirection($uri, $langcode);
    $new_redirection = $this->ifRedirectionForPath($filtered_uri, $langcode, $count++);

    return $new_redirection ?? $uri;
  }

  /**
   * Handle prefix from redirection.
   *
   * @param string $uri
   *   The uri.
   * @param string $langcode
   *   The langcode.
   *
   * @return string
   *   The uri.
   */
  public function handlePrefixFromRedirection($uri, $langcode = '') {
    $prefixes = ['internal:', 'entity:', $langcode];
    foreach ($prefixes as $prefix) {
      $uri = (string) preg_replace('/^' . $prefix . '/', '', $uri);
      $uri = trim($uri, '/');
    }
    return $uri;
  }

  /**
   * {@inheritdoc}
   */
  public function getPathWithoutLangPrefix($path) {
    $prefix = $this->getLangPrefixFromPath($path);
    if (empty($prefix)) {
      return $path;
    }

    // We ensure 2 structures: /langcode/path or /langcode.
    $processed_path = ltrim($path, '/');
    if (str_starts_with($processed_path, $prefix . '/')) {
      $path = substr($processed_path, strlen($prefix));
    }
    elseif ($processed_path === $prefix) {
      $path = '/';
    }

    return $path;
  }

  /**
   * {@inheritdoc}
   */
  public function getLangcodeFromPath($path): ?string {
    $result = NULL;
    if ($langcode_and_prefix = $this->getLangcodeAndPrefixFromPath($path)) {
      $result = $langcode_and_prefix['langcode'] ?? NULL;
    }
    return $result;
  }

  /**
   * {@inheritdoc}
   */
  public function getLangPrefixFromPath($path): ?string {
    $result = NULL;
    if ($langcode_and_prefix = $this->getLangcodeAndPrefixFromPath($path)) {
      $result = $langcode_and_prefix['prefix'] ?? NULL;
    }
    return $result;
  }

  /**
   * Get the langcode and prefix from the path.
   *
   * @param string $path
   *   The path.
   *
   * @return array|null
   *   The langcode and prefix or NULL.
   */
  protected function getLangcodeAndPrefixFromPath($path): ?array {
    // If the prefixes ares empty, it is not a multilingual site, so
    // there are not langcode to return.
    if (empty($this->prefixes)) {
      return NULL;
    }
    $path = '/' . ltrim($path, '/');
    foreach ($this->prefixes as $langcode => $prefix) {
      if ($prefix && str_starts_with($path, '/' . $prefix . '/')) {
        return [
          'langcode' => $langcode,
          'prefix' => $prefix,
        ];
      }
    }

    return NULL;
  }

  /**
   * {@inheritdoc}
   */
  public function clearMeshAccountCache() {
    $this->meshAccount = NULL;
  }

  /**
   * {@inheritdoc}
   */
  public function getMeshAccount(): DummyAccount {
    if (!$this->meshAccount) {
      $this->meshAccount = DummyAccount::create($this->entityTypeManager);

      // Get the configured analyzer account from settings.
      $config = $this->configFactory->get('entity_mesh.settings');
      $analyzer_account = $config->get('analyzer_account') ?: [
        'type' => 'anonymous',
        'roles' => NULL,
        'user_id' => NULL,
      ];

      switch ($analyzer_account['type']) {
        case 'anonymous':
          $this->meshAccount->setAsAnonymous();
          break;

        case 'authenticated':
          // Start with authenticated role.
          $roles = ['authenticated'];
          // Add any additional configured roles.
          if (!empty($analyzer_account['roles'])) {
            $roles = array_merge($roles, $analyzer_account['roles']);
          }
          $this->meshAccount->setRoles($roles);
          break;

        case 'user':
          if (!empty($analyzer_account['user_id'])) {
            try {
              $user = $this->entityTypeManager->getStorage('user')->load($analyzer_account['user_id']);
              if ($user) {
                $this->meshAccount->setRoles($user->getRoles());
                $this->meshAccount->setId((int) $user->id());
                $this->meshAccount->setPreferredLangcode($user->getPreferredLangcode());
              }
              else {
                $this->meshAccount->setAsAnonymous();
              }
            }
            catch (\Exception $e) {
              // Error loading user, fallback to anonymous.
              $this->meshAccount->setAsAnonymous();
            }
          }
          else {
            // No user ID configured, fallback to anonymous.
            $this->meshAccount->setAsAnonymous();
          }
          break;

        default:
          // Unknown type, fallback to anonymous.
          $this->meshAccount->setAsAnonymous();
          break;
      }
    }

    return $this->meshAccount;
  }

  /**
   * {@inheritdoc}
   */
  public function checkViewAccessEntity(EntityInterface $entity): bool {
    $mesh_account = $this->getMeshAccount();
    return $entity->access('view', $mesh_account);
  }

}

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

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