graphql_core_schema-1.0.x-dev/src/Plugin/GraphQL/DataProducer/Route.php

src/Plugin/GraphQL/DataProducer/Route.php
<?php

declare(strict_types=1);

namespace Drupal\graphql_core_schema\Plugin\GraphQL\DataProducer;

use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Path\PathValidatorInterface;
use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Url;
use Drupal\graphql\GraphQL\Execution\FieldContext;
use Drupal\graphql\Plugin\GraphQL\DataProducer\DataProducerPluginBase;
use Drupal\graphql_core_schema\GraphQL\Buffers\SubRequestBuffer;
use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
use GraphQL\Deferred;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\Session\AccountProxyInterface;

/**
 * Returns the URL of the given path.
 *
 * @DataProducer(
 *   id = "get_route",
 *   name = @Translation("Load route"),
 *   description = @Translation("Loads a route."),
 *   produces = @ContextDefinition("any",
 *     label = @Translation("Route")
 *   ),
 *   consumes = {
 *     "path" = @ContextDefinition("string",
 *       label = @Translation("Path")
 *     )
 *   }
 * )
 */
class Route extends DataProducerPluginBase implements ContainerFactoryPluginInterface {

  /**
   * The language negotiator service.
   *
   * @var \Drupal\language\LanguageNegotiator
   */
  protected $languageNegotiator;

  /**
   * The redirect repository.
   *
   * @var \Drupal\redirect\RedirectRepository
   */
  protected $redirectRepository;

  /**
   * The redirect entity repository.
   *
   * @var \Drupal\domain_path_redirect\DomainPathRedirectRepository
   */
  protected $domainPathRedirectRepository;

  /**
   * Domain negotiator.
   *
   * @var \Drupal\domain\DomainNegotiator
   */
  protected $domainNegotiator;

