graphql_fragment_include-8.x-1.1/src/GraphQL/Fragment/GraphQLFragmentLoader.php

src/GraphQL/Fragment/GraphQLFragmentLoader.php
<?php

namespace Drupal\graphql_fragment_include\GraphQL\Fragment;

use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;

/**
 * An implementation of GraphqlFragmentLoaderInterface.
 *
 * Allows inclusion of GraphQL Fragments on a query, defined by the
 * following syntax:
 * # include Fragment.gql
 * Includes are not supported by GraphQL, so we need to use comments for them.
 */
class GraphQLFragmentLoader implements GraphQLFragmentLoaderInterface {

  use StringTranslationTrait;


  /**
   * Config object for this module.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $configFactory;

  /**
   * Logger instance for this module.
   *
   * @var \Psr\Log\LoggerInterface
   */
  protected $logger;

  /**
   * Loaded includes.
   *
   * @var array
   */
  protected $loadedFragments;

  /**
   * Constructor for IncludeLoader.
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
   *   Drupal config factory.
   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $loggerFactory
   *   Logger Factory.
   */
  public function __construct(
    ConfigFactoryInterface $configFactory,
  LoggerChannelFactoryInterface $loggerFactory) {
    $this->configFactory = $configFactory;
    $this->logger = $loggerFactory->get('graphql_fragment_include');
  }

  /**
   * {@inheritdoc}
   */
  public function findFragments(string $graphQLQuery) {
    preg_match_all("/^#\s+include\s+(\S+)\s*$/m", $graphQLQuery, $matches);
    return $matches;
  }

  /**
   * {@inheritdoc}
   */
  public function loadFragments(string $graphQLQuery) {
    // Ensure $this->loadedFragments is empty on each execution.
    $this->loadedFragments = [];
    $graphQLQuery = $this->parseQuery($graphQLQuery);
    $this->loadedFragments = [];
    return $graphQLQuery;
  }

  /**
   * Parse query and load fragments..
   *
   * We use a helper function so we can manage $this->loadedFragments in a more
   * easier way.
   *
   * @param string $graphQLQuery
   *   The GraphQL query to parse.
   *
   * @return string
   *   The parsed GraphQL query.
   */
  protected function parseQuery(string $graphQLQuery) {
    $matches = $this->findFragments($graphQLQuery);
    if ($matches) {
      $baseDir = DRUPAL_ROOT . $this->configFactory->get('graphql_fragment_include.settings')->get("fragments_base_dir");
      foreach ($matches[1] as $key => $match) {
        $fragmentPath = realpath($baseDir . '/' . $match);
        if (!$this->isFragmentPathValid($fragmentPath)) {
          $this->logger->warning($this->t("Fragment path '@fragment-path' is not valid (derived from '@match').", ['@fragment-path' => $fragmentPath, '@match' => $match]));
          continue;
        }
        if (!is_file($fragmentPath)) {
          $this->logger->warning($this->t("No fragment '@fragment-path' found (derived from '@match').", ['@fragment-path' => $fragmentPath, '@match' => $match]));
          continue;
        }

        // Avoid double loading a fragment.
        if ($this->isFragmentAlreadyLoaded($fragmentPath)) {
          $graphQLQuery = trim(str_replace($matches[0][$key], "", $graphQLQuery));
        }
        else {
          $this->markFragmentAsLoaded($fragmentPath);
          $fragmentData = trim(file_get_contents($fragmentPath));
          // Recursively load other fragments.
          $fragmentData = $this->parseQuery($fragmentData);
          $graphQLQuery = trim(str_replace($matches[0][$key], "", $graphQLQuery));
          $graphQLQuery .= "\n\n# START $match \n" . $fragmentData . "\n# END $match ";
        }
      }
    }
    return $graphQLQuery;
  }

  /**
   * Tells whether a fragment path is valid.
   *
   * It's considered valid if it starts with fragments_base_dir.
   *
   * @param string $fragmentPath
   *   The file to check.
   *
   * @return bool
   *   True if it's valid, false otherwise.
   */
  protected function isFragmentPathValid(string $fragmentPath) {
    $baseDir = realpath(DRUPAL_ROOT . $this->configFactory->get('graphql_fragment_include.settings')->get("fragments_base_dir"));
    $fragmentPathStart = mb_substr($fragmentPath, 0, strlen($baseDir));
    if ($fragmentPathStart === $baseDir) {
      return TRUE;
    }
    return FALSE;
  }

  /**
   * Tells whether a fragment has been already loaded.
   *
   * GraphQL fragments can not be repeated.
   *
   * @param string $fragmentPath
   *   The file to check.
   *
   * @return bool
   *   True if it has been already loaded, false otherwise.
   */
  protected function isFragmentAlreadyLoaded(string $fragmentPath) {
    return isset($this->loadedFragments[$fragmentPath]);
  }

  /**
   * Marks a fragment as already loaded.
   *
   * @param string $fragmentPath
   *   The file to be marked as already loaded.
   */
  protected function markFragmentAsLoaded(string $fragmentPath) {
    $this->loadedFragments[$fragmentPath] = TRUE;
  }

}

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

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