File manager - Edit - /home/opticamezl/www/newok/graphql.zip
Back
PK 6H�\�x�e� � src/Directive/BindDirective.phpnu �[��� <?php namespace YOOtheme\GraphQL\Directive; use YOOtheme\Container; use YOOtheme\GraphQL\Type\Definition\Directive; use YOOtheme\GraphQL\Type\Definition\Type; class BindDirective extends Directive { /** * @var Container */ protected $container; /** * Constructor. * * @param Container $container */ public function __construct(Container $container) { parent::__construct([ 'name' => 'bind', 'args' => [ [ 'name' => 'id', 'type' => Type::string(), ], [ 'name' => 'class', 'type' => Type::string(), ], [ 'name' => 'args', 'type' => Type::string(), ], ], 'locations' => ['OBJECT', 'ENUM_VALUE', 'FIELD_DEFINITION'], ]); $this->container = $container; } /** * Register service on container. * * @param array $params */ public function __invoke(array $params) { if (!$this->container->has($params['id'])) { $service = $this->container->add($params['id']); if (isset($params['class'])) { $service->setClass($params['class']); } if (isset($params['args'])) { $service->setArguments(json_decode($params['args'], true)); } } } } PK 6H�\�r��L L src/Directive/SliceDirective.phpnu �[��� <?php namespace YOOtheme\GraphQL\Directive; use YOOtheme\GraphQL\Type\Definition\Directive; use YOOtheme\GraphQL\Type\Definition\Type; class SliceDirective extends Directive { /** * Constructor. */ public function __construct() { parent::__construct([ 'name' => 'slice', 'args' => [ [ 'name' => 'offset', 'type' => Type::int(), ], [ 'name' => 'limit', 'type' => Type::int(), ], ], 'locations' => ['FIELD', 'FRAGMENT_SPREAD', 'INLINE_FRAGMENT'], ]); } /** * Directive callback. * * @param array $params * * @return \Closure */ public function __invoke(array $params) { return function ($root, $args, $context, $info, callable $next) use ($params) { $offset = $params['offset'] ?? 0; $limit = $params['limit'] ?? null; $value = $next($root, $args, $context, $info); // TODO 2.4 no need to check for $offset && $limit ? if (is_array($value) && ($offset || $limit)) { return array_slice($value, (int) $offset, (int) $limit ?: null); } return $value; }; } } PK 6H�\/(l�O O src/Directive/CallDirective.phpnu �[��� <?php namespace YOOtheme\GraphQL\Directive; use YOOtheme\Container; use YOOtheme\GraphQL\Type\Definition\Directive; use YOOtheme\GraphQL\Type\Definition\Type; use YOOtheme\GraphQL\Utils\Middleware; class CallDirective extends Directive { /** * @var Container */ protected $container; /** * Constructor. * * @param Container $container */ public function __construct(Container $container) { parent::__construct([ 'name' => 'call', 'args' => [ [ 'name' => 'func', 'type' => Type::string(), ], [ 'name' => 'args', 'type' => Type::string(), ], ], 'locations' => ['ENUM_VALUE', 'FIELD_DEFINITION'], ]); $this->container = $container; } /** * Resolve value from function callback. * * @param array $params * @param Middleware $resolver * * @return \Closure|void */ public function __invoke(array $params, Middleware $resolver) { // override default resolver $resolver->setHandler($this->container->callback($params['func'])); // merge additional arguments if (isset($params['args']) && is_array($arguments = json_decode($params['args'], true))) { return fn($value, $args, $context, $info, $next) => $next( $value, $args + $arguments, $context, $info, ); } } } PK 6H�\�]*;u u src/Utils/ASTHelper.phpnu �[��� <?php namespace YOOtheme\GraphQL\Utils; use YOOtheme\GraphQL\Type\Definition\FieldDefinition; use YOOtheme\GraphQL\Type\Definition\InputObjectField; use YOOtheme\GraphQL\Type\Definition\InputObjectType; use YOOtheme\GraphQL\Type\Definition\ObjectType; class ASTHelper extends AST { public static function objectType(ObjectType $type) { $node = [ 'kind' => 'ObjectTypeDefinition', 'name' => [ 'kind' => 'Name', 'value' => $type->name, ], 'fields' => [], 'interfaces' => [], 'directives' => [], ]; if (isset($type->config['directives'])) { foreach ($type->config['directives'] as $config) { $node['directives'][] = static::directive($config); } } foreach ($type->getFields() as $field) { $field->astNode = static::field($field); } return static::fromArray($node); } public static function inputType(InputObjectType $type) { $node = [ 'kind' => 'InputObjectTypeDefinition', 'name' => [ 'kind' => 'Name', 'value' => $type->name, ], 'fields' => [], 'directives' => [], ]; foreach ($type->config['directives'] ?? [] as $config) { $node['directives'][] = static::directive($config); } foreach ($type->getFields() as $field) { $field->astNode = static::inputField($field); } return static::fromArray($node); } public static function field(FieldDefinition $field) { $node = [ 'kind' => 'FieldDefinition', 'name' => [ 'kind' => 'Name', 'value' => $field->name, ], 'arguments' => [], 'directives' => [], ]; foreach ($field->config['directives'] ?? [] as $config) { $node['directives'][] = static::directive($config); } return static::fromArray($node); } public static function inputField(InputObjectField $field) { $node = [ 'kind' => 'InputValueDefinition', 'name' => [ 'kind' => 'Name', 'value' => $field->name, ], 'directives' => [], ]; foreach ($field->config['directives'] ?? [] as $config) { $node['directives'][] = static::directive($config); } return static::fromArray($node); } public static function directive(array $config) { $directive = [ 'kind' => 'Directive', 'name' => [ 'kind' => 'Name', 'value' => $config['name'], ], ]; foreach ($config['args'] ?? [] as $name => $value) { $directive['arguments'][] = static::argument($name, $value); } return static::fromArray($directive); } public static function argument($name, $value) { $argument = [ 'kind' => 'Argument', 'name' => [ 'kind' => 'Name', 'value' => $name, ], 'value' => [ 'kind' => 'StringValue', 'value' => $value, ], ]; return static::fromArray($argument); } } PK 6H�\n.$� � src/Utils/Introspection.phpnu �[��� <?php namespace YOOtheme\GraphQL\Utils; use YOOtheme\GraphQL\Type\Definition\ObjectType; use YOOtheme\GraphQL\Type\Introspection as BaseIntrospection; class Introspection extends BaseIntrospection { public static function getIntrospectionQuery(array $options = []): string { $value = fn($val) => is_callable($val) ? $val() : $val; $options += ['defaults' => ['description']]; $fields = []; foreach (static::getTypes() as $name => $type) { if (isset($options[$name]) && $type instanceof ObjectType) { $type->config['fields'] = $value($type->config['fields']) + $options[$name]; $fields[$name] = join( ' ', array_merge($options['defaults'], array_keys($options[$name])), ); } else { $fields[$name] = join(' ', $options['defaults']); } } return <<<EOD query IntrospectionQuery { __schema { queryType { name } mutationType { name } subscriptionType { name } types { ...FullType } directives { name {$fields['__Directive']} locations args { ...InputValue } } } } fragment FullType on __Type { kind name {$fields['__Type']} fields(includeDeprecated: true) { name {$fields['__Field']} args { ...InputValue } type { ...TypeRef } } inputFields { ...InputValue } interfaces { ...TypeRef } enumValues(includeDeprecated: true) { name {$fields['__EnumValue']} } possibleTypes { ...TypeRef } } fragment InputValue on __InputValue { name {$fields['__InputValue']} type { ...TypeRef } defaultValue } fragment TypeRef on __Type { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name } } } } } } } } EOD; } } PK 6H�\ gǎ� � src/Utils/Middleware.phpnu �[��� <?php namespace YOOtheme\GraphQL\Utils; class Middleware { /** * @var callable|null */ protected $handler; /** * @var array */ protected $stack = []; /** * Constructor. * * @param callable $handler */ public function __construct(?callable $handler = null) { $this->handler = $handler; } /** * Invokes the next middleware handler. * * @param mixed ...$arguments * * @return mixed */ public function __invoke(...$arguments) { if ($this->stack) { $arguments[] = $this; } $handler = array_shift($this->stack) ?: $this->handler; return $handler(...$arguments); } /** * Returns true if handler exists. */ public function hasHandler() { return isset($this->handler); } /** * Sets the middleware handler. * * @param callable $handler */ public function setHandler(callable $handler) { $this->handler = $handler; } /** * Unshift a middleware to the bottom of the stack. * * @param callable $middleware */ public function unshift(callable $middleware) { array_unshift($this->stack, $middleware); } /** * Push a middleware to the top of the stack. * * @param callable $middleware */ public function push(callable $middleware) { $this->stack[] = $middleware; } } PK 6H�\����? ? src/Plugin/ContainerPlugin.phpnu �[��� <?php namespace YOOtheme\GraphQL\Plugin; use YOOtheme\Container; use YOOtheme\GraphQL\Directive\BindDirective; use YOOtheme\GraphQL\Directive\CallDirective; use YOOtheme\GraphQL\SchemaBuilder; use YOOtheme\GraphQL\Type\Definition\Type; class ContainerPlugin { /** * @var Container */ protected $container; /** * Constructor. * * @param Container $container */ public function __construct(Container $container) { $this->container = $container; } /** * Register directives. * * @param SchemaBuilder $schema */ public function onLoad(SchemaBuilder $schema) { $schema->setDirective(new BindDirective($this->container)); $schema->setDirective(new CallDirective($this->container)); } /** * Add directives on type. * * @param Type $type */ public function onLoadType(Type $type) { if ( property_exists($type, 'config') && ($extensions = $type->config['extensions'] ?? []) && ($directives = $this->getDirectives($extensions)) ) { $type->config['directives'] = array_merge( $type->config['directives'] ?? [], $directives, ); } } /** * Add directives on field. * * @param Type $type * @param array $field * * @return array */ public function onLoadField(Type $type, array $field) { $extensions = $field['extensions'] ?? []; if ($extensions && ($directives = $this->getDirectives($extensions))) { if (!isset($field['directives'])) { $field['directives'] = []; } $field['directives'] = array_merge($field['directives'], $directives); } return $field; } /** * Get directives. * * @param array $extensions * * @return array */ protected function getDirectives(array $extensions) { $directives = []; if (isset($extensions['bind'])) { foreach ($extensions['bind'] as $id => $params) { $directives[] = $this->bindDirective($id, $params); } } if (isset($extensions['call'])) { $directives[] = $this->callDirective($extensions['call']); } return $directives; } /** * Get @bind directive. * * @param string $id * @param string|array $params * * @return array */ protected function bindDirective($id, $params) { if (is_string($params)) { $params = ['class' => $params]; } if (isset($params['args'])) { $params['args'] = json_encode($params['args']); } return [ 'name' => 'bind', 'args' => array_filter(compact('id') + $params), ]; } /** * Get @call directive. * * @param string|array $params * * @return array */ protected function callDirective($params) { if (is_string($params)) { $params = ['func' => $params]; } if (isset($params['args'])) { $params['args'] = json_encode($params['args']); } return [ 'name' => 'call', 'args' => $params, ]; } } PK 6H�\T�8�S1 S1 src/SchemaBuilder.phpnu �[��� <?php namespace YOOtheme\GraphQL; use YOOtheme\GraphQL\Error\InvariantViolation; use YOOtheme\GraphQL\Executor\Executor; use YOOtheme\GraphQL\Executor\Values; use YOOtheme\GraphQL\Language\AST\DirectiveNode; use YOOtheme\GraphQL\Language\AST\NodeList; use YOOtheme\GraphQL\Language\Parser; use YOOtheme\GraphQL\Type\Definition\Directive; use YOOtheme\GraphQL\Type\Definition\InputObjectType; use YOOtheme\GraphQL\Type\Definition\NamedType; use YOOtheme\GraphQL\Type\Definition\ObjectType; use YOOtheme\GraphQL\Type\Definition\ResolveInfo; use YOOtheme\GraphQL\Type\Definition\Type; use YOOtheme\GraphQL\Type\Schema; use YOOtheme\GraphQL\Utils\ASTHelper; use YOOtheme\GraphQL\Utils\BuildSchema; use YOOtheme\GraphQL\Utils\Middleware; class SchemaBuilder { /** * @var callable[][] */ protected $hooks = []; /** * @var Type[] */ protected $types = []; /** * @var Type[] */ protected $loadedTypes = []; /** * @var array */ protected $directives = []; /** * Constructor. * * @param array $plugins */ public function __construct(array $plugins = []) { $this->hooks = [ 'onLoad' => [], 'onLoadType' => [], 'onLoadField' => [], ]; foreach ($plugins as $plugin) { $this->loadPlugin($plugin); } /** @phpstan-ignore-next-line */ foreach ($this->hooks['onLoad'] as $hook) { $hook($this); } } /** * @param string $file * @param string $cache * * @return Schema */ public function loadSchema($file, $cache = null) { $isCached = is_file($cache) && filectime($cache) > filectime($file); $document = $isCached ? ASTHelper::fromArray(require $cache) : Parser::parse(file_get_contents($file), ['noLocation' => true]); $result = BuildSchema::build( $document, fn(array $config) => ['resolveField' => [$this, 'resolveField']] + $config, ['assumeValid' => $isCached, 'assumeValidSDL' => $isCached], ); if (!$isCached && $cache) { file_put_contents( $cache, "<?php\n\nreturn {$this->exportValue(ASTHelper::toArray($document))};", ); } return $result; } /** * @param array $config * * @return Schema */ public function buildSchema(array $config = []) { $config = array_replace_recursive( [ 'query' => 'Query', 'mutation' => 'Mutation', 'subscription' => 'Subscription', 'directives' => $this->directives, 'typeLoader' => [$this, 'getType'], ], $config, ); if (is_string($config['query'])) { $config['query'] = $this->getType($config['query']); } if (is_string($config['mutation'])) { $config['mutation'] = $this->getType($config['mutation']); } if (is_string($config['subscription'])) { $config['subscription'] = $this->getType($config['subscription']); } return new Schema($config); } /** * @param array $config * * @return string */ public function printSchema(array $config = []) { return SchemaPrinter::doPrint($this->buildSchema($config)); } /** * @param string $name * * @return Directive */ public function getDirective($name) { return $this->directives[$name] ?? null; } /** * @param Directive $directive */ public function setDirective(Directive $directive) { $this->directives[$directive->name] = $directive; } /** * @param string $name * * @return bool */ public function hasType($name) { return isset($this->types[$name]); } /** * @param string $name * * @return Type|void */ public function getType($name) { if (empty($this->loadedTypes)) { $this->loadedTypes = Type::getStandardTypes(); } if (isset($this->loadedTypes[$name])) { return $this->loadedTypes[$name]; } if (isset($this->types[$name])) { return $this->loadType($this->loadedTypes[$name] = $this->types[$name]); } } /** * @param Type $type */ public function setType(Type $type) { /** @var NamedType $type */ $this->types[$type->name] = $type; } /** * @param array|callable $config * * @return ObjectType */ public function queryType($config = []) { return $this->objectType('Query', $config); } /** * @param string $name * @param array|callable $config * * @return InputObjectType */ public function inputType($name, $config = []) { $type = $this->types[$name] ?? new InputObjectType([ 'name' => $name, 'fields' => [], ]); if (!$type instanceof InputObjectType) { throw new InvariantViolation("Type '{$name}' must be an InputObjectType."); } return $this->types[$name] = $this->extendType($type, $config); } /** * @param string $name * @param array|callable $config * * @return ObjectType */ public function objectType($name, $config = []) { $type = $this->types[$name] ?? new ObjectType([ 'name' => $name, 'fields' => [], 'resolveField' => [$this, 'resolveField'], ]); if (!$type instanceof ObjectType) { throw new InvariantViolation("Type '{$name}' must be an ObjectType."); } return $this->types[$name] = $this->extendType($type, $config); } /** * @template T of Type * @param T $type * @param array|callable $config * @return T */ public function extendType(Type $type, $config = []) { if (is_callable($config)) { $config = $config($type, $this); } if (is_array($config) && property_exists($type, 'config')) { $type->config = array_replace_recursive($type->config, $config); } return $type; } /** * @template T of Type * @param T $type * @return T */ public function loadType(Type $type) { foreach ($this->hooks['onLoadType'] as $hook) { $hook($type, $this); } if (isset($type->config['description']) && property_exists($type, 'description')) { $type->description = $type->config['description']; } if (isset($type->config['resolveField']) && $type instanceof ObjectType) { $type->resolveFieldFn = $type->config['resolveField']; } if (isset($type->config['fields'])) { $type->config['fields'] = $this->loadFields($type, $type->config['fields']); } if ($type instanceof ObjectType) { $type->astNode = ASTHelper::objectType($type); } elseif ($type instanceof InputObjectType) { $type->astNode = ASTHelper::inputType($type); } return $type; } /** * @param mixed $value * @param mixed $args * @param mixed $context * @param ResolveInfo $info * * @return mixed */ public function resolveField($value, $args, $context, ResolveInfo $info) { $resolver = new Middleware([Executor::class, 'defaultFieldResolver']); foreach ($this->resolveDirectives($info) as $directiveNode) { $directiveDef = $this->getDirective($directiveNode->name->value); if (is_callable($directiveDef)) { $directive = $directiveDef( Values::getArgumentValues($directiveDef, $directiveNode, $info->variableValues), $resolver, ); if (is_callable($directive)) { $resolver->push($directive); } } } return $resolver($value, $args, $context, $info); } /** * @return NodeList<DirectiveNode> */ public function resolveDirectives(ResolveInfo $info) { $nodes = new NodeList([]); $field = $info->parentType->getField($info->fieldName); // type directives if (isset($info->parentType->astNode->directives)) { $nodes = $nodes->merge($info->parentType->astNode->directives); } // field directives if (isset($field->astNode->directives)) { $nodes = $nodes->merge($field->astNode->directives); } // query field directives foreach ($info->fieldNodes as $node) { if ($info->fieldName === $node->name->value) { return $nodes->merge($node->directives); } } return $nodes; } /** * @param Type $type * @param array $field * * @return array */ protected function loadField(Type $type, array $field) { $field += ['type' => null]; if (is_string($field['type'])) { $field['type'] = $this->getType($field['type']); } if (is_array($field['type'])) { $field['type'] = $this->loadModifiers($field['type']); } if (empty($field['type'])) { /** @var NamedType $type */ throw new InvariantViolation( "Field '{$field['name']}' on '{$type->name}' does not have a Type.", ); } return $field; } /** * @param Type $type * @param array $fields * * @return array */ protected function loadFields(Type $type, array $fields) { $result = []; foreach ($fields as $name => $field) { $field = $this->loadField( $type, $field + [ 'name' => lcfirst($name), 'args' => [], ], ); foreach ($field['args'] as $key => $arg) { $field['args'][$key] = $this->loadField($type, $arg); } foreach ($this->hooks['onLoadField'] as $hook) { $field = $hook($type, $field, $this); } $result[$name] = $field; } return $result; } /** * @param array $type * * @return Type|array */ protected function loadModifiers(array $type) { if (isset($type['nonNull'])) { if (is_string($type['nonNull'])) { $nonNull = $this->getType($type['nonNull']); } elseif (is_array($type['nonNull'])) { $nonNull = $this->loadModifiers($type['nonNull']); } $type = Type::nonNull($nonNull ?? Type::string()); } elseif (isset($type['listOf'])) { if (is_string($type['listOf'])) { $listOf = $this->getType($type['listOf']); } elseif (is_array($type['listOf'])) { $listOf = $this->loadModifiers($type['listOf']); } $type = Type::listOf($listOf ?? Type::string()); } return $type; } /** * @param mixed $plugin */ protected function loadPlugin($plugin) { foreach ($this->hooks as $method => &$hooks) { $hook = [$plugin, $method]; if (is_callable($hook)) { $hooks[] = $hook; } } } /** * Export a parsable string representation of a value. * * @param mixed $value * @param int $indent * * @return string */ protected function exportValue($value, $indent = 0) { if (is_array($value)) { $array = []; $assoc = array_values($value) !== $value; $indention = str_repeat(' ', $indent); $indentlast = $assoc ? "\n" . $indention : ''; foreach ($value as $key => $val) { $array[] = ($assoc ? "\n " . $indention . var_export($key, true) . ' => ' : '') . $this->exportValue($val, $indent + 1); } return '[' . join(', ', $array) . $indentlast . ']'; } return var_export($value, true); } } PK 6H�\��|� � src/SchemaPrinter.phpnu �[��� <?php namespace YOOtheme\GraphQL; use YOOtheme\GraphQL\Error\Error; use YOOtheme\GraphQL\Language\Printer; use YOOtheme\GraphQL\Type\Definition\InterfaceType; use YOOtheme\GraphQL\Type\Definition\ObjectType; use YOOtheme\GraphQL\Type\Schema; use YOOtheme\GraphQL\Utils\SchemaPrinter as BasePrinter; use YOOtheme\GraphQL\Utils\Utils; use function array_keys; use function array_map; use function array_values; use function compact; use function count; use function implode; use function sprintf; /** * Given an instance of Schema, prints it in GraphQL type language. */ class SchemaPrinter extends BasePrinter { /** * @inheritdoc */ public static function doPrint(Schema $schema, array $options = []): string { return parent::doPrint($schema, $options + compact('schema')); } /** * @inheritdoc */ public static function printIntrospectionSchema(Schema $schema, array $options = []): string { return parent::printIntrospectionSchema($schema, $options + compact('schema')); } /** * @inheritdoc */ protected static function printObject(ObjectType $type, array $options): string { $interfaces = $type->getInterfaces(); $implementedInterfaces = count($interfaces) > 0 ? ' implements ' . implode( ' & ', array_map( fn(InterfaceType $interface): string => $interface->name, $interfaces, ), ) : ''; return static::printDescription($options, $type) . sprintf( "type %s%s%s {\n%s\n}", $type->name, $implementedInterfaces, static::printDirectives($type, $options), static::printFields($options, $type), ); } /** * @inheritdoc */ protected static function printFields(array $options, $type): string { $fields = array_values($type->getFields()); return implode( "\n", array_map( fn($f, $i) => static::printDescription($options, $f, ' ', !$i) . ' ' . $f->name . static::printArgs($options, $f->args, ' ') . ': ' . $f->getType() . static::printDirectives($f, $options) . static::printDeprecated($f), $fields, array_keys($fields), ), ); } protected static function printDirectives($fieldOrType, array $options): string { $directives = []; if (isset($fieldOrType->astNode->directives)) { foreach ($fieldOrType->astNode->directives as $directive) { if (!$options['schema']->getDirective($directive->name->value)) { throw new Error( 'Unknown directive: ' . Utils::printSafe($directive->name->value) . '.', ); } $directives[] = Printer::doPrint($directive); } } return $directives ? ' ' . implode(' ', $directives) : ''; } } PK 6H�\���Į � src/Type/ObjectScalarType.phpnu �[��� <?php namespace YOOtheme\GraphQL\Type; use YOOtheme\GraphQL\Error\Error; use YOOtheme\GraphQL\Language\AST\Node; use YOOtheme\GraphQL\Type\Definition\ScalarType; class ObjectScalarType extends ScalarType { /** * @param array $config */ public function __construct(array $config = []) { parent::__construct($config + ['name' => 'Object']); } /** * @param mixed $value * * @return mixed */ public function serialize($value) { return $value; } /** * @param mixed $value * * @return array|null */ public function parseValue($value) { return is_array($value) ? $value : null; } /** * @param Node $valueNode * @param null|array $variables */ public function parseLiteral($valueNode, ?array $variables = null) { throw new Error("Query error: Can't parse Object literal"); } } PK 6H�\R��� ! ! lib/GraphQL.phpnu �[��� <?php declare(strict_types=1); namespace YOOtheme\GraphQL; use YOOtheme\GraphQL\Error\Error; use YOOtheme\GraphQL\Error\InvariantViolation; use YOOtheme\GraphQL\Executor\ExecutionResult; use YOOtheme\GraphQL\Executor\Executor; use YOOtheme\GraphQL\Executor\Promise\Adapter\SyncPromiseAdapter; use YOOtheme\GraphQL\Executor\Promise\Promise; use YOOtheme\GraphQL\Executor\Promise\PromiseAdapter; use YOOtheme\GraphQL\Language\AST\DocumentNode; use YOOtheme\GraphQL\Language\Parser; use YOOtheme\GraphQL\Language\Source; use YOOtheme\GraphQL\Type\Definition\Directive; use YOOtheme\GraphQL\Type\Definition\ScalarType; use YOOtheme\GraphQL\Type\Definition\Type; use YOOtheme\GraphQL\Type\Schema as SchemaType; use YOOtheme\GraphQL\Validator\DocumentValidator; use YOOtheme\GraphQL\Validator\Rules\QueryComplexity; use YOOtheme\GraphQL\Validator\Rules\ValidationRule; /** * This is the primary facade for fulfilling GraphQL operations. * See [related documentation](executing-queries.md). * * @phpstan-import-type ArgsMapper from Executor * @phpstan-import-type FieldResolver from Executor * * @see \GraphQL\Tests\GraphQLTest */ class GraphQL { /** * Executes graphql query. * * More sophisticated GraphQL servers, such as those which persist queries, * may wish to separate the validation and execution phases to a static time * tooling step, and a server runtime step. * * Available options: * * schema: * The GraphQL type system to use when validating and executing a query. * source: * A GraphQL language formatted string representing the requested operation. * rootValue: * The value provided as the first argument to resolver functions on the top * level type (e.g. the query object type). * contextValue: * The context value is provided as an argument to resolver functions after * field arguments. It is used to pass shared information useful at any point * during executing this query, for example the currently logged in user and * connections to databases or other services. * If the passed object implements the `ScopedContext` interface, * its `clone()` method will be called before passing the context down to a field. * This allows passing information to child fields in the query tree without affecting sibling or parent fields. * variableValues: * A mapping of variable name to runtime value to use for all variables * defined in the requestString. * operationName: * The name of the operation to use if requestString contains multiple * possible operations. Can be omitted if requestString contains only * one operation. * fieldResolver: * A resolver function to use when one is not provided by the schema. * If not provided, the default field resolver is used (which looks for a * value on the source value with the field's name). * validationRules: * A set of rules for query validation step. Default value is all available rules. * Empty array would allow to skip query validation (may be convenient for persisted * queries which are validated before persisting and assumed valid during execution) * * @param string|DocumentNode $source * @param mixed $rootValue * @param mixed $contextValue * @param array<string, mixed>|null $variableValues * @param array<ValidationRule>|null $validationRules * * @api * * @throws \Exception * @throws InvariantViolation */ public static function executeQuery( SchemaType $schema, $source, $rootValue = null, $contextValue = null, ?array $variableValues = null, ?string $operationName = null, ?callable $fieldResolver = null, ?array $validationRules = null ): ExecutionResult { $promiseAdapter = new SyncPromiseAdapter(); $promise = self::promiseToExecute( $promiseAdapter, $schema, $source, $rootValue, $contextValue, $variableValues, $operationName, $fieldResolver, $validationRules ); return $promiseAdapter->wait($promise); } /** * Same as executeQuery(), but requires PromiseAdapter and always returns a Promise. * Useful for Async PHP platforms. * * @param string|DocumentNode $source * @param mixed $rootValue * @param mixed $context * @param array<string, mixed>|null $variableValues * @param array<ValidationRule>|null $validationRules Defaults to using all available rules * * @api * * @throws \Exception */ public static function promiseToExecute( PromiseAdapter $promiseAdapter, SchemaType $schema, $source, $rootValue = null, $context = null, ?array $variableValues = null, ?string $operationName = null, ?callable $fieldResolver = null, ?array $validationRules = null ): Promise { try { $documentNode = $source instanceof DocumentNode ? $source : Parser::parse(new Source($source, 'GraphQL')); if ($validationRules === null) { $queryComplexity = DocumentValidator::getRule(QueryComplexity::class); assert($queryComplexity instanceof QueryComplexity, 'should not register a different rule for QueryComplexity'); $queryComplexity->setRawVariableValues($variableValues); } else { foreach ($validationRules as $rule) { if ($rule instanceof QueryComplexity) { $rule->setRawVariableValues($variableValues); } } } $validationErrors = DocumentValidator::validate($schema, $documentNode, $validationRules); if ($validationErrors !== []) { return $promiseAdapter->createFulfilled( new ExecutionResult(null, $validationErrors) ); } return Executor::promiseToExecute( $promiseAdapter, $schema, $documentNode, $rootValue, $context, $variableValues, $operationName, $fieldResolver ); } catch (Error $e) { return $promiseAdapter->createFulfilled( new ExecutionResult(null, [$e]) ); } } /** * Returns directives defined in GraphQL spec. * * @throws InvariantViolation * * @return array<string, Directive> * * @api */ public static function getStandardDirectives(): array { return Directive::getInternalDirectives(); } /** * Returns types defined in GraphQL spec. * * @throws InvariantViolation * * @return array<string, ScalarType> * * @api */ public static function getStandardTypes(): array { return Type::getStandardTypes(); } /** * Replaces standard types with types from this list (matching by name). * * Standard types not listed here remain untouched. * * @param array<string, ScalarType> $types * * @api * * @throws InvariantViolation */ public static function overrideStandardTypes(array $types): void { Type::overrideStandardTypes($types); } /** * Returns standard validation rules implementing GraphQL spec. * * @return array<class-string<ValidationRule>, ValidationRule> * * @api */ public static function getStandardValidationRules(): array { return DocumentValidator::defaultRules(); } /** * Set default resolver implementation. * * @phpstan-param FieldResolver $fn * * @api */ public static function setDefaultFieldResolver(callable $fn): void { Executor::setDefaultFieldResolver($fn); } /** * Set default args mapper implementation. * * @phpstan-param ArgsMapper $fn * * @api */ public static function setDefaultArgsMapper(callable $fn): void { Executor::setDefaultArgsMapper($fn); } } PK 6H�\�V��/ �/ # lib/Validator/DocumentValidator.phpnu �[��� <?php declare(strict_types=1); namespace YOOtheme\GraphQL\Validator; use YOOtheme\GraphQL\Error\Error; use YOOtheme\GraphQL\Language\AST\DocumentNode; use YOOtheme\GraphQL\Language\Visitor; use YOOtheme\GraphQL\Type\Schema; use YOOtheme\GraphQL\Utils\TypeInfo; use YOOtheme\GraphQL\Validator\Rules\DisableIntrospection; use YOOtheme\GraphQL\Validator\Rules\ExecutableDefinitions; use YOOtheme\GraphQL\Validator\Rules\FieldsOnCorrectType; use YOOtheme\GraphQL\Validator\Rules\FragmentsOnCompositeTypes; use YOOtheme\GraphQL\Validator\Rules\KnownArgumentNames; use YOOtheme\GraphQL\Validator\Rules\KnownArgumentNamesOnDirectives; use YOOtheme\GraphQL\Validator\Rules\KnownDirectives; use YOOtheme\GraphQL\Validator\Rules\KnownFragmentNames; use YOOtheme\GraphQL\Validator\Rules\KnownTypeNames; use YOOtheme\GraphQL\Validator\Rules\LoneAnonymousOperation; use YOOtheme\GraphQL\Validator\Rules\LoneSchemaDefinition; use YOOtheme\GraphQL\Validator\Rules\NoFragmentCycles; use YOOtheme\GraphQL\Validator\Rules\NoUndefinedVariables; use YOOtheme\GraphQL\Validator\Rules\NoUnusedFragments; use YOOtheme\GraphQL\Validator\Rules\NoUnusedVariables; use YOOtheme\GraphQL\Validator\Rules\OneOfInputObjectsRule; use YOOtheme\GraphQL\Validator\Rules\OverlappingFieldsCanBeMerged; use YOOtheme\GraphQL\Validator\Rules\PossibleFragmentSpreads; use YOOtheme\GraphQL\Validator\Rules\PossibleTypeExtensions; use YOOtheme\GraphQL\Validator\Rules\ProvidedRequiredArguments; use YOOtheme\GraphQL\Validator\Rules\ProvidedRequiredArgumentsOnDirectives; use YOOtheme\GraphQL\Validator\Rules\QueryComplexity; use YOOtheme\GraphQL\Validator\Rules\QueryDepth; use YOOtheme\GraphQL\Validator\Rules\QuerySecurityRule; use YOOtheme\GraphQL\Validator\Rules\ScalarLeafs; use YOOtheme\GraphQL\Validator\Rules\SingleFieldSubscription; use YOOtheme\GraphQL\Validator\Rules\UniqueArgumentDefinitionNames; use YOOtheme\GraphQL\Validator\Rules\UniqueArgumentNames; use YOOtheme\GraphQL\Validator\Rules\UniqueDirectiveNames; use YOOtheme\GraphQL\Validator\Rules\UniqueDirectivesPerLocation; use YOOtheme\GraphQL\Validator\Rules\UniqueEnumValueNames; use YOOtheme\GraphQL\Validator\Rules\UniqueFieldDefinitionNames; use YOOtheme\GraphQL\Validator\Rules\UniqueFragmentNames; use YOOtheme\GraphQL\Validator\Rules\UniqueInputFieldNames; use YOOtheme\GraphQL\Validator\Rules\UniqueOperationNames; use YOOtheme\GraphQL\Validator\Rules\UniqueOperationTypes; use YOOtheme\GraphQL\Validator\Rules\UniqueTypeNames; use YOOtheme\GraphQL\Validator\Rules\UniqueVariableNames; use YOOtheme\GraphQL\Validator\Rules\ValidationRule; use YOOtheme\GraphQL\Validator\Rules\ValuesOfCorrectType; use YOOtheme\GraphQL\Validator\Rules\VariablesAreInputTypes; use YOOtheme\GraphQL\Validator\Rules\VariablesInAllowedPosition; /** * Implements the "Validation" section of the spec. * * Validation runs synchronously, returning an array of encountered errors, or * an empty array if no errors were encountered and the document is valid. * * A list of specific validation rules may be provided. If not provided, the * default list of rules defined by the GraphQL specification will be used. * * Each validation rule is an instance of GraphQL\Validator\Rules\ValidationRule * which returns a visitor (see the [GraphQL\Language\Visitor API](class-reference.md#graphqllanguagevisitor)). * * Visitor methods are expected to return an instance of [GraphQL\Error\Error](class-reference.md#graphqlerrorerror), * or array of such instances when invalid. * * Optionally a custom TypeInfo instance may be provided. If not provided, one * will be created from the provided schema. */ class DocumentValidator { /** @var array<string, ValidationRule> */ private static array $rules = []; /** @var array<class-string<ValidationRule>, ValidationRule> */ private static array $defaultRules; /** @var array<class-string<QuerySecurityRule>, QuerySecurityRule> */ private static array $securityRules; /** @var array<class-string<ValidationRule>, ValidationRule> */ private static array $sdlRules; private static bool $initRules = false; /** * Validate a GraphQL query against a schema. * * @param array<ValidationRule>|null $rules Defaults to using all available rules * * @throws \Exception * * @return list<Error> * * @api */ public static function validate( Schema $schema, DocumentNode $ast, ?array $rules = null, ?TypeInfo $typeInfo = null ): array { $rules ??= static::allRules(); if ($rules === []) { return []; } $typeInfo ??= new TypeInfo($schema); $context = new QueryValidationContext($schema, $ast, $typeInfo); $visitors = []; foreach ($rules as $rule) { $visitors[] = $rule->getVisitor($context); } Visitor::visit( $ast, Visitor::visitWithTypeInfo( $typeInfo, Visitor::visitInParallel($visitors) ) ); return $context->getErrors(); } /** * Returns all global validation rules. * * @throws \InvalidArgumentException * * @return array<string, ValidationRule> * * @api */ public static function allRules(): array { if (! self::$initRules) { self::$rules = array_merge( static::defaultRules(), self::securityRules(), self::$rules ); self::$initRules = true; } return self::$rules; } /** @return array<class-string<ValidationRule>, ValidationRule> */ public static function defaultRules(): array { return self::$defaultRules ??= [ ExecutableDefinitions::class => new ExecutableDefinitions(), UniqueOperationNames::class => new UniqueOperationNames(), LoneAnonymousOperation::class => new LoneAnonymousOperation(), SingleFieldSubscription::class => new SingleFieldSubscription(), KnownTypeNames::class => new KnownTypeNames(), FragmentsOnCompositeTypes::class => new FragmentsOnCompositeTypes(), VariablesAreInputTypes::class => new VariablesAreInputTypes(), ScalarLeafs::class => new ScalarLeafs(), FieldsOnCorrectType::class => new FieldsOnCorrectType(), UniqueFragmentNames::class => new UniqueFragmentNames(), KnownFragmentNames::class => new KnownFragmentNames(), NoUnusedFragments::class => new NoUnusedFragments(), PossibleFragmentSpreads::class => new PossibleFragmentSpreads(), NoFragmentCycles::class => new NoFragmentCycles(), UniqueVariableNames::class => new UniqueVariableNames(), NoUndefinedVariables::class => new NoUndefinedVariables(), NoUnusedVariables::class => new NoUnusedVariables(), KnownDirectives::class => new KnownDirectives(), UniqueDirectivesPerLocation::class => new UniqueDirectivesPerLocation(), KnownArgumentNames::class => new KnownArgumentNames(), UniqueArgumentNames::class => new UniqueArgumentNames(), ValuesOfCorrectType::class => new ValuesOfCorrectType(), ProvidedRequiredArguments::class => new ProvidedRequiredArguments(), VariablesInAllowedPosition::class => new VariablesInAllowedPosition(), OverlappingFieldsCanBeMerged::class => new OverlappingFieldsCanBeMerged(), UniqueInputFieldNames::class => new UniqueInputFieldNames(), OneOfInputObjectsRule::class => new OneOfInputObjectsRule(), ]; } /** * @deprecated just add rules via @see DocumentValidator::addRule() * * @throws \InvalidArgumentException * * @return array<class-string<QuerySecurityRule>, QuerySecurityRule> */ public static function securityRules(): array { return self::$securityRules ??= [ DisableIntrospection::class => new DisableIntrospection(DisableIntrospection::DISABLED), QueryDepth::class => new QueryDepth(QueryDepth::DISABLED), QueryComplexity::class => new QueryComplexity(QueryComplexity::DISABLED), ]; } /** @return array<class-string<ValidationRule>, ValidationRule> */ public static function sdlRules(): array { return self::$sdlRules ??= [ LoneSchemaDefinition::class => new LoneSchemaDefinition(), UniqueOperationTypes::class => new UniqueOperationTypes(), UniqueTypeNames::class => new UniqueTypeNames(), UniqueEnumValueNames::class => new UniqueEnumValueNames(), UniqueFieldDefinitionNames::class => new UniqueFieldDefinitionNames(), UniqueArgumentDefinitionNames::class => new UniqueArgumentDefinitionNames(), UniqueDirectiveNames::class => new UniqueDirectiveNames(), KnownTypeNames::class => new KnownTypeNames(), KnownDirectives::class => new KnownDirectives(), UniqueDirectivesPerLocation::class => new UniqueDirectivesPerLocation(), PossibleTypeExtensions::class => new PossibleTypeExtensions(), KnownArgumentNamesOnDirectives::class => new KnownArgumentNamesOnDirectives(), UniqueArgumentNames::class => new UniqueArgumentNames(), UniqueInputFieldNames::class => new UniqueInputFieldNames(), ProvidedRequiredArgumentsOnDirectives::class => new ProvidedRequiredArgumentsOnDirectives(), ]; } /** * Returns global validation rule by name. * * Standard rules are named by class name, so example usage for such rules: * * @example DocumentValidator::getRule(GraphQL\Validator\Rules\QueryComplexity::class); * * @api * * @throws \InvalidArgumentException */ public static function getRule(string $name): ?ValidationRule { return static::allRules()[$name] ?? null; } /** * Add rule to list of global validation rules. * * @api */ public static function addRule(ValidationRule $rule): void { self::$rules[$rule->getName()] = $rule; } /** * Remove rule from list of global validation rules. * * @api */ public static function removeRule(ValidationRule $rule): void { unset(self::$rules[$rule->getName()]); } /** * Validate a GraphQL document defined through schema definition language. * * @param array<ValidationRule>|null $rules * * @throws \Exception * * @return list<Error> */ public static function validateSDL( DocumentNode $documentAST, ?Schema $schemaToExtend = null, ?array $rules = null ): array { $rules ??= self::sdlRules(); if ($rules === []) { return []; } $context = new SDLValidationContext($documentAST, $schemaToExtend); $visitors = []; foreach ($rules as $rule) { $visitors[] = $rule->getSDLVisitor($context); } Visitor::visit( $documentAST, Visitor::visitInParallel($visitors) ); return $context->getErrors(); } /** * @throws \Exception * @throws Error */ public static function assertValidSDL(DocumentNode $documentAST): void { $errors = self::validateSDL($documentAST); if ($errors !== []) { throw new Error(self::combineErrorMessages($errors)); } } /** * @throws \Exception * @throws Error */ public static function assertValidSDLExtension(DocumentNode $documentAST, Schema $schema): void { $errors = self::validateSDL($documentAST, $schema); if ($errors !== []) { throw new Error(self::combineErrorMessages($errors)); } } /** @param array<Error> $errors */ private static function combineErrorMessages(array $errors): string { $messages = []; foreach ($errors as $error) { $messages[] = $error->getMessage(); } return implode("\n\n", $messages); } } PK 6H�\�:I� "