graphql_compose-1.0.0-beta20/src/Plugin/GraphQLComposeSchemaTypeManager.php

src/Plugin/GraphQLComposeSchemaTypeManager.php
<?php

declare(strict_types=1);

namespace Drupal\graphql_compose\Plugin;

use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Logger\LoggerChannelTrait;
use Drupal\Core\Plugin\DefaultPluginManager;
use Drupal\graphql_compose\Annotation\GraphQLComposeSchemaType;
use Drupal\graphql_compose\Attribute\SchemaType;
use Drupal\graphql_compose\Utility\ComposeContext;
use Drupal\graphql_compose\Utility\ComposeProviders;
use Drupal\graphql_compose\Plugin\GraphQLCompose\GraphQLComposeSchemaTypeInterface;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Schema;
use GraphQL\Utils\SchemaPrinter;

/**
 * Manage graphql types for lazy loading schema creation.
 *
 * A schema type is a plugin that defines how to resolve a GraphQL Type.
 */
class GraphQLComposeSchemaTypeManager extends DefaultPluginManager {

  use LoggerChannelTrait;

  /**
   * Static storage of types.
   *
   * @var \GraphQL\Type\Definition\Type[]
   */
  private array $types = [];

  /**
   * Static storage of extensions.
   *
   * @var \GraphQL\Type\Definition\Type[]
   */
  private array $extensions = [];

  /**
   * Static storage of instances.
   *
   * @var \Drupal\graphql_compose\Annotation\GraphQLComposeSchemaTypeInterface[]
   */
  private array $instances = [];

  /**
   * Constructs a GraphQLComposeSchemaTypeManager object.
   *
   * @param \Traversable $namespaces
   *   An object that implements \Traversable which contains the root paths
   *   keyed by the corresponding namespace to look for plugin implementations.
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
   *   The module handler.
   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
   *   The cache backend.
   * @param array $config
   *   The configuration service parameter.
   * @param \Drupal\graphql_compose\Plugin\GraphQLComposeEntityTypeManager $gqlEntityTypeManager
   *   Entity type plugin manager.
   */
  public function __construct(
    \Traversable $namespaces,
    ModuleHandlerInterface $module_handler,
    CacheBackendInterface $cache_backend,
    array $config,
    protected GraphQLComposeEntityTypeManager $gqlEntityTypeManager,
  ) {
    parent::__construct(
      'Plugin/GraphQLCompose/SchemaType',
      $namespaces,
      $module_handler,
      GraphQLComposeSchemaTypeInterface::class,
      SchemaType::class,
      GraphQLComposeSchemaType::class,
    );

    $this->alterInfo('graphql_compose_graphql_type');
    $this->useCaches(empty($config['development']));
    $this->setCacheBackend($cache_backend, 'graphql_compose_graphql_type', ['graphql_compose_graphql_type']);
  }

  /**
   * Get a plugin instance.
   *
   * @param string $plugin_id
   *   Type to get settings for. Eg 'Address'.
   *
   * @return \Drupal\graphql_compose\Plugin\GraphQLCompose\GraphQLComposeSchemaTypeInterface|null
   *   The plugin instance.
   */
  public function getPluginInstance(string $plugin_id): ?GraphQLComposeSchemaTypeInterface {

    // Limit the plugin to the providers that are enabled.
    $definition = $this->getDefinition($plugin_id, TRUE);

    return ComposeProviders::has($definition['provider'])
      ? $this->createInstance($plugin_id)
      : NULL;
  }

  /**
   * Get all instances.
   *
   * @return \Drupal\graphql_compose\Plugin\GraphQLCompose\GraphQLComposeSchemaTypeInterface[]
   *   All plugin instances.
   */
  public function getPluginInstances(): array {
    $server_id = ComposeContext::getServerId();

    array_map(
      $this->getPluginInstance(...),
      array_keys($this->getDefinitions())
    );

    return $this->instances[$server_id] ?? [];
  }

  /**
   * Hijack the createInstance to init the types and extensions.
   *
   * @param string $plugin_id
   *   The plugin id.
   * @param array $configuration
   *   The plugin configuration.
   *
   * @return \Drupal\graphql_compose\Plugin\GraphQLCompose\GraphQLComposeSchemaTypeInterface
   *   The plugin instance.
   */
  public function createInstance($plugin_id, array $configuration = []) {
    $server_id = ComposeContext::getServerId();

    if (!isset($this->instances[$server_id][$plugin_id])) {
      $plugin = parent::createInstance($plugin_id, $configuration);
      $this->instances[$server_id][$plugin_id] = $plugin;
      foreach ($plugin->getTypes() as $type) {
        $this->add($type);
      }
      foreach ($plugin->getExtensions() as $extension) {
        $this->extend($extension);
      }
    }

    return $this->instances[$server_id][$plugin_id];
  }

  /**
   * Store an instance of a type in the registry.
   *
   * @param \GraphQL\Type\Definition\Type $type
   *   The type to store.
   *
   * @return \GraphQL\Type\Definition\Type
   *   The stored type.
   *
   * @throws \Exception
   *   If the type does not have a name.
   */
  public function add(Type $type): Type {
    $type = Type::getNamedType($type);
    if (!$type) {
      throw new \Exception('GraphQL Type missing name property.');
    }

    return $this->types[$type->name()] ??= $type;
  }

  /**
   * Get a type by name.
   *
   * @param string $plugin_id
   *   The name of the type.
   * @param bool $multiple
   *   Optional, if the type is a list, wrap the type.
   * @param bool $required
   *   Optional, if the type is required, wrap the type.
   *
   * @return \GraphQL\Type\Definition\Type
   *   The GraphQL type.
   */
  public function get(string $plugin_id, bool $multiple = FALSE, bool $required = FALSE): Type {
    $standard_id = strtolower($plugin_id);
    $standard_types = array_change_key_case(Type::getStandardTypes(), CASE_LOWER);

    if (array_key_exists($standard_id, $standard_types)) {
      $type = $standard_types[$standard_id];
    }
    else {
      if (!array_key_exists($plugin_id, $this->types)) {
        try {
          $this->getPluginInstance($plugin_id);
        }
        catch (PluginNotFoundException $e) {
          // This type may be referenced by a field, but not enabled in GUI.
          // or may not have a defined plugin in GraphqlCompose/SchemaType.
          $message = 'Type @plugin_id not found (perhaps no bundle is enabled?), replacing with UnsupportedType.';
          $this->getLogger('graphql_compose')->warning($message, [
            '@plugin_id' => $plugin_id,
          ]);
        }
      }

      // If the type is still not found, load the UnsupportedType.
      if (empty($this->types[$plugin_id])) {
        $this->getPluginInstance('UnsupportedType');
      }

      // Get the type from the registry.
      $type = $this->types[$plugin_id] ?? $this->types['UnsupportedType'];
    }

    if ($multiple) {
      $type = Type::listOf(Type::nonNull($type));
    }

    if ($required) {
      $type = Type::nonNull($type);
    }

    return $type;
  }

  /**
   * Add an extension to the registry.
   *
   * @param \GraphQL\Type\Definition\Type $type
   *   The type to extend.
   *
   * @return \GraphQL\Type\Definition\Type
   *   The extended type.
   */
  public function extend(Type $type): Type {
    $this->extensions[] = $type;
    return $type;
  }

  /**
   * Utility function to get current defined types.
   *
   * @return \GraphQL\Type\Definition\Type[]
   *   The types.
   */
  public function getTypes(): array {
    return $this->types;
  }

  /**
   * Utility function to get current extensions.
   *
   * @return \GraphQL\Type\Definition\Type[]
   *   The extensions.
   */
  public function getExtensions(): array {
    return $this->extensions;
  }

  /**
   * Print types as GraphQL strings.
   *
   * @return string|null
   *   The GraphQL schema types.
   */
  public function printTypes(): ?string {

    // Give opportunity to hook this printer.
    ComposeProviders::invoke('graphql_compose_print_types', [$this]);

    $schema = new Schema([
      'types' => $this->getTypes(),
    ]);

    $printed = SchemaPrinter::doPrint($schema);

    return trim($printed) ?: NULL;
  }

  /**
   * Print extensions as GraphQL strings.
   *
   * @return string|null
   *   The GraphQL schema type extensions.
   */
  public function printExtensions(): ?string {

    // Give opportunity to hook this printer.
    ComposeProviders::invoke('graphql_compose_print_extensions', [$this]);

    $print = function (Type $type) {
      $printed = SchemaPrinter::printType($type);

      // Allow types to extend only interfaces.
      // Strip empty {} blocks.
      return preg_replace('/\{[\s\r\n\t]+\}/', '', $printed);
    };

    $types = array_map(
      fn($type) => 'extend ' . $print($type),
      $this->getExtensions()
    );

    return trim(implode(PHP_EOL . PHP_EOL, $types)) ?: NULL;
  }

}

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

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