  /**
   * The redirect 404 storage.
   *
   * @var \Drupal\redirect_404\RedirectNotFoundStorageInterface
   */
  protected $redirectNotFoundStorage;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('path.validator'),
      $container->get('language_negotiator', ContainerInterface::NULL_ON_INVALID_REFERENCE),
      $container->get('language_manager'),
      $container->get('redirect.repository', ContainerInterface::NULL_ON_INVALID_REFERENCE),
      $container->get('path_processor_manager'),
      $container->get('domain_path_redirect.repository', ContainerInterface::NULL_ON_INVALID_REFERENCE),
      $container->get('domain.negotiator', ContainerInterface::NULL_ON_INVALID_REFERENCE),
      $container->get('entity_type.manager'),
      $container->get('redirect.not_found_storage', ContainerInterface::NULL_ON_INVALID_REFERENCE),
      $container->get('config.factory'),
      $container->get('graphql_core_schema.buffer.subrequest'),
      $container->get('current_user'),
    );
  }

  public function __construct(
    array $configuration,
    $pluginId,
    $pluginDefinition,
    protected PathValidatorInterface $pathValidator,
    $languageNegotiator,
    protected LanguageManagerInterface $languageManager,
    $redirectRepository,
    protected InboundPathProcessorInterface $pathProcessor,
    $domain_path_redirect_repository,
    $domain_negotiator,
    protected EntityTypeManagerInterface $entityTypeManager,
    $redirect_not_found_storage,
    protected ConfigFactoryInterface $configFactory,
    protected SubRequestBuffer $subRequestBuffer,
    protected AccountProxyInterface $currentUser,
  ) {
    parent::__construct($configuration, $pluginId, $pluginDefinition);
    $this->redirectRepository = $redirectRepository;
    $this->languageNegotiator = $languageNegotiator;
    $this->domainPathRedirectRepository = $domain_path_redirect_repository;
    $this->domainNegotiator = $domain_negotiator;
    $this->redirectNotFoundStorage = $redirect_not_found_storage;
  }

  /**
   * {@inheritdoc}
   */
  public function resolve($value, FieldContext $field) {
    // @todo This entire method needs to be refactored and made more
    // configurable/extendable by users of the module.
    $currentLanguage = $this->languageManager->getCurrentLanguage()->getId();
    $field->setContextValue('language', $currentLanguage);
    $request = Request::create($value);
    $path = $this->pathProcessor->processInbound($value, $request);

    if ($this->domainPathRedirectRepository) {
      $domain = $this->domainNegotiator ? $this->domainNegotiator->getActiveId() : NULL;
      $field->addCacheContexts(['domain']);

      // Check for domain_path_redirect.
      $domain_redirect_path = trim($path, '/');
      if ($redirect = $this->domainPathRedirectRepository->findMatchingRedirect($domain_redirect_path, $domain, [], 'und')) {
        return $redirect;
      }
    }

    if ($this->redirectRepository) {
      $query_params = $request->query->all() ?: [];
      if ($query_params) {
        // Strip everything after the query string.
        $path = explode('?', $path)[0];
      }
      // Remove any trailing slashes.
      $path = rtrim($path, '/');

      // Check for regular redirects.
      if ($redirect = $this->redirectRepository->findMatchingRedirect($path, $query_params, $currentLanguage)) {
        // Pass the query string to the resolver.
        if ($query_params) {
          $redirect->queryParams = $request->getQueryString();
        }
        return $redirect;
      }
    }

    // Get the URL if valid.
    $url = $this->pathValidator->getUrlIfValidWithoutAccessCheck($value);
    if ($url) {

      // If the URL is external, we stop here for security reasons.
      // Similar to https://www.drupal.org/sa-core-2020-003
      // This prevents the possibility of an open redirect. Example:
      // https://example.ddev.site//https://malicous-redirect.com/
      // will not be redirected to https://malicous-redirect.com/
      if ($url->isExternal()) {
        return NULL;
      }

      $resolver = $this->subRequestBuffer->add($url, function (Url $url) use ($value, $request, $currentLanguage, $path, $field) {
        $negotiatedLangcode = $currentLanguage;

        if ($this->languageNegotiator && $this->languageNegotiator->isNegotiationMethodEnabled('language-url')) {
          $currentUser = $this->currentUser;
          $this->languageNegotiator->setCurrentUser($currentUser);

          // Determine the language from the provided url string.
          $negotiator = $this->languageNegotiator->getNegotiationMethodInstance('language-url');
          $negotiatedUrlLangcode = $negotiator->getLangcode($request);
          if ($negotiatedUrlLangcode) {
            $negotiatedLangcode = $negotiatedUrlLangcode;
          }
        }

        // Check URL access.
        $target_url = $url->toString(TRUE)->getGeneratedUrl();

        // If language detection is domain based, remove domain from $target_url
        if ($this->languageNegotiator) {
          $lang_n_config = $this->configFactory->get('language.negotiation');
          if ($lang_n_config->get('url.source') == LanguageNegotiationUrl::CONFIG_DOMAIN) {
            $lang_domain = $lang_n_config->get('url.domains.' . $negotiatedLangcode);
            $target_url = str_replace(['http://', 'https://'], '', $target_url);
            $target_url = str_replace($lang_domain, '', $target_url);
          }
        }

        // Check if $target_url is absolute. This is needed for domain_source module.
        // '/my-url' is replaced by domain_source with 'http://example.com/my-url'.
        $isExternal = UrlHelper::isExternal($target_url);

        // Check if the URL has an alias and should be redirected.
        if (!$isExternal && $value !== $target_url && $this->entityTypeManager->hasDefinition('redirect')) {
          $redirectStorage = $this->entityTypeManager->getStorage('redirect');
          /** @var \Drupal\redirect\Entity\Redirect $redirect */
          $redirect = $redirectStorage->create();
          $redirect->setRedirect($target_url);
          $redirect->setSource($path);
          $redirect->setLanguage($negotiatedLangcode);
          $redirect->setStatusCode(301);
          return $redirect;
        }

        $access = $url->access(NULL, TRUE);
        $field->addCacheableDependency($access);

        if ($access->isAllowed()) {
          $negotiatedLanguage = $this->languageManager->getLanguage($negotiatedLangcode);
          $url->setOption('language', $negotiatedLanguage);
          $field->setContextValue('language', $negotiatedLangcode);
          return $url;
        }
        else {
          if ($this->entityTypeManager->hasDefinition('redirect')) {
            $url = Url::fromUserInput('/user/login?destination=' . $url->toString());
            // The URL exists but the user has no access.
            $redirectStorage = $this->entityTypeManager->getStorage('redirect');
            /** @var \Drupal\redirect\Entity\Redirect $redirect */
            $redirect = $redirectStorage->create();
            $redirect->setRedirect($url->toString());
            $redirect->setSource($path);
            $redirect->setLanguage($negotiatedLangcode);
            $redirect->setStatusCode(403);
            return $redirect;
          }
        }
      });

      return new Deferred($resolver);
    }

    $field->addCacheTags(['4xx-response']);
    if ($this->redirectNotFoundStorage) {
      $this->redirectNotFoundStorage->logRequest($path, $currentLanguage);
    }
    return NULL;
  }

}

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

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