Added dependency plugins

This commit is contained in:
Moris Zen
2018-06-25 00:00:37 +02:00
parent 720a1c31a4
commit f069f6782f
698 changed files with 289637 additions and 1 deletions

View File

@@ -0,0 +1,7 @@
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit989472a815f7398c1ff4d2e496f07f11::getLoader();

View File

@@ -0,0 +1,445 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Autoload;
/**
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
*
* $loader = new \Composer\Autoload\ClassLoader();
*
* // register classes with namespaces
* $loader->add('Symfony\Component', __DIR__.'/component');
* $loader->add('Symfony', __DIR__.'/framework');
*
* // activate the autoloader
* $loader->register();
*
* // to enable searching the include path (eg. for PEAR packages)
* $loader->setUseIncludePath(true);
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* This class is loosely based on the Symfony UniversalClassLoader.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see http://www.php-fig.org/psr/psr-0/
* @see http://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
// PSR-4
private $prefixLengthsPsr4 = array();
private $prefixDirsPsr4 = array();
private $fallbackDirsPsr4 = array();
// PSR-0
private $prefixesPsr0 = array();
private $fallbackDirsPsr0 = array();
private $useIncludePath = false;
private $classMap = array();
private $classMapAuthoritative = false;
private $missingClasses = array();
private $apcuPrefix;
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', $this->prefixesPsr0);
}
return array();
}
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array $classMap Class to filename map
*/
public function addClassMap(array $classMap)
{
if ($this->classMap) {
$this->classMap = array_merge($this->classMap, $classMap);
} else {
$this->classMap = $classMap;
}
}
/**
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*/
public function add($prefix, $paths, $prepend = false)
{
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
(array) $paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
(array) $paths
);
}
return;
}
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
(array) $paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
(array) $paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 base directories
*/
public function set($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr0 = (array) $paths;
} else {
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
}
}
/**
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*/
public function setPsr4($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr4 = (array) $paths;
} else {
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
}
}
/**
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*/
public function setUseIncludePath($useIncludePath)
{
$this->useIncludePath = $useIncludePath;
}
/**
* Can be used to check if the autoloader uses the include path to check
* for classes.
*
* @return bool
*/
public function getUseIncludePath()
{
return $this->useIncludePath;
}
/**
* Turns off searching the prefix and fallback directories for classes
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
$this->classMapAuthoritative = $classMapAuthoritative;
}
/**
* Should class lookup fail if not found in the current class map?
*
* @return bool
*/
public function isClassMapAuthoritative()
{
return $this->classMapAuthoritative;
}
/**
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
*
* @param string|null $apcuPrefix
*/
public function setApcuPrefix($apcuPrefix)
{
$this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
}
/**
* The APCu prefix in use, or null if APCu caching is not enabled.
*
* @return string|null
*/
public function getApcuPrefix()
{
return $this->apcuPrefix;
}
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}
/**
* Unregisters this instance as an autoloader.
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return bool|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
return true;
}
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|false The path if found, false otherwise
*/
public function findFile($class)
{
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
return false;
}
if (null !== $this->apcuPrefix) {
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
if ($hit) {
return $file;
}
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if (false === $file && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}
if (null !== $this->apcuPrefix) {
apcu_add($this->apcuPrefix.$class, $file);
}
if (false === $file) {
// Remember that this class does not exist.
$this->missingClasses[$class] = true;
}
return $file;
}
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
$subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos);
$search = $subPath.'\\';
if (isset($this->prefixDirsPsr4[$search])) {
foreach ($this->prefixDirsPsr4[$search] as $dir) {
$length = $this->prefixLengthsPsr4[$first][$search];
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
return $file;
}
}
}
}
}
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
// PSR-0 lookup
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
} else {
// PEAR-like class name
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
}
if (isset($this->prefixesPsr0[$first])) {
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
}
}
}
// PSR-0 fallback dirs
foreach ($this->fallbackDirsPsr0 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
// PSR-0 include paths.
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
return false;
}
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*/
function includeFile($file)
{
include $file;
}

View File

@@ -0,0 +1,21 @@
Copyright (c) Nils Adermann, Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,259 @@
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'GraphQLRelay\\Connection\\ArrayConnection' => $vendorDir . '/ivome/graphql-relay-php/src/Connection/ArrayConnection.php',
'GraphQLRelay\\Connection\\Connection' => $vendorDir . '/ivome/graphql-relay-php/src/Connection/Connection.php',
'GraphQLRelay\\Mutation\\Mutation' => $vendorDir . '/ivome/graphql-relay-php/src/Mutation/Mutation.php',
'GraphQLRelay\\Node\\Node' => $vendorDir . '/ivome/graphql-relay-php/src/Node/Node.php',
'GraphQLRelay\\Node\\Plural' => $vendorDir . '/ivome/graphql-relay-php/src/Node/Plural.php',
'GraphQLRelay\\Relay' => $vendorDir . '/ivome/graphql-relay-php/src/Relay.php',
'GraphQL\\Deferred' => $vendorDir . '/webonyx/graphql-php/src/Deferred.php',
'GraphQL\\Error' => $vendorDir . '/webonyx/graphql-php/src/Error.php',
'GraphQL\\Error\\ClientAware' => $vendorDir . '/webonyx/graphql-php/src/Error/ClientAware.php',
'GraphQL\\Error\\Debug' => $vendorDir . '/webonyx/graphql-php/src/Error/Debug.php',
'GraphQL\\Error\\Error' => $vendorDir . '/webonyx/graphql-php/src/Error/Error.php',
'GraphQL\\Error\\FormattedError' => $vendorDir . '/webonyx/graphql-php/src/Error/FormattedError.php',
'GraphQL\\Error\\InvariantViolation' => $vendorDir . '/webonyx/graphql-php/src/Error/InvariantViolation.php',
'GraphQL\\Error\\SyntaxError' => $vendorDir . '/webonyx/graphql-php/src/Error/SyntaxError.php',
'GraphQL\\Error\\UserError' => $vendorDir . '/webonyx/graphql-php/src/Error/UserError.php',
'GraphQL\\Error\\Warning' => $vendorDir . '/webonyx/graphql-php/src/Error/Warning.php',
'GraphQL\\Executor\\ExecutionContext' => $vendorDir . '/webonyx/graphql-php/src/Executor/ExecutionContext.php',
'GraphQL\\Executor\\ExecutionResult' => $vendorDir . '/webonyx/graphql-php/src/Executor/ExecutionResult.php',
'GraphQL\\Executor\\Executor' => $vendorDir . '/webonyx/graphql-php/src/Executor/Executor.php',
'GraphQL\\Executor\\Promise\\Adapter\\ReactPromiseAdapter' => $vendorDir . '/webonyx/graphql-php/src/Executor/Promise/Adapter/ReactPromiseAdapter.php',
'GraphQL\\Executor\\Promise\\Adapter\\SyncPromise' => $vendorDir . '/webonyx/graphql-php/src/Executor/Promise/Adapter/SyncPromise.php',
'GraphQL\\Executor\\Promise\\Adapter\\SyncPromiseAdapter' => $vendorDir . '/webonyx/graphql-php/src/Executor/Promise/Adapter/SyncPromiseAdapter.php',
'GraphQL\\Executor\\Promise\\Promise' => $vendorDir . '/webonyx/graphql-php/src/Executor/Promise/Promise.php',
'GraphQL\\Executor\\Promise\\PromiseAdapter' => $vendorDir . '/webonyx/graphql-php/src/Executor/Promise/PromiseAdapter.php',
'GraphQL\\Executor\\Values' => $vendorDir . '/webonyx/graphql-php/src/Executor/Values.php',
'GraphQL\\GraphQL' => $vendorDir . '/webonyx/graphql-php/src/GraphQL.php',
'GraphQL\\Language\\AST\\ArgumentNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/ArgumentNode.php',
'GraphQL\\Language\\AST\\BooleanValueNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/BooleanValueNode.php',
'GraphQL\\Language\\AST\\DefinitionNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/DefinitionNode.php',
'GraphQL\\Language\\AST\\DirectiveDefinitionNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/DirectiveDefinitionNode.php',
'GraphQL\\Language\\AST\\DirectiveNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/DirectiveNode.php',
'GraphQL\\Language\\AST\\DocumentNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/DocumentNode.php',
'GraphQL\\Language\\AST\\EnumTypeDefinitionNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/EnumTypeDefinitionNode.php',
'GraphQL\\Language\\AST\\EnumValueDefinitionNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/EnumValueDefinitionNode.php',
'GraphQL\\Language\\AST\\EnumValueNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/EnumValueNode.php',
'GraphQL\\Language\\AST\\FieldDefinitionNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/FieldDefinitionNode.php',
'GraphQL\\Language\\AST\\FieldNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/FieldNode.php',
'GraphQL\\Language\\AST\\FloatValueNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/FloatValueNode.php',
'GraphQL\\Language\\AST\\FragmentDefinitionNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/FragmentDefinitionNode.php',
'GraphQL\\Language\\AST\\FragmentSpreadNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/FragmentSpreadNode.php',
'GraphQL\\Language\\AST\\HasSelectionSet' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/HasSelectionSet.php',
'GraphQL\\Language\\AST\\InlineFragmentNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/InlineFragmentNode.php',
'GraphQL\\Language\\AST\\InputObjectTypeDefinitionNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/InputObjectTypeDefinitionNode.php',
'GraphQL\\Language\\AST\\InputValueDefinitionNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/InputValueDefinitionNode.php',
'GraphQL\\Language\\AST\\IntValueNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/IntValueNode.php',
'GraphQL\\Language\\AST\\InterfaceTypeDefinitionNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/InterfaceTypeDefinitionNode.php',
'GraphQL\\Language\\AST\\ListTypeNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/ListTypeNode.php',
'GraphQL\\Language\\AST\\ListValueNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/ListValueNode.php',
'GraphQL\\Language\\AST\\Location' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/Location.php',
'GraphQL\\Language\\AST\\NameNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/NameNode.php',
'GraphQL\\Language\\AST\\NamedTypeNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/NamedTypeNode.php',
'GraphQL\\Language\\AST\\Node' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/Node.php',
'GraphQL\\Language\\AST\\NodeKind' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/NodeKind.php',
'GraphQL\\Language\\AST\\NodeList' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/NodeList.php',
'GraphQL\\Language\\AST\\NonNullTypeNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/NonNullTypeNode.php',
'GraphQL\\Language\\AST\\NullValueNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/NullValueNode.php',
'GraphQL\\Language\\AST\\ObjectFieldNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/ObjectFieldNode.php',
'GraphQL\\Language\\AST\\ObjectTypeDefinitionNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/ObjectTypeDefinitionNode.php',
'GraphQL\\Language\\AST\\ObjectValueNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/ObjectValueNode.php',
'GraphQL\\Language\\AST\\OperationDefinitionNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/OperationDefinitionNode.php',
'GraphQL\\Language\\AST\\OperationTypeDefinitionNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/OperationTypeDefinitionNode.php',
'GraphQL\\Language\\AST\\ScalarTypeDefinitionNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/ScalarTypeDefinitionNode.php',
'GraphQL\\Language\\AST\\SchemaDefinitionNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/SchemaDefinitionNode.php',
'GraphQL\\Language\\AST\\SelectionNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/SelectionNode.php',
'GraphQL\\Language\\AST\\SelectionSetNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/SelectionSetNode.php',
'GraphQL\\Language\\AST\\StringValueNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/StringValueNode.php',
'GraphQL\\Language\\AST\\TypeDefinitionNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/TypeDefinitionNode.php',
'GraphQL\\Language\\AST\\TypeExtensionDefinitionNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/TypeExtensionDefinitionNode.php',
'GraphQL\\Language\\AST\\TypeNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/TypeNode.php',
'GraphQL\\Language\\AST\\TypeSystemDefinitionNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/TypeSystemDefinitionNode.php',
'GraphQL\\Language\\AST\\UnionTypeDefinitionNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/UnionTypeDefinitionNode.php',
'GraphQL\\Language\\AST\\ValueNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/ValueNode.php',
'GraphQL\\Language\\AST\\VariableDefinitionNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/VariableDefinitionNode.php',
'GraphQL\\Language\\AST\\VariableNode' => $vendorDir . '/webonyx/graphql-php/src/Language/AST/VariableNode.php',
'GraphQL\\Language\\Lexer' => $vendorDir . '/webonyx/graphql-php/src/Language/Lexer.php',
'GraphQL\\Language\\Parser' => $vendorDir . '/webonyx/graphql-php/src/Language/Parser.php',
'GraphQL\\Language\\Printer' => $vendorDir . '/webonyx/graphql-php/src/Language/Printer.php',
'GraphQL\\Language\\Source' => $vendorDir . '/webonyx/graphql-php/src/Language/Source.php',
'GraphQL\\Language\\SourceLocation' => $vendorDir . '/webonyx/graphql-php/src/Language/SourceLocation.php',
'GraphQL\\Language\\Token' => $vendorDir . '/webonyx/graphql-php/src/Language/Token.php',
'GraphQL\\Language\\Visitor' => $vendorDir . '/webonyx/graphql-php/src/Language/Visitor.php',
'GraphQL\\Language\\VisitorOperation' => $vendorDir . '/webonyx/graphql-php/src/Language/Visitor.php',
'GraphQL\\Schema' => $vendorDir . '/webonyx/graphql-php/src/Schema.php',
'GraphQL\\Server' => $vendorDir . '/webonyx/graphql-php/src/Server.php',
'GraphQL\\Server\\Helper' => $vendorDir . '/webonyx/graphql-php/src/Server/Helper.php',
'GraphQL\\Server\\OperationParams' => $vendorDir . '/webonyx/graphql-php/src/Server/OperationParams.php',
'GraphQL\\Server\\RequestError' => $vendorDir . '/webonyx/graphql-php/src/Server/RequestError.php',
'GraphQL\\Server\\ServerConfig' => $vendorDir . '/webonyx/graphql-php/src/Server/ServerConfig.php',
'GraphQL\\Server\\StandardServer' => $vendorDir . '/webonyx/graphql-php/src/Server/StandardServer.php',
'GraphQL\\Type\\Definition\\AbstractType' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/AbstractType.php',
'GraphQL\\Type\\Definition\\BooleanType' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/BooleanType.php',
'GraphQL\\Type\\Definition\\CompositeType' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/CompositeType.php',
'GraphQL\\Type\\Definition\\Config' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/Config.php',
'GraphQL\\Type\\Definition\\CustomScalarType' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/CustomScalarType.php',
'GraphQL\\Type\\Definition\\Directive' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/Directive.php',
'GraphQL\\Type\\Definition\\DirectiveLocation' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/DirectiveLocation.php',
'GraphQL\\Type\\Definition\\EnumType' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/EnumType.php',
'GraphQL\\Type\\Definition\\EnumValueDefinition' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/EnumValueDefinition.php',
'GraphQL\\Type\\Definition\\FieldArgument' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/FieldArgument.php',
'GraphQL\\Type\\Definition\\FieldDefinition' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/FieldDefinition.php',
'GraphQL\\Type\\Definition\\FloatType' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/FloatType.php',
'GraphQL\\Type\\Definition\\IDType' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/IDType.php',
'GraphQL\\Type\\Definition\\InputObjectField' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/InputObjectField.php',
'GraphQL\\Type\\Definition\\InputObjectType' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/InputObjectType.php',
'GraphQL\\Type\\Definition\\InputType' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/InputType.php',
'GraphQL\\Type\\Definition\\IntType' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/IntType.php',
'GraphQL\\Type\\Definition\\InterfaceType' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/InterfaceType.php',
'GraphQL\\Type\\Definition\\LeafType' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/LeafType.php',
'GraphQL\\Type\\Definition\\ListOfType' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/ListOfType.php',
'GraphQL\\Type\\Definition\\NonNull' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/NonNull.php',
'GraphQL\\Type\\Definition\\ObjectType' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/ObjectType.php',
'GraphQL\\Type\\Definition\\OutputType' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/OutputType.php',
'GraphQL\\Type\\Definition\\ResolveInfo' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/ResolveInfo.php',
'GraphQL\\Type\\Definition\\ScalarType' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/ScalarType.php',
'GraphQL\\Type\\Definition\\StringType' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/StringType.php',
'GraphQL\\Type\\Definition\\Type' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/Type.php',
'GraphQL\\Type\\Definition\\UnionType' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/UnionType.php',
'GraphQL\\Type\\Definition\\UnmodifiedType' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/UnmodifiedType.php',
'GraphQL\\Type\\Definition\\WrappingType' => $vendorDir . '/webonyx/graphql-php/src/Type/Definition/WrappingType.php',
'GraphQL\\Type\\EagerResolution' => $vendorDir . '/webonyx/graphql-php/src/Type/EagerResolution.php',
'GraphQL\\Type\\Introspection' => $vendorDir . '/webonyx/graphql-php/src/Type/Introspection.php',
'GraphQL\\Type\\LazyResolution' => $vendorDir . '/webonyx/graphql-php/src/Type/LazyResolution.php',
'GraphQL\\Type\\Resolution' => $vendorDir . '/webonyx/graphql-php/src/Type/Resolution.php',
'GraphQL\\Type\\Schema' => $vendorDir . '/webonyx/graphql-php/src/Type/Schema.php',
'GraphQL\\Type\\SchemaConfig' => $vendorDir . '/webonyx/graphql-php/src/Type/SchemaConfig.php',
'GraphQL\\Type\\TypeKind' => $vendorDir . '/webonyx/graphql-php/src/Type/Introspection.php',
'GraphQL\\Utils' => $vendorDir . '/webonyx/graphql-php/src/Utils.php',
'GraphQL\\Utils\\AST' => $vendorDir . '/webonyx/graphql-php/src/Utils/AST.php',
'GraphQL\\Utils\\BuildSchema' => $vendorDir . '/webonyx/graphql-php/src/Utils/BuildSchema.php',
'GraphQL\\Utils\\FindBreakingChanges' => $vendorDir . '/webonyx/graphql-php/src/Utils/FindBreakingChanges.php',
'GraphQL\\Utils\\MixedStore' => $vendorDir . '/webonyx/graphql-php/src/Utils/MixedStore.php',
'GraphQL\\Utils\\PairSet' => $vendorDir . '/webonyx/graphql-php/src/Utils/PairSet.php',
'GraphQL\\Utils\\SchemaPrinter' => $vendorDir . '/webonyx/graphql-php/src/Utils/SchemaPrinter.php',
'GraphQL\\Utils\\TypeComparators' => $vendorDir . '/webonyx/graphql-php/src/Utils/TypeComparators.php',
'GraphQL\\Utils\\TypeInfo' => $vendorDir . '/webonyx/graphql-php/src/Utils/TypeInfo.php',
'GraphQL\\Utils\\Utils' => $vendorDir . '/webonyx/graphql-php/src/Utils/Utils.php',
'GraphQL\\Validator\\DocumentValidator' => $vendorDir . '/webonyx/graphql-php/src/Validator/DocumentValidator.php',
'GraphQL\\Validator\\Rules\\AbstractQuerySecurity' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/AbstractQuerySecurity.php',
'GraphQL\\Validator\\Rules\\AbstractValidationRule' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/AbstractValidationRule.php',
'GraphQL\\Validator\\Rules\\ArgumentsOfCorrectType' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/ArgumentsOfCorrectType.php',
'GraphQL\\Validator\\Rules\\CustomValidationRule' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/CustomValidationRule.php',
'GraphQL\\Validator\\Rules\\DefaultValuesOfCorrectType' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/DefaultValuesOfCorrectType.php',
'GraphQL\\Validator\\Rules\\DisableIntrospection' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/DisableIntrospection.php',
'GraphQL\\Validator\\Rules\\FieldsOnCorrectType' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/FieldsOnCorrectType.php',
'GraphQL\\Validator\\Rules\\FragmentsOnCompositeTypes' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/FragmentsOnCompositeTypes.php',
'GraphQL\\Validator\\Rules\\KnownArgumentNames' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/KnownArgumentNames.php',
'GraphQL\\Validator\\Rules\\KnownDirectives' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/KnownDirectives.php',
'GraphQL\\Validator\\Rules\\KnownFragmentNames' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/KnownFragmentNames.php',
'GraphQL\\Validator\\Rules\\KnownTypeNames' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/KnownTypeNames.php',
'GraphQL\\Validator\\Rules\\LoneAnonymousOperation' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/LoneAnonymousOperation.php',
'GraphQL\\Validator\\Rules\\NoFragmentCycles' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/NoFragmentCycles.php',
'GraphQL\\Validator\\Rules\\NoUndefinedVariables' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/NoUndefinedVariables.php',
'GraphQL\\Validator\\Rules\\NoUnusedFragments' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/NoUnusedFragments.php',
'GraphQL\\Validator\\Rules\\NoUnusedVariables' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/NoUnusedVariables.php',
'GraphQL\\Validator\\Rules\\OverlappingFieldsCanBeMerged' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/OverlappingFieldsCanBeMerged.php',
'GraphQL\\Validator\\Rules\\PossibleFragmentSpreads' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/PossibleFragmentSpreads.php',
'GraphQL\\Validator\\Rules\\ProvidedNonNullArguments' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/ProvidedNonNullArguments.php',
'GraphQL\\Validator\\Rules\\QueryComplexity' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/QueryComplexity.php',
'GraphQL\\Validator\\Rules\\QueryDepth' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/QueryDepth.php',
'GraphQL\\Validator\\Rules\\ScalarLeafs' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/ScalarLeafs.php',
'GraphQL\\Validator\\Rules\\UniqueArgumentNames' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/UniqueArgumentNames.php',
'GraphQL\\Validator\\Rules\\UniqueDirectivesPerLocation' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/UniqueDirectivesPerLocation.php',
'GraphQL\\Validator\\Rules\\UniqueFragmentNames' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/UniqueFragmentNames.php',
'GraphQL\\Validator\\Rules\\UniqueInputFieldNames' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/UniqueInputFieldNames.php',
'GraphQL\\Validator\\Rules\\UniqueOperationNames' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/UniqueOperationNames.php',
'GraphQL\\Validator\\Rules\\UniqueVariableNames' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/UniqueVariableNames.php',
'GraphQL\\Validator\\Rules\\VariablesAreInputTypes' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/VariablesAreInputTypes.php',
'GraphQL\\Validator\\Rules\\VariablesInAllowedPosition' => $vendorDir . '/webonyx/graphql-php/src/Validator/Rules/VariablesInAllowedPosition.php',
'GraphQL\\Validator\\ValidationContext' => $vendorDir . '/webonyx/graphql-php/src/Validator/ValidationContext.php',
'WPGraphQL\\AppContext' => $baseDir . '/src/AppContext.php',
'WPGraphQL\\Data\\Config' => $baseDir . '/src/Data/Config.php',
'WPGraphQL\\Data\\ConnectionResolver' => $baseDir . '/src/Data/ConnectionResolver.php',
'WPGraphQL\\Data\\ConnectionResolverInterface' => $baseDir . '/src/Data/ConnectionResolverInterface.php',
'WPGraphQL\\Data\\DataSource' => $baseDir . '/src/Data/DataSource.php',
'WPGraphQL\\Data\\Loader' => $baseDir . '/src/Data/Loader.php',
'WPGraphQL\\Router' => $baseDir . '/src/Router.php',
'WPGraphQL\\Type\\Avatar\\AvatarType' => $baseDir . '/src/Type/Avatar/AvatarType.php',
'WPGraphQL\\Type\\CommentAuthor\\CommentAuthorType' => $baseDir . '/src/Type/CommentAuthor/CommentAuthorType.php',
'WPGraphQL\\Type\\Comment\\CommentQuery' => $baseDir . '/src/Type/Comment/CommentQuery.php',
'WPGraphQL\\Type\\Comment\\CommentType' => $baseDir . '/src/Type/Comment/CommentType.php',
'WPGraphQL\\Type\\Comment\\Connection\\CommentConnectionArgs' => $baseDir . '/src/Type/Comment/Connection/CommentConnectionArgs.php',
'WPGraphQL\\Type\\Comment\\Connection\\CommentConnectionDefinition' => $baseDir . '/src/Type/Comment/Connection/CommentConnectionDefinition.php',
'WPGraphQL\\Type\\Comment\\Connection\\CommentConnectionResolver' => $baseDir . '/src/Type/Comment/Connection/CommentConnectionResolver.php',
'WPGraphQL\\Type\\EditLock\\EditLockType' => $baseDir . '/src/Type/EditLock/EditLockType.php',
'WPGraphQL\\Type\\Enum\\MediaItemStatusEnumType' => $baseDir . '/src/Type/Enum/MediaItemStatusEnumType.php',
'WPGraphQL\\Type\\Enum\\MimeTypeEnumType' => $baseDir . '/src/Type/Enum/MimeTypeEnumType.php',
'WPGraphQL\\Type\\Enum\\PostObjectFieldFormatEnumType' => $baseDir . '/src/Type/Enum/PostObjectFieldFormatEnumType.php',
'WPGraphQL\\Type\\Enum\\PostStatusEnumType' => $baseDir . '/src/Type/Enum/PostStatusEnumType.php',
'WPGraphQL\\Type\\Enum\\PostTypeEnumType' => $baseDir . '/src/Type/Enum/PostTypeEnumType.php',
'WPGraphQL\\Type\\Enum\\RelationEnumType' => $baseDir . '/src/Type/Enum/RelationEnumType.php',
'WPGraphQL\\Type\\Enum\\TaxonomyEnumType' => $baseDir . '/src/Type/Enum/TaxonomyEnumType.php',
'WPGraphQL\\Type\\MediaItem\\MediaItemType' => $baseDir . '/src/Type/MediaItem/MediaItemType.php',
'WPGraphQL\\Type\\MediaItem\\Mutation\\MediaItemCreate' => $baseDir . '/src/Type/MediaItem/Mutation/MediaItemCreate.php',
'WPGraphQL\\Type\\MediaItem\\Mutation\\MediaItemDelete' => $baseDir . '/src/Type/MediaItem/Mutation/MediaItemDelete.php',
'WPGraphQL\\Type\\MediaItem\\Mutation\\MediaItemMutation' => $baseDir . '/src/Type/MediaItem/Mutation/MediaItemMutation.php',
'WPGraphQL\\Type\\MediaItem\\Mutation\\MediaItemUpdate' => $baseDir . '/src/Type/MediaItem/Mutation/MediaItemUpdate.php',
'WPGraphQL\\Type\\Plugin\\Connection\\PluginConnectionDefinition' => $baseDir . '/src/Type/Plugin/Connection/PluginConnectionDefinition.php',
'WPGraphQL\\Type\\Plugin\\Connection\\PluginConnectionResolver' => $baseDir . '/src/Type/Plugin/Connection/PluginConnectionResolver.php',
'WPGraphQL\\Type\\Plugin\\PluginQuery' => $baseDir . '/src/Type/Plugin/PluginQuery.php',
'WPGraphQL\\Type\\Plugin\\PluginType' => $baseDir . '/src/Type/Plugin/PluginType.php',
'WPGraphQL\\Type\\PostObject\\Connection\\PostObjectConnectionArgs' => $baseDir . '/src/Type/PostObject/Connection/PostObjectConnectionArgs.php',
'WPGraphQL\\Type\\PostObject\\Connection\\PostObjectConnectionArgsDateQuery' => $baseDir . '/src/Type/PostObject/Connection/PostObjectConnectionArgsDateQuery.php',
'WPGraphQL\\Type\\PostObject\\Connection\\PostObjectConnectionDefinition' => $baseDir . '/src/Type/PostObject/Connection/PostObjectConnectionDefinition.php',
'WPGraphQL\\Type\\PostObject\\Connection\\PostObjectConnectionResolver' => $baseDir . '/src/Type/PostObject/Connection/PostObjectConnectionResolver.php',
'WPGraphQL\\Type\\PostObject\\Mutation\\PostObjectCreate' => $baseDir . '/src/Type/PostObject/Mutation/PostObjectCreate.php',
'WPGraphQL\\Type\\PostObject\\Mutation\\PostObjectDelete' => $baseDir . '/src/Type/PostObject/Mutation/PostObjectDelete.php',
'WPGraphQL\\Type\\PostObject\\Mutation\\PostObjectMutation' => $baseDir . '/src/Type/PostObject/Mutation/PostObjectMutation.php',
'WPGraphQL\\Type\\PostObject\\Mutation\\PostObjectUpdate' => $baseDir . '/src/Type/PostObject/Mutation/PostObjectUpdate.php',
'WPGraphQL\\Type\\PostObject\\Mutation\\TermObjectDelete' => $baseDir . '/src/Type/TermObject/Mutation/TermObjectDelete.php',
'WPGraphQL\\Type\\PostObject\\PostObjectQuery' => $baseDir . '/src/Type/PostObject/PostObjectQuery.php',
'WPGraphQL\\Type\\PostObject\\PostObjectType' => $baseDir . '/src/Type/PostObject/PostObjectType.php',
'WPGraphQL\\Type\\PostType\\PostTypeType' => $baseDir . '/src/Type/PostType/PostTypeType.php',
'WPGraphQL\\Type\\RootMutationType' => $baseDir . '/src/Type/RootMutationType.php',
'WPGraphQL\\Type\\RootQueryType' => $baseDir . '/src/Type/RootQueryType.php',
'WPGraphQL\\Type\\Setting\\SettingQuery' => $baseDir . '/src/Type/Setting/SettingQuery.php',
'WPGraphQL\\Type\\Setting\\SettingType' => $baseDir . '/src/Type/Setting/SettingType.php',
'WPGraphQL\\Type\\Settings\\Mutation\\SettingsMutation' => $baseDir . '/src/Type/Settings/Mutation/SettingsMutation.php',
'WPGraphQL\\Type\\Settings\\Mutation\\SettingsUpdate' => $baseDir . '/src/Type/Settings/Mutation/SettingsUpdate.php',
'WPGraphQL\\Type\\Settings\\SettingsQuery' => $baseDir . '/src/Type/Settings/SettingsQuery.php',
'WPGraphQL\\Type\\Settings\\SettingsType' => $baseDir . '/src/Type/Settings/SettingsType.php',
'WPGraphQL\\Type\\Taxonomy\\TaxonomyType' => $baseDir . '/src/Type/Taxonomy/TaxonomyType.php',
'WPGraphQL\\Type\\TermObject\\Connection\\TermObjectConnectionArgs' => $baseDir . '/src/Type/TermObject/Connection/TermObjectConnectionArgs.php',
'WPGraphQL\\Type\\TermObject\\Connection\\TermObjectConnectionDefinition' => $baseDir . '/src/Type/TermObject/Connection/TermObjectConnectionDefinition.php',
'WPGraphQL\\Type\\TermObject\\Connection\\TermObjectConnectionResolver' => $baseDir . '/src/Type/TermObject/Connection/TermObjectConnectionResolver.php',
'WPGraphQL\\Type\\TermObject\\Mutation\\TermObjectCreate' => $baseDir . '/src/Type/TermObject/Mutation/TermObjectCreate.php',
'WPGraphQL\\Type\\TermObject\\Mutation\\TermObjectMutation' => $baseDir . '/src/Type/TermObject/Mutation/TermObjectMutation.php',
'WPGraphQL\\Type\\TermObject\\Mutation\\TermObjectUpdate' => $baseDir . '/src/Type/TermObject/Mutation/TermObjectUpdate.php',
'WPGraphQL\\Type\\TermObject\\TermObjectQuery' => $baseDir . '/src/Type/TermObject/TermObjectQuery.php',
'WPGraphQL\\Type\\TermObject\\TermObjectType' => $baseDir . '/src/Type/TermObject/TermObjectType.php',
'WPGraphQL\\Type\\Theme\\Connection\\ThemeConnectionDefinition' => $baseDir . '/src/Type/Theme/Connection/ThemeConnectionDefinition.php',
'WPGraphQL\\Type\\Theme\\Connection\\ThemeConnectionResolver' => $baseDir . '/src/Type/Theme/Connection/ThemeConnectionResolver.php',
'WPGraphQL\\Type\\Theme\\ThemeType' => $baseDir . '/src/Type/Theme/ThemeType.php',
'WPGraphQL\\Type\\Union\\CommentAuthorUnionType' => $baseDir . '/src/Type/Union/CommentAuthorUnionType.php',
'WPGraphQL\\Type\\Union\\PostObjectUnionType' => $baseDir . '/src/Type/Union/PostObjectUnionType.php',
'WPGraphQL\\Type\\Union\\TermObjectUnionType' => $baseDir . '/src/Type/Union/TermObjectUnionType.php',
'WPGraphQL\\Type\\User\\Connection\\UserConnectionArgs' => $baseDir . '/src/Type/User/Connection/UserConnectionArgs.php',
'WPGraphQL\\Type\\User\\Connection\\UserConnectionDefinition' => $baseDir . '/src/Type/User/Connection/UserConnectionDefinition.php',
'WPGraphQL\\Type\\User\\Connection\\UserConnectionResolver' => $baseDir . '/src/Type/User/Connection/UserConnectionResolver.php',
'WPGraphQL\\Type\\User\\Mutation\\UserCreate' => $baseDir . '/src/Type/User/Mutation/UserCreate.php',
'WPGraphQL\\Type\\User\\Mutation\\UserDelete' => $baseDir . '/src/Type/User/Mutation/UserDelete.php',
'WPGraphQL\\Type\\User\\Mutation\\UserMutation' => $baseDir . '/src/Type/User/Mutation/UserMutation.php',
'WPGraphQL\\Type\\User\\Mutation\\UserUpdate' => $baseDir . '/src/Type/User/Mutation/UserUpdate.php',
'WPGraphQL\\Type\\User\\UserQuery' => $baseDir . '/src/Type/User/UserQuery.php',
'WPGraphQL\\Type\\User\\UserType' => $baseDir . '/src/Type/User/UserType.php',
'WPGraphQL\\Type\\WPEnumType' => $baseDir . '/src/Type/WPEnumType.php',
'WPGraphQL\\Type\\WPInputObjectType' => $baseDir . '/src/Type/WPInputObjectType.php',
'WPGraphQL\\Type\\WPObjectType' => $baseDir . '/src/Type/WPObjectType.php',
'WPGraphQL\\Types' => $baseDir . '/src/Types.php',
'WPGraphQL\\Utils\\InstrumentSchema' => $baseDir . '/src/Utils/InstrumentSchema.php',
'WPGraphQL\\WPSchema' => $baseDir . '/src/WPSchema.php',
);

View File

@@ -0,0 +1,10 @@
<?php
// autoload_files.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'c594688b3441835d5575f3085da4a242' => $vendorDir . '/webonyx/graphql-php/src/deprecated.php',
);

View File

@@ -0,0 +1,9 @@
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
);

View File

@@ -0,0 +1,11 @@
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'WPGraphQL\\' => array($baseDir . '/src'),
'GraphQL\\' => array($vendorDir . '/webonyx/graphql-php/src'),
);

View File

@@ -0,0 +1,70 @@
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit989472a815f7398c1ff4d2e496f07f11
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInit989472a815f7398c1ff4d2e496f07f11', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInit989472a815f7398c1ff4d2e496f07f11', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require_once __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit989472a815f7398c1ff4d2e496f07f11::getInitializer($loader));
} else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
$loader->register(true);
if ($useStaticLoader) {
$includeFiles = Composer\Autoload\ComposerStaticInit989472a815f7398c1ff4d2e496f07f11::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire989472a815f7398c1ff4d2e496f07f11($fileIdentifier, $file);
}
return $loader;
}
}
function composerRequire989472a815f7398c1ff4d2e496f07f11($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
}
}

View File

@@ -0,0 +1,297 @@
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInit989472a815f7398c1ff4d2e496f07f11
{
public static $files = array (
'c594688b3441835d5575f3085da4a242' => __DIR__ . '/..' . '/webonyx/graphql-php/src/deprecated.php',
);
public static $prefixLengthsPsr4 = array (
'W' =>
array (
'WPGraphQL\\' => 10,
),
'G' =>
array (
'GraphQL\\' => 8,
),
);
public static $prefixDirsPsr4 = array (
'WPGraphQL\\' =>
array (
0 => __DIR__ . '/../..' . '/src',
),
'GraphQL\\' =>
array (
0 => __DIR__ . '/..' . '/webonyx/graphql-php/src',
),
);
public static $classMap = array (
'GraphQLRelay\\Connection\\ArrayConnection' => __DIR__ . '/..' . '/ivome/graphql-relay-php/src/Connection/ArrayConnection.php',
'GraphQLRelay\\Connection\\Connection' => __DIR__ . '/..' . '/ivome/graphql-relay-php/src/Connection/Connection.php',
'GraphQLRelay\\Mutation\\Mutation' => __DIR__ . '/..' . '/ivome/graphql-relay-php/src/Mutation/Mutation.php',
'GraphQLRelay\\Node\\Node' => __DIR__ . '/..' . '/ivome/graphql-relay-php/src/Node/Node.php',
'GraphQLRelay\\Node\\Plural' => __DIR__ . '/..' . '/ivome/graphql-relay-php/src/Node/Plural.php',
'GraphQLRelay\\Relay' => __DIR__ . '/..' . '/ivome/graphql-relay-php/src/Relay.php',
'GraphQL\\Deferred' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Deferred.php',
'GraphQL\\Error' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Error.php',
'GraphQL\\Error\\ClientAware' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Error/ClientAware.php',
'GraphQL\\Error\\Debug' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Error/Debug.php',
'GraphQL\\Error\\Error' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Error/Error.php',
'GraphQL\\Error\\FormattedError' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Error/FormattedError.php',
'GraphQL\\Error\\InvariantViolation' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Error/InvariantViolation.php',
'GraphQL\\Error\\SyntaxError' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Error/SyntaxError.php',
'GraphQL\\Error\\UserError' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Error/UserError.php',
'GraphQL\\Error\\Warning' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Error/Warning.php',
'GraphQL\\Executor\\ExecutionContext' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Executor/ExecutionContext.php',
'GraphQL\\Executor\\ExecutionResult' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Executor/ExecutionResult.php',
'GraphQL\\Executor\\Executor' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Executor/Executor.php',
'GraphQL\\Executor\\Promise\\Adapter\\ReactPromiseAdapter' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Executor/Promise/Adapter/ReactPromiseAdapter.php',
'GraphQL\\Executor\\Promise\\Adapter\\SyncPromise' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Executor/Promise/Adapter/SyncPromise.php',
'GraphQL\\Executor\\Promise\\Adapter\\SyncPromiseAdapter' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Executor/Promise/Adapter/SyncPromiseAdapter.php',
'GraphQL\\Executor\\Promise\\Promise' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Executor/Promise/Promise.php',
'GraphQL\\Executor\\Promise\\PromiseAdapter' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Executor/Promise/PromiseAdapter.php',
'GraphQL\\Executor\\Values' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Executor/Values.php',
'GraphQL\\GraphQL' => __DIR__ . '/..' . '/webonyx/graphql-php/src/GraphQL.php',
'GraphQL\\Language\\AST\\ArgumentNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/ArgumentNode.php',
'GraphQL\\Language\\AST\\BooleanValueNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/BooleanValueNode.php',
'GraphQL\\Language\\AST\\DefinitionNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/DefinitionNode.php',
'GraphQL\\Language\\AST\\DirectiveDefinitionNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/DirectiveDefinitionNode.php',
'GraphQL\\Language\\AST\\DirectiveNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/DirectiveNode.php',
'GraphQL\\Language\\AST\\DocumentNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/DocumentNode.php',
'GraphQL\\Language\\AST\\EnumTypeDefinitionNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/EnumTypeDefinitionNode.php',
'GraphQL\\Language\\AST\\EnumValueDefinitionNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/EnumValueDefinitionNode.php',
'GraphQL\\Language\\AST\\EnumValueNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/EnumValueNode.php',
'GraphQL\\Language\\AST\\FieldDefinitionNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/FieldDefinitionNode.php',
'GraphQL\\Language\\AST\\FieldNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/FieldNode.php',
'GraphQL\\Language\\AST\\FloatValueNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/FloatValueNode.php',
'GraphQL\\Language\\AST\\FragmentDefinitionNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/FragmentDefinitionNode.php',
'GraphQL\\Language\\AST\\FragmentSpreadNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/FragmentSpreadNode.php',
'GraphQL\\Language\\AST\\HasSelectionSet' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/HasSelectionSet.php',
'GraphQL\\Language\\AST\\InlineFragmentNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/InlineFragmentNode.php',
'GraphQL\\Language\\AST\\InputObjectTypeDefinitionNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/InputObjectTypeDefinitionNode.php',
'GraphQL\\Language\\AST\\InputValueDefinitionNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/InputValueDefinitionNode.php',
'GraphQL\\Language\\AST\\IntValueNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/IntValueNode.php',
'GraphQL\\Language\\AST\\InterfaceTypeDefinitionNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/InterfaceTypeDefinitionNode.php',
'GraphQL\\Language\\AST\\ListTypeNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/ListTypeNode.php',
'GraphQL\\Language\\AST\\ListValueNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/ListValueNode.php',
'GraphQL\\Language\\AST\\Location' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/Location.php',
'GraphQL\\Language\\AST\\NameNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/NameNode.php',
'GraphQL\\Language\\AST\\NamedTypeNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/NamedTypeNode.php',
'GraphQL\\Language\\AST\\Node' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/Node.php',
'GraphQL\\Language\\AST\\NodeKind' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/NodeKind.php',
'GraphQL\\Language\\AST\\NodeList' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/NodeList.php',
'GraphQL\\Language\\AST\\NonNullTypeNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/NonNullTypeNode.php',
'GraphQL\\Language\\AST\\NullValueNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/NullValueNode.php',
'GraphQL\\Language\\AST\\ObjectFieldNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/ObjectFieldNode.php',
'GraphQL\\Language\\AST\\ObjectTypeDefinitionNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/ObjectTypeDefinitionNode.php',
'GraphQL\\Language\\AST\\ObjectValueNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/ObjectValueNode.php',
'GraphQL\\Language\\AST\\OperationDefinitionNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/OperationDefinitionNode.php',
'GraphQL\\Language\\AST\\OperationTypeDefinitionNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/OperationTypeDefinitionNode.php',
'GraphQL\\Language\\AST\\ScalarTypeDefinitionNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/ScalarTypeDefinitionNode.php',
'GraphQL\\Language\\AST\\SchemaDefinitionNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/SchemaDefinitionNode.php',
'GraphQL\\Language\\AST\\SelectionNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/SelectionNode.php',
'GraphQL\\Language\\AST\\SelectionSetNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/SelectionSetNode.php',
'GraphQL\\Language\\AST\\StringValueNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/StringValueNode.php',
'GraphQL\\Language\\AST\\TypeDefinitionNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/TypeDefinitionNode.php',
'GraphQL\\Language\\AST\\TypeExtensionDefinitionNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/TypeExtensionDefinitionNode.php',
'GraphQL\\Language\\AST\\TypeNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/TypeNode.php',
'GraphQL\\Language\\AST\\TypeSystemDefinitionNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/TypeSystemDefinitionNode.php',
'GraphQL\\Language\\AST\\UnionTypeDefinitionNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/UnionTypeDefinitionNode.php',
'GraphQL\\Language\\AST\\ValueNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/ValueNode.php',
'GraphQL\\Language\\AST\\VariableDefinitionNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/VariableDefinitionNode.php',
'GraphQL\\Language\\AST\\VariableNode' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/AST/VariableNode.php',
'GraphQL\\Language\\Lexer' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/Lexer.php',
'GraphQL\\Language\\Parser' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/Parser.php',
'GraphQL\\Language\\Printer' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/Printer.php',
'GraphQL\\Language\\Source' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/Source.php',
'GraphQL\\Language\\SourceLocation' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/SourceLocation.php',
'GraphQL\\Language\\Token' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/Token.php',
'GraphQL\\Language\\Visitor' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/Visitor.php',
'GraphQL\\Language\\VisitorOperation' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Language/Visitor.php',
'GraphQL\\Schema' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Schema.php',
'GraphQL\\Server' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Server.php',
'GraphQL\\Server\\Helper' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Server/Helper.php',
'GraphQL\\Server\\OperationParams' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Server/OperationParams.php',
'GraphQL\\Server\\RequestError' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Server/RequestError.php',
'GraphQL\\Server\\ServerConfig' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Server/ServerConfig.php',
'GraphQL\\Server\\StandardServer' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Server/StandardServer.php',
'GraphQL\\Type\\Definition\\AbstractType' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/AbstractType.php',
'GraphQL\\Type\\Definition\\BooleanType' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/BooleanType.php',
'GraphQL\\Type\\Definition\\CompositeType' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/CompositeType.php',
'GraphQL\\Type\\Definition\\Config' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/Config.php',
'GraphQL\\Type\\Definition\\CustomScalarType' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/CustomScalarType.php',
'GraphQL\\Type\\Definition\\Directive' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/Directive.php',
'GraphQL\\Type\\Definition\\DirectiveLocation' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/DirectiveLocation.php',
'GraphQL\\Type\\Definition\\EnumType' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/EnumType.php',
'GraphQL\\Type\\Definition\\EnumValueDefinition' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/EnumValueDefinition.php',
'GraphQL\\Type\\Definition\\FieldArgument' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/FieldArgument.php',
'GraphQL\\Type\\Definition\\FieldDefinition' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/FieldDefinition.php',
'GraphQL\\Type\\Definition\\FloatType' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/FloatType.php',
'GraphQL\\Type\\Definition\\IDType' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/IDType.php',
'GraphQL\\Type\\Definition\\InputObjectField' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/InputObjectField.php',
'GraphQL\\Type\\Definition\\InputObjectType' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/InputObjectType.php',
'GraphQL\\Type\\Definition\\InputType' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/InputType.php',
'GraphQL\\Type\\Definition\\IntType' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/IntType.php',
'GraphQL\\Type\\Definition\\InterfaceType' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/InterfaceType.php',
'GraphQL\\Type\\Definition\\LeafType' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/LeafType.php',
'GraphQL\\Type\\Definition\\ListOfType' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/ListOfType.php',
'GraphQL\\Type\\Definition\\NonNull' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/NonNull.php',
'GraphQL\\Type\\Definition\\ObjectType' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/ObjectType.php',
'GraphQL\\Type\\Definition\\OutputType' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/OutputType.php',
'GraphQL\\Type\\Definition\\ResolveInfo' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/ResolveInfo.php',
'GraphQL\\Type\\Definition\\ScalarType' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/ScalarType.php',
'GraphQL\\Type\\Definition\\StringType' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/StringType.php',
'GraphQL\\Type\\Definition\\Type' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/Type.php',
'GraphQL\\Type\\Definition\\UnionType' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/UnionType.php',
'GraphQL\\Type\\Definition\\UnmodifiedType' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/UnmodifiedType.php',
'GraphQL\\Type\\Definition\\WrappingType' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Definition/WrappingType.php',
'GraphQL\\Type\\EagerResolution' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/EagerResolution.php',
'GraphQL\\Type\\Introspection' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Introspection.php',
'GraphQL\\Type\\LazyResolution' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/LazyResolution.php',
'GraphQL\\Type\\Resolution' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Resolution.php',
'GraphQL\\Type\\Schema' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Schema.php',
'GraphQL\\Type\\SchemaConfig' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/SchemaConfig.php',
'GraphQL\\Type\\TypeKind' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Type/Introspection.php',
'GraphQL\\Utils' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Utils.php',
'GraphQL\\Utils\\AST' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Utils/AST.php',
'GraphQL\\Utils\\BuildSchema' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Utils/BuildSchema.php',
'GraphQL\\Utils\\FindBreakingChanges' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Utils/FindBreakingChanges.php',
'GraphQL\\Utils\\MixedStore' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Utils/MixedStore.php',
'GraphQL\\Utils\\PairSet' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Utils/PairSet.php',
'GraphQL\\Utils\\SchemaPrinter' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Utils/SchemaPrinter.php',
'GraphQL\\Utils\\TypeComparators' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Utils/TypeComparators.php',
'GraphQL\\Utils\\TypeInfo' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Utils/TypeInfo.php',
'GraphQL\\Utils\\Utils' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Utils/Utils.php',
'GraphQL\\Validator\\DocumentValidator' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/DocumentValidator.php',
'GraphQL\\Validator\\Rules\\AbstractQuerySecurity' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/AbstractQuerySecurity.php',
'GraphQL\\Validator\\Rules\\AbstractValidationRule' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/AbstractValidationRule.php',
'GraphQL\\Validator\\Rules\\ArgumentsOfCorrectType' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/ArgumentsOfCorrectType.php',
'GraphQL\\Validator\\Rules\\CustomValidationRule' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/CustomValidationRule.php',
'GraphQL\\Validator\\Rules\\DefaultValuesOfCorrectType' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/DefaultValuesOfCorrectType.php',
'GraphQL\\Validator\\Rules\\DisableIntrospection' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/DisableIntrospection.php',
'GraphQL\\Validator\\Rules\\FieldsOnCorrectType' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/FieldsOnCorrectType.php',
'GraphQL\\Validator\\Rules\\FragmentsOnCompositeTypes' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/FragmentsOnCompositeTypes.php',
'GraphQL\\Validator\\Rules\\KnownArgumentNames' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/KnownArgumentNames.php',
'GraphQL\\Validator\\Rules\\KnownDirectives' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/KnownDirectives.php',
'GraphQL\\Validator\\Rules\\KnownFragmentNames' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/KnownFragmentNames.php',
'GraphQL\\Validator\\Rules\\KnownTypeNames' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/KnownTypeNames.php',
'GraphQL\\Validator\\Rules\\LoneAnonymousOperation' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/LoneAnonymousOperation.php',
'GraphQL\\Validator\\Rules\\NoFragmentCycles' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/NoFragmentCycles.php',
'GraphQL\\Validator\\Rules\\NoUndefinedVariables' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/NoUndefinedVariables.php',
'GraphQL\\Validator\\Rules\\NoUnusedFragments' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/NoUnusedFragments.php',
'GraphQL\\Validator\\Rules\\NoUnusedVariables' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/NoUnusedVariables.php',
'GraphQL\\Validator\\Rules\\OverlappingFieldsCanBeMerged' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/OverlappingFieldsCanBeMerged.php',
'GraphQL\\Validator\\Rules\\PossibleFragmentSpreads' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/PossibleFragmentSpreads.php',
'GraphQL\\Validator\\Rules\\ProvidedNonNullArguments' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/ProvidedNonNullArguments.php',
'GraphQL\\Validator\\Rules\\QueryComplexity' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/QueryComplexity.php',
'GraphQL\\Validator\\Rules\\QueryDepth' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/QueryDepth.php',
'GraphQL\\Validator\\Rules\\ScalarLeafs' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/ScalarLeafs.php',
'GraphQL\\Validator\\Rules\\UniqueArgumentNames' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/UniqueArgumentNames.php',
'GraphQL\\Validator\\Rules\\UniqueDirectivesPerLocation' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/UniqueDirectivesPerLocation.php',
'GraphQL\\Validator\\Rules\\UniqueFragmentNames' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/UniqueFragmentNames.php',
'GraphQL\\Validator\\Rules\\UniqueInputFieldNames' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/UniqueInputFieldNames.php',
'GraphQL\\Validator\\Rules\\UniqueOperationNames' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/UniqueOperationNames.php',
'GraphQL\\Validator\\Rules\\UniqueVariableNames' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/UniqueVariableNames.php',
'GraphQL\\Validator\\Rules\\VariablesAreInputTypes' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/VariablesAreInputTypes.php',
'GraphQL\\Validator\\Rules\\VariablesInAllowedPosition' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/Rules/VariablesInAllowedPosition.php',
'GraphQL\\Validator\\ValidationContext' => __DIR__ . '/..' . '/webonyx/graphql-php/src/Validator/ValidationContext.php',
'WPGraphQL\\AppContext' => __DIR__ . '/../..' . '/src/AppContext.php',
'WPGraphQL\\Data\\Config' => __DIR__ . '/../..' . '/src/Data/Config.php',
'WPGraphQL\\Data\\ConnectionResolver' => __DIR__ . '/../..' . '/src/Data/ConnectionResolver.php',
'WPGraphQL\\Data\\ConnectionResolverInterface' => __DIR__ . '/../..' . '/src/Data/ConnectionResolverInterface.php',
'WPGraphQL\\Data\\DataSource' => __DIR__ . '/../..' . '/src/Data/DataSource.php',
'WPGraphQL\\Data\\Loader' => __DIR__ . '/../..' . '/src/Data/Loader.php',
'WPGraphQL\\Router' => __DIR__ . '/../..' . '/src/Router.php',
'WPGraphQL\\Type\\Avatar\\AvatarType' => __DIR__ . '/../..' . '/src/Type/Avatar/AvatarType.php',
'WPGraphQL\\Type\\CommentAuthor\\CommentAuthorType' => __DIR__ . '/../..' . '/src/Type/CommentAuthor/CommentAuthorType.php',
'WPGraphQL\\Type\\Comment\\CommentQuery' => __DIR__ . '/../..' . '/src/Type/Comment/CommentQuery.php',
'WPGraphQL\\Type\\Comment\\CommentType' => __DIR__ . '/../..' . '/src/Type/Comment/CommentType.php',
'WPGraphQL\\Type\\Comment\\Connection\\CommentConnectionArgs' => __DIR__ . '/../..' . '/src/Type/Comment/Connection/CommentConnectionArgs.php',
'WPGraphQL\\Type\\Comment\\Connection\\CommentConnectionDefinition' => __DIR__ . '/../..' . '/src/Type/Comment/Connection/CommentConnectionDefinition.php',
'WPGraphQL\\Type\\Comment\\Connection\\CommentConnectionResolver' => __DIR__ . '/../..' . '/src/Type/Comment/Connection/CommentConnectionResolver.php',
'WPGraphQL\\Type\\EditLock\\EditLockType' => __DIR__ . '/../..' . '/src/Type/EditLock/EditLockType.php',
'WPGraphQL\\Type\\Enum\\MediaItemStatusEnumType' => __DIR__ . '/../..' . '/src/Type/Enum/MediaItemStatusEnumType.php',
'WPGraphQL\\Type\\Enum\\MimeTypeEnumType' => __DIR__ . '/../..' . '/src/Type/Enum/MimeTypeEnumType.php',
'WPGraphQL\\Type\\Enum\\PostObjectFieldFormatEnumType' => __DIR__ . '/../..' . '/src/Type/Enum/PostObjectFieldFormatEnumType.php',
'WPGraphQL\\Type\\Enum\\PostStatusEnumType' => __DIR__ . '/../..' . '/src/Type/Enum/PostStatusEnumType.php',
'WPGraphQL\\Type\\Enum\\PostTypeEnumType' => __DIR__ . '/../..' . '/src/Type/Enum/PostTypeEnumType.php',
'WPGraphQL\\Type\\Enum\\RelationEnumType' => __DIR__ . '/../..' . '/src/Type/Enum/RelationEnumType.php',
'WPGraphQL\\Type\\Enum\\TaxonomyEnumType' => __DIR__ . '/../..' . '/src/Type/Enum/TaxonomyEnumType.php',
'WPGraphQL\\Type\\MediaItem\\MediaItemType' => __DIR__ . '/../..' . '/src/Type/MediaItem/MediaItemType.php',
'WPGraphQL\\Type\\MediaItem\\Mutation\\MediaItemCreate' => __DIR__ . '/../..' . '/src/Type/MediaItem/Mutation/MediaItemCreate.php',
'WPGraphQL\\Type\\MediaItem\\Mutation\\MediaItemDelete' => __DIR__ . '/../..' . '/src/Type/MediaItem/Mutation/MediaItemDelete.php',
'WPGraphQL\\Type\\MediaItem\\Mutation\\MediaItemMutation' => __DIR__ . '/../..' . '/src/Type/MediaItem/Mutation/MediaItemMutation.php',
'WPGraphQL\\Type\\MediaItem\\Mutation\\MediaItemUpdate' => __DIR__ . '/../..' . '/src/Type/MediaItem/Mutation/MediaItemUpdate.php',
'WPGraphQL\\Type\\Plugin\\Connection\\PluginConnectionDefinition' => __DIR__ . '/../..' . '/src/Type/Plugin/Connection/PluginConnectionDefinition.php',
'WPGraphQL\\Type\\Plugin\\Connection\\PluginConnectionResolver' => __DIR__ . '/../..' . '/src/Type/Plugin/Connection/PluginConnectionResolver.php',
'WPGraphQL\\Type\\Plugin\\PluginQuery' => __DIR__ . '/../..' . '/src/Type/Plugin/PluginQuery.php',
'WPGraphQL\\Type\\Plugin\\PluginType' => __DIR__ . '/../..' . '/src/Type/Plugin/PluginType.php',
'WPGraphQL\\Type\\PostObject\\Connection\\PostObjectConnectionArgs' => __DIR__ . '/../..' . '/src/Type/PostObject/Connection/PostObjectConnectionArgs.php',
'WPGraphQL\\Type\\PostObject\\Connection\\PostObjectConnectionArgsDateQuery' => __DIR__ . '/../..' . '/src/Type/PostObject/Connection/PostObjectConnectionArgsDateQuery.php',
'WPGraphQL\\Type\\PostObject\\Connection\\PostObjectConnectionDefinition' => __DIR__ . '/../..' . '/src/Type/PostObject/Connection/PostObjectConnectionDefinition.php',
'WPGraphQL\\Type\\PostObject\\Connection\\PostObjectConnectionResolver' => __DIR__ . '/../..' . '/src/Type/PostObject/Connection/PostObjectConnectionResolver.php',
'WPGraphQL\\Type\\PostObject\\Mutation\\PostObjectCreate' => __DIR__ . '/../..' . '/src/Type/PostObject/Mutation/PostObjectCreate.php',
'WPGraphQL\\Type\\PostObject\\Mutation\\PostObjectDelete' => __DIR__ . '/../..' . '/src/Type/PostObject/Mutation/PostObjectDelete.php',
'WPGraphQL\\Type\\PostObject\\Mutation\\PostObjectMutation' => __DIR__ . '/../..' . '/src/Type/PostObject/Mutation/PostObjectMutation.php',
'WPGraphQL\\Type\\PostObject\\Mutation\\PostObjectUpdate' => __DIR__ . '/../..' . '/src/Type/PostObject/Mutation/PostObjectUpdate.php',
'WPGraphQL\\Type\\PostObject\\Mutation\\TermObjectDelete' => __DIR__ . '/../..' . '/src/Type/TermObject/Mutation/TermObjectDelete.php',
'WPGraphQL\\Type\\PostObject\\PostObjectQuery' => __DIR__ . '/../..' . '/src/Type/PostObject/PostObjectQuery.php',
'WPGraphQL\\Type\\PostObject\\PostObjectType' => __DIR__ . '/../..' . '/src/Type/PostObject/PostObjectType.php',
'WPGraphQL\\Type\\PostType\\PostTypeType' => __DIR__ . '/../..' . '/src/Type/PostType/PostTypeType.php',
'WPGraphQL\\Type\\RootMutationType' => __DIR__ . '/../..' . '/src/Type/RootMutationType.php',
'WPGraphQL\\Type\\RootQueryType' => __DIR__ . '/../..' . '/src/Type/RootQueryType.php',
'WPGraphQL\\Type\\Setting\\SettingQuery' => __DIR__ . '/../..' . '/src/Type/Setting/SettingQuery.php',
'WPGraphQL\\Type\\Setting\\SettingType' => __DIR__ . '/../..' . '/src/Type/Setting/SettingType.php',
'WPGraphQL\\Type\\Settings\\Mutation\\SettingsMutation' => __DIR__ . '/../..' . '/src/Type/Settings/Mutation/SettingsMutation.php',
'WPGraphQL\\Type\\Settings\\Mutation\\SettingsUpdate' => __DIR__ . '/../..' . '/src/Type/Settings/Mutation/SettingsUpdate.php',
'WPGraphQL\\Type\\Settings\\SettingsQuery' => __DIR__ . '/../..' . '/src/Type/Settings/SettingsQuery.php',
'WPGraphQL\\Type\\Settings\\SettingsType' => __DIR__ . '/../..' . '/src/Type/Settings/SettingsType.php',
'WPGraphQL\\Type\\Taxonomy\\TaxonomyType' => __DIR__ . '/../..' . '/src/Type/Taxonomy/TaxonomyType.php',
'WPGraphQL\\Type\\TermObject\\Connection\\TermObjectConnectionArgs' => __DIR__ . '/../..' . '/src/Type/TermObject/Connection/TermObjectConnectionArgs.php',
'WPGraphQL\\Type\\TermObject\\Connection\\TermObjectConnectionDefinition' => __DIR__ . '/../..' . '/src/Type/TermObject/Connection/TermObjectConnectionDefinition.php',
'WPGraphQL\\Type\\TermObject\\Connection\\TermObjectConnectionResolver' => __DIR__ . '/../..' . '/src/Type/TermObject/Connection/TermObjectConnectionResolver.php',
'WPGraphQL\\Type\\TermObject\\Mutation\\TermObjectCreate' => __DIR__ . '/../..' . '/src/Type/TermObject/Mutation/TermObjectCreate.php',
'WPGraphQL\\Type\\TermObject\\Mutation\\TermObjectMutation' => __DIR__ . '/../..' . '/src/Type/TermObject/Mutation/TermObjectMutation.php',
'WPGraphQL\\Type\\TermObject\\Mutation\\TermObjectUpdate' => __DIR__ . '/../..' . '/src/Type/TermObject/Mutation/TermObjectUpdate.php',
'WPGraphQL\\Type\\TermObject\\TermObjectQuery' => __DIR__ . '/../..' . '/src/Type/TermObject/TermObjectQuery.php',
'WPGraphQL\\Type\\TermObject\\TermObjectType' => __DIR__ . '/../..' . '/src/Type/TermObject/TermObjectType.php',
'WPGraphQL\\Type\\Theme\\Connection\\ThemeConnectionDefinition' => __DIR__ . '/../..' . '/src/Type/Theme/Connection/ThemeConnectionDefinition.php',
'WPGraphQL\\Type\\Theme\\Connection\\ThemeConnectionResolver' => __DIR__ . '/../..' . '/src/Type/Theme/Connection/ThemeConnectionResolver.php',
'WPGraphQL\\Type\\Theme\\ThemeType' => __DIR__ . '/../..' . '/src/Type/Theme/ThemeType.php',
'WPGraphQL\\Type\\Union\\CommentAuthorUnionType' => __DIR__ . '/../..' . '/src/Type/Union/CommentAuthorUnionType.php',
'WPGraphQL\\Type\\Union\\PostObjectUnionType' => __DIR__ . '/../..' . '/src/Type/Union/PostObjectUnionType.php',
'WPGraphQL\\Type\\Union\\TermObjectUnionType' => __DIR__ . '/../..' . '/src/Type/Union/TermObjectUnionType.php',
'WPGraphQL\\Type\\User\\Connection\\UserConnectionArgs' => __DIR__ . '/../..' . '/src/Type/User/Connection/UserConnectionArgs.php',
'WPGraphQL\\Type\\User\\Connection\\UserConnectionDefinition' => __DIR__ . '/../..' . '/src/Type/User/Connection/UserConnectionDefinition.php',
'WPGraphQL\\Type\\User\\Connection\\UserConnectionResolver' => __DIR__ . '/../..' . '/src/Type/User/Connection/UserConnectionResolver.php',
'WPGraphQL\\Type\\User\\Mutation\\UserCreate' => __DIR__ . '/../..' . '/src/Type/User/Mutation/UserCreate.php',
'WPGraphQL\\Type\\User\\Mutation\\UserDelete' => __DIR__ . '/../..' . '/src/Type/User/Mutation/UserDelete.php',
'WPGraphQL\\Type\\User\\Mutation\\UserMutation' => __DIR__ . '/../..' . '/src/Type/User/Mutation/UserMutation.php',
'WPGraphQL\\Type\\User\\Mutation\\UserUpdate' => __DIR__ . '/../..' . '/src/Type/User/Mutation/UserUpdate.php',
'WPGraphQL\\Type\\User\\UserQuery' => __DIR__ . '/../..' . '/src/Type/User/UserQuery.php',
'WPGraphQL\\Type\\User\\UserType' => __DIR__ . '/../..' . '/src/Type/User/UserType.php',
'WPGraphQL\\Type\\WPEnumType' => __DIR__ . '/../..' . '/src/Type/WPEnumType.php',
'WPGraphQL\\Type\\WPInputObjectType' => __DIR__ . '/../..' . '/src/Type/WPInputObjectType.php',
'WPGraphQL\\Type\\WPObjectType' => __DIR__ . '/../..' . '/src/Type/WPObjectType.php',
'WPGraphQL\\Types' => __DIR__ . '/../..' . '/src/Types.php',
'WPGraphQL\\Utils\\InstrumentSchema' => __DIR__ . '/../..' . '/src/Utils/InstrumentSchema.php',
'WPGraphQL\\WPSchema' => __DIR__ . '/../..' . '/src/WPSchema.php',
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit989472a815f7398c1ff4d2e496f07f11::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit989472a815f7398c1ff4d2e496f07f11::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInit989472a815f7398c1ff4d2e496f07f11::$classMap;
}, null, ClassLoader::class);
}
}

View File

@@ -0,0 +1,178 @@
<?php
/**
* @author: Ivo Meißner
* Date: 22.02.16
* Time: 18:54
*/
namespace GraphQLRelay\Connection;
class ArrayConnection
{
const PREFIX = 'arrayconnection:';
/**
* Creates the cursor string from an offset.
*/
public static function offsetToCursor($offset)
{
return base64_encode(self::PREFIX . $offset);
}
/**
* Rederives the offset from the cursor string.
*/
public static function cursorToOffset($cursor)
{
$offset = substr(base64_decode($cursor), strlen(self::PREFIX));
if (is_numeric($offset)){
return intval($offset);
} else {
return null;
}
}
/**
* Given an optional cursor and a default offset, returns the offset
* to use; if the cursor contains a valid offset, that will be used,
* otherwise it will be the default.
*/
public static function getOffsetWidthDefault($cursor, $defaultOffset)
{
if ($cursor == null){
return $defaultOffset;
}
$offset = self::cursorToOffset($cursor);
return $offset !== null ? $offset: $defaultOffset;
}
/**
* A simple function that accepts an array and connection arguments, and returns
* a connection object for use in GraphQL. It uses array offsets as pagination,
* so pagination will only work if the array is static.
* @param array $data
* @param $args
*
* @return array
*/
public static function connectionFromArray(array $data, $args)
{
return self::connectionFromArraySlice($data, $args, [
'sliceStart' => 0,
'arrayLength' => count($data)
]);
}
/**
* Given a slice (subset) of an array, returns a connection object for use in
* GraphQL.
*
* This function is similar to `connectionFromArray`, but is intended for use
* cases where you know the cardinality of the connection, consider it too large
* to materialize the entire array, and instead wish pass in a slice of the
* total result large enough to cover the range specified in `args`.
*
* @return array
*/
public static function connectionFromArraySlice(array $arraySlice, $args, $meta)
{
$after = self::getArrayValueSafe($args, 'after');
$before = self::getArrayValueSafe($args, 'before');
$first = self::getArrayValueSafe($args, 'first');
$last = self::getArrayValueSafe($args, 'last');
$sliceStart = self::getArrayValueSafe($meta, 'sliceStart');
$arrayLength = self::getArrayValueSafe($meta, 'arrayLength');
$sliceEnd = $sliceStart + count($arraySlice);
$beforeOffset = self::getOffsetWidthDefault($before, $arrayLength);
$afterOffset = self::getOffsetWidthDefault($after, -1);
$startOffset = max([
$sliceStart - 1,
$afterOffset,
-1
]) + 1;
$endOffset = min([
$sliceEnd,
$beforeOffset,
$arrayLength
]);
if ($first !== null) {
$endOffset = min([
$endOffset,
$startOffset + $first
]);
}
if ($last !== null) {
$startOffset = max([
$startOffset,
$endOffset - $last
]);
}
$slice = array_slice($arraySlice,
max($startOffset - $sliceStart, 0),
count($arraySlice) - ($sliceEnd - $endOffset) - max($startOffset - $sliceStart, 0)
);
$edges = array_map(function($item, $index) use ($startOffset) {
return [
'cursor' => self::offsetToCursor($startOffset + $index),
'node' => $item
];
}, $slice, array_keys($slice));
$firstEdge = $edges ? $edges[0] : null;
$lastEdge = $edges ? $edges[count($edges) - 1] : null;
$lowerBound = $after ? ($afterOffset + 1) : 0;
$upperBound = $before ? ($beforeOffset) : $arrayLength;
return [
'edges' => $edges,
'pageInfo' => [
'startCursor' => $firstEdge ? $firstEdge['cursor'] : null,
'endCursor' => $lastEdge ? $lastEdge['cursor'] : null,
'hasPreviousPage' => $last !== null ? $startOffset > $lowerBound : false,
'hasNextPage' => $first !== null ? $endOffset < $upperBound : false
]
];
}
/**
* Return the cursor associated with an object in an array.
*
* @param array $data
* @param $object
* @return null|string
*/
public static function cursorForObjectInConnection(array $data, $object)
{
$offset = -1;
for ($i = 0; $i < count($data); $i++) {
if ($data[$i] == $object){
$offset = $i;
break;
}
}
if ($offset === -1) {
return null;
}
return self::offsetToCursor($offset);
}
/**
* Returns the value for the given array key, NULL, if it does not exist
*
* @param array $array
* @param string $key
* @return mixed
*/
protected static function getArrayValueSafe(array $array, $key)
{
return array_key_exists($key, $array) ? $array[$key] : null;
}
}

View File

@@ -0,0 +1,195 @@
<?php
/**
* @author: Ivo Meißner
* Date: 22.02.16
* Time: 17:15
*/
namespace GraphQLRelay\Connection;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
class Connection {
/**
* @var ObjectType
*/
protected static $pageInfoType;
/**
* Returns a GraphQLFieldConfigArgumentMap appropriate to include on a field
* whose return type is a connection type with forward pagination.
*
* @return array
*/
public static function forwardConnectionArgs()
{
return [
'after' => [
'type' => Type::string()
],
'first' => [
'type' => Type::int()
]
];
}
/**
* Returns a GraphQLFieldConfigArgumentMap appropriate to include on a field
* whose return type is a connection type with backward pagination.
*
* @return array
*/
public static function backwardConnectionArgs()
{
return [
'before' => [
'type' => Type::string()
],
'last' => [
'type' => Type::int()
]
];
}
/**
* Returns a GraphQLFieldConfigArgumentMap appropriate to include on a field
* whose return type is a connection type with bidirectional pagination.
*
* @return array
*/
public static function connectionArgs()
{
return array_merge(
self::forwardConnectionArgs(),
self::backwardConnectionArgs()
);
}
/**
* Returns a GraphQLObjectType for a connection with the given name,
* and whose nodes are of the specified type.
*/
public static function connectionDefinitions(array $config)
{
return [
'edgeType' => self::createEdgeType($config),
'connectionType' => self::createConnectionType($config)
];
}
/**
* Returns a GraphQLObjectType for a connection with the given name,
* and whose nodes are of the specified type.
*
* @return ObjectType
*/
public static function createConnectionType(array $config)
{
if (!array_key_exists('nodeType', $config)){
throw new \InvalidArgumentException('Connection config needs to have at least a node definition');
}
$nodeType = $config['nodeType'];
$name = array_key_exists('name', $config) ? $config['name'] : $nodeType->name;
$connectionFields = array_key_exists('connectionFields', $config) ? $config['connectionFields'] : [];
$edgeType = array_key_exists('edgeType', $config) ? $config['edgeType'] : null;
$connectionType = new ObjectType([
'name' => $name . 'Connection',
'description' => 'A connection to a list of items.',
'fields' => function() use ($edgeType, $connectionFields, $config) {
return array_merge([
'pageInfo' => [
'type' => Type::nonNull(self::pageInfoType()),
'description' => 'Information to aid in pagination.'
],
'edges' => [
'type' => Type::listOf($edgeType ?: self::createEdgeType($config)),
'description' => 'Information to aid in pagination'
]
], self::resolveMaybeThunk($connectionFields));
}
]);
return $connectionType;
}
/**
* Returns a GraphQLObjectType for an edge with the given name,
* and whose nodes are of the specified type.
*
* @param array $config
* @return ObjectType
*/
public static function createEdgeType(array $config)
{
if (!array_key_exists('nodeType', $config)){
throw new \InvalidArgumentException('Edge config needs to have at least a node definition');
}
$nodeType = $config['nodeType'];
$name = array_key_exists('name', $config) ? $config['name'] : $nodeType->name;
$edgeFields = array_key_exists('edgeFields', $config) ? $config['edgeFields'] : [];
$resolveNode = array_key_exists('resolveNode', $config) ? $config['resolveNode'] : null;
$resolveCursor = array_key_exists('resolveCursor', $config) ? $config['resolveCursor'] : null;
$edgeType = new ObjectType(array_merge([
'name' => $name . 'Edge',
'description' => 'An edge in a connection',
'fields' => function() use ($nodeType, $resolveNode, $resolveCursor, $edgeFields) {
return array_merge([
'node' => [
'type' => $nodeType,
'resolve' => $resolveNode,
'description' => 'The item at the end of the edge'
],
'cursor' => [
'type' => Type::nonNull(Type::string()),
'resolve' => $resolveCursor,
'description' => 'A cursor for use in pagination'
]
], self::resolveMaybeThunk($edgeFields));
}
]));
return $edgeType;
}
/**
* The common page info type used by all connections.
*
* @return ObjectType
*/
public static function pageInfoType()
{
if (self::$pageInfoType === null){
self::$pageInfoType = new ObjectType([
'name' => 'PageInfo',
'description' => 'Information about pagination in a connection.',
'fields' => [
'hasNextPage' => [
'type' => Type::nonNull(Type::boolean()),
'description' => 'When paginating forwards, are there more items?'
],
'hasPreviousPage' => [
'type' => Type::nonNull(Type::boolean()),
'description' => 'When paginating backwards, are there more items?'
],
'startCursor' => [
'type' => Type::string(),
'description' => 'When paginating backwards, the cursor to continue.'
],
'endCursor' => [
'type' => Type::string(),
'description' => 'When paginating forwards, the cursor to continue.'
]
]
]);
}
return self::$pageInfoType;
}
protected static function resolveMaybeThunk ($thinkOrThunk)
{
return is_callable($thinkOrThunk) ? call_user_func($thinkOrThunk) : $thinkOrThunk;
}
}

View File

@@ -0,0 +1,111 @@
<?php
/**
* @author: Ivo Meißner
* Date: 23.02.16
* Time: 12:02
*/
namespace GraphQLRelay\Mutation;
use GraphQL\Type\Definition\InputObjectType;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\ResolveInfo;
use GraphQL\Type\Definition\Type;
class Mutation {
/**
* Returns a GraphQLFieldConfig for the mutation described by the
* provided MutationConfig.
*
* A description of a mutation consumable by mutationWithClientMutationId
* to create a GraphQLFieldConfig for that mutation.
*
* The inputFields and outputFields should not include `clientMutationId`,
* as this will be provided automatically.
*
* An input object will be created containing the input fields, and an
* object will be created containing the output fields.
*
* mutateAndGetPayload will receieve an Object with a key for each
* input field, and it should return an Object with a key for each
* output field. It may return synchronously, or return a Promise.
*
* type MutationConfig = {
* name: string,
* inputFields: InputObjectConfigFieldMap,
* outputFields: GraphQLFieldConfigMap,
* mutateAndGetPayload: mutationFn,
* }
*/
public static function mutationWithClientMutationId(array $config)
{
$name = self::getArrayValue($config, 'name');
$inputFields = self::getArrayValue($config, 'inputFields');
$outputFields = self::getArrayValue($config, 'outputFields');
$mutateAndGetPayload = self::getArrayValue($config, 'mutateAndGetPayload');
$augmentedInputFields = function() use ($inputFields) {
$inputFieldsResolved = self::resolveMaybeThunk($inputFields);
return array_merge($inputFieldsResolved !== null ? $inputFieldsResolved : [], [
'clientMutationId' => [
'type' => Type::nonNull(Type::string())
]
]);
};
$augmentedOutputFields = function () use ($outputFields) {
$outputFieldsResolved = self::resolveMaybeThunk($outputFields);
return array_merge($outputFieldsResolved !== null ? $outputFieldsResolved : [], [
'clientMutationId' => [
'type' => Type::nonNull(Type::string())
]
]);
};
$outputType = new ObjectType([
'name' => $name . 'Payload',
'fields' => $augmentedOutputFields
]);
$inputType = new InputObjectType([
'name' => $name . 'Input',
'fields' => $augmentedInputFields
]);
return [
'type' => $outputType,
'args' => [
'input' => [
'type' => Type::nonNull($inputType)
]
],
'resolve' => function ($query, $args, $context, ResolveInfo $info) use ($mutateAndGetPayload) {
$payload = call_user_func($mutateAndGetPayload, $args['input'], $context, $info);
$payload['clientMutationId'] = $args['input']['clientMutationId'];
return $payload;
}
];
}
/**
* Returns the value for the given array key, NULL, if it does not exist
*
* @param array $array
* @param string $key
* @return mixed
*/
protected static function getArrayValue(array $array, $key)
{
if (array_key_exists($key, $array)){
return $array[$key];
} else {
throw new \InvalidArgumentException('The config value for "' . $key . '" is required, but missing in MutationConfig."');
}
}
protected static function resolveMaybeThunk($thinkOrThunk)
{
return is_callable($thinkOrThunk) ? call_user_func($thinkOrThunk) : $thinkOrThunk;
}
}

View File

@@ -0,0 +1,117 @@
<?php
/**
* @author: Ivo Meißner
* Date: 22.02.16
* Time: 12:45
*/
namespace GraphQLRelay\Node;
use GraphQL\Type\Definition\InterfaceType;
use GraphQL\Type\Definition\Type;
const GLOBAL_ID_DELIMITER = ':';
class Node {
/**
* Given a function to map from an ID to an underlying object, and a function
* to map from an underlying object to the concrete GraphQLObjectType it
* corresponds to, constructs a `Node` interface that objects can implement,
* and a field config for a `node` root field.
*
* If the typeResolver is omitted, object resolution on the interface will be
* handled with the `isTypeOf` method on object types, as with any GraphQL
* interface without a provided `resolveType` method.
*
* @param callable $idFetcher
* @param callable $typeResolver
* @return array
*/
public static function nodeDefinitions(callable $idFetcher, callable $typeResolver = null) {
$nodeInterface = new InterfaceType([
'name' => 'Node',
'description' => 'An object with an ID',
'fields' => [
'id' => [
'type' => Type::nonNull(Type::id()),
'description' => 'The id of the object',
]
],
'resolveType' => $typeResolver
]);
$nodeField = [
'name' => 'node',
'description' => 'Fetches an object given its ID',
'type' => $nodeInterface,
'args' => [
'id' => [
'type' => Type::nonNull(Type::id()),
'description' => 'The ID of an object'
]
],
'resolve' => function ($obj, $args, $context, $info) use ($idFetcher) {
return $idFetcher($args['id'], $context, $info);
}
];
return [
'nodeInterface' => $nodeInterface,
'nodeField' => $nodeField
];
}
/**
* Takes a type name and an ID specific to that type name, and returns a
* "global ID" that is unique among all types.
*
* @param string $type
* @param string $id
* @return string
*/
public static function toGlobalId($type, $id) {
return base64_encode($type . GLOBAL_ID_DELIMITER . $id);
}
/**
* Takes the "global ID" created by self::toGlobalId, and returns the type name and ID
* used to create it.
*
* @param $globalId
* @return array
*/
public static function fromGlobalId($globalId) {
$unbasedGlobalId = base64_decode($globalId);
$delimiterPos = strpos($unbasedGlobalId, GLOBAL_ID_DELIMITER);
return [
'type' => substr($unbasedGlobalId, 0, $delimiterPos),
'id' => substr($unbasedGlobalId, $delimiterPos + 1)
];
}
/**
* Creates the configuration for an id field on a node, using `self::toGlobalId` to
* construct the ID from the provided typename. The type-specific ID is fetched
* by calling idFetcher on the object, or if not provided, by accessing the `id`
* property on the object.
*
* @param string|null $typeName
* @param callable|null $idFetcher
* @return array
*/
public static function globalIdField($typeName = null, callable $idFetcher = null) {
return [
'name' => 'id',
'description' => 'The ID of an object',
'type' => Type::nonNull(Type::id()),
'resolve' => function($obj, $args, $context, $info) use ($typeName, $idFetcher) {
return self::toGlobalId(
$typeName !== null ? $typeName : $info->parentType->name,
$idFetcher ? $idFetcher($obj, $info) : $obj['id']
);
}
];
}
}

View File

@@ -0,0 +1,69 @@
<?php
/**
* @author: Ivo Meißner
* Date: 29.02.16
* Time: 16:17
*/
namespace GraphQLRelay\Node;
use GraphQL\Type\Definition\ResolveInfo;
use GraphQL\Type\Definition\Type;
class Plural {
/**
* Returns configuration for Plural identifying root field
*
* type PluralIdentifyingRootFieldConfig = {
* argName: string,
* inputType: GraphQLInputType,
* outputType: GraphQLOutputType,
* resolveSingleInput: (input: any, info: GraphQLResolveInfo) => ?any,
* description?: ?string,
* };
*
* @param array $config
* @return array
*/
public static function pluralIdentifyingRootField(array $config)
{
$inputArgs = [];
$argName = self::getArrayValue($config, 'argName');
$inputArgs[$argName] = [
'type' => Type::nonNull(
Type::listOf(
Type::nonNull(self::getArrayValue($config, 'inputType'))
)
)
];
return [
'description' => isset($config['description']) ? $config['description'] : null,
'type' => Type::listOf(self::getArrayValue($config, 'outputType')),
'args' => $inputArgs,
'resolve' => function ($obj, $args, $context, ResolveInfo $info) use ($argName, $config) {
$inputs = $args[$argName];
return array_map(function($input) use ($config, $context, $info) {
return call_user_func(self::getArrayValue($config, 'resolveSingleInput'), $input, $context, $info);
}, $inputs);
}
];
}
/**
* Returns the value for the given array key, NULL, if it does not exist
*
* @param array $array
* @param string $key
* @return mixed
*/
protected static function getArrayValue(array $array, $key)
{
if (array_key_exists($key, $array)){
return $array[$key];
} else {
throw new \InvalidArgumentException('The config value for "' . $key . '" is required, but missing in PluralIdentifyingRootFieldConfig."');
}
}
}

View File

@@ -0,0 +1,219 @@
<?php
/**
* @author: Ivo Meißner
* Date: 23.02.16
* Time: 15:21
*/
namespace GraphQLRelay;
use GraphQL\Type\Definition\ObjectType;
use GraphQLRelay\Connection\ArrayConnection;
use GraphQLRelay\Connection\Connection;
use GraphQLRelay\Mutation\Mutation;
use GraphQLRelay\Node\Node;
class Relay {
/**
* Returns a GraphQLFieldConfigArgumentMap appropriate to include on a field
* whose return type is a connection type with forward pagination.
*
* @return array
*/
public static function forwardConnectionArgs()
{
return Connection::forwardConnectionArgs();
}
/**
* Returns a GraphQLFieldConfigArgumentMap appropriate to include on a field
* whose return type is a connection type with backward pagination.
*
* @return array
*/
public static function backwardConnectionArgs()
{
return Connection::backwardConnectionArgs();
}
/**
* Returns a GraphQLFieldConfigArgumentMap appropriate to include on a field
* whose return type is a connection type with bidirectional pagination.
*
* @return array
*/
public static function connectionArgs()
{
return Connection::connectionArgs();
}
/**
* Returns a GraphQLObjectType for a connection and its edge with the given name,
* and whose nodes are of the specified type.
*
* @param array $config
* @return array
*/
public static function connectionDefinitions(array $config)
{
return Connection::connectionDefinitions($config);
}
/**
* Returns a GraphQLObjectType for a connection with the given name,
* and whose nodes are of the specified type.
*
* @param array $config
* @return ObjectType
*/
public static function connectionType(array $config)
{
return Connection::createConnectionType($config);
}
/**
* Returns a GraphQLObjectType for a edge with the given name,
* and whose nodes are of the specified type.
*
* @param array $config
* @return ObjectType
*/
public static function edgeType(array $config)
{
return Connection::createEdgeType($config);
}
/**
* A simple function that accepts an array and connection arguments, and returns
* a connection object for use in GraphQL. It uses array offsets as pagination,
* so pagination will only work if the array is static.
* @param array $data
* @param $args
*
* @return array
*/
public static function connectionFromArray(array $data, $args)
{
return ArrayConnection::connectionFromArray($data, $args);
}
/**
* Given a slice (subset) of an array, returns a connection object for use in
* GraphQL.
*
* This function is similar to `connectionFromArray`, but is intended for use
* cases where you know the cardinality of the connection, consider it too large
* to materialize the entire array, and instead wish pass in a slice of the
* total result large enough to cover the range specified in `args`.
*
* @param array $arraySlice
* @param $args
* @param $meta
* @return array
*/
public static function connectionFromArraySlice(array $arraySlice, $args, $meta)
{
return ArrayConnection::connectionFromArraySlice($arraySlice, $args, $meta);
}
/**
* Return the cursor associated with an object in an array.
*
* @param array $data
* @param $object
* @return null|string
*/
public static function cursorForObjectInConnection(array $data, $object)
{
return ArrayConnection::cursorForObjectInConnection($data, $object);
}
/**
* Returns a GraphQLFieldConfig for the mutation described by the
* provided MutationConfig.
*
* A description of a mutation consumable by mutationWithClientMutationId
* to create a GraphQLFieldConfig for that mutation.
*
* The inputFields and outputFields should not include `clientMutationId`,
* as this will be provided automatically.
*
* An input object will be created containing the input fields, and an
* object will be created containing the output fields.
*
* mutateAndGetPayload will receieve an Object with a key for each
* input field, and it should return an Object with a key for each
* output field. It may return synchronously, or return a Promise.
*
* type MutationConfig = {
* name: string,
* inputFields: InputObjectConfigFieldMap,
* outputFields: GraphQLFieldConfigMap,
* mutateAndGetPayload: mutationFn,
* }
*
* @param array $config
* @return array
*/
public static function mutationWithClientMutationId(array $config)
{
return Mutation::mutationWithClientMutationId($config);
}
/**
* Given a function to map from an ID to an underlying object, and a function
* to map from an underlying object to the concrete GraphQLObjectType it
* corresponds to, constructs a `Node` interface that objects can implement,
* and a field config for a `node` root field.
*
* If the typeResolver is omitted, object resolution on the interface will be
* handled with the `isTypeOf` method on object types, as with any GraphQL
* interface without a provided `resolveType` method.
*
* @param callable $idFetcher
* @param callable $typeResolver
* @return array
*/
public static function nodeDefinitions(callable $idFetcher, callable $typeResolver = null) {
return Node::nodeDefinitions($idFetcher, $typeResolver);
}
/**
* Takes a type name and an ID specific to that type name, and returns a
* "global ID" that is unique among all types.
*
* @param string $type
* @param string $id
* @return string
*/
public static function toGlobalId($type, $id) {
return Node::toGlobalId($type, $id);
}
/**
* Takes the "global ID" created by self::toGlobalId, and returns the type name and ID
* used to create it.
*
* @param $globalId
* @return array
*/
public static function fromGlobalId($globalId) {
return Node::fromGlobalId($globalId);
}
/**
* Creates the configuration for an id field on a node, using `self::toGlobalId` to
* construct the ID from the provided typename. The type-specific ID is fetched
* by calling idFetcher on the object, or if not provided, by accessing the `id`
* property on the object.
*
* @param string|null $typeName
* @param callable|null $idFetcher
* @return array
*/
public static function globalIdField($typeName = null, callable $idFetcher = null) {
return Node::globalIdField($typeName, $idFetcher);
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace GraphQL;
use GraphQL\Executor\Promise\Adapter\SyncPromise;
class Deferred
{
/**
* @var \SplQueue
*/
private static $queue;
/**
* @var callable
*/
private $callback;
/**
* @var SyncPromise
*/
public $promise;
public static function getQueue()
{
return self::$queue ?: self::$queue = new \SplQueue();
}
public static function runQueue()
{
$q = self::$queue;
while ($q && !$q->isEmpty()) {
/** @var self $dfd */
$dfd = $q->dequeue();
$dfd->run();
}
}
public function __construct(callable $callback)
{
$this->callback = $callback;
$this->promise = new SyncPromise();
self::getQueue()->enqueue($this);
}
public function then($onFulfilled = null, $onRejected = null)
{
return $this->promise->then($onFulfilled, $onRejected);
}
private function run()
{
try {
$cb = $this->callback;
$this->promise->resolve($cb());
} catch (\Exception $e) {
$this->promise->reject($e);
} catch (\Throwable $e) {
$this->promise->reject($e);
}
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace GraphQL;
trigger_error(
'GraphQL\Error was moved to GraphQL\Error\Error and will be deleted on next release',
E_USER_DEPRECATED
);
/**
* Class Error
*
* @deprecated as of 8.0 in favor of GraphQL\Error\Error
* @package GraphQL
*/
class Error extends \GraphQL\Error\Error
{
}

View File

@@ -0,0 +1,31 @@
<?php
namespace GraphQL\Error;
/**
* This interface is used for [default error formatting](error-handling.md).
*
* Only errors implementing this interface (and returning true from `isClientSafe()`)
* will be formatted with original error message.
*
* All other errors will be formatted with generic "Internal server error".
*/
interface ClientAware
{
/**
* Returns true when exception message is safe to be displayed to a client.
*
* @api
* @return bool
*/
public function isClientSafe();
/**
* Returns string describing a category of the error.
*
* Value "graphql" is reserved for errors produced by query parsing or validation, do not use it.
*
* @api
* @return string
*/
public function getCategory();
}

View File

@@ -0,0 +1,12 @@
<?php
namespace GraphQL\Error;
/**
* Collection of flags for [error debugging](error-handling.md#debugging-tools).
*/
class Debug
{
const INCLUDE_DEBUG_MESSAGE = 1;
const INCLUDE_TRACE = 2;
const RETHROW_INTERNAL_EXCEPTIONS = 4;
}

View File

@@ -0,0 +1,300 @@
<?php
namespace GraphQL\Error;
use GraphQL\Language\Source;
use GraphQL\Language\SourceLocation;
use GraphQL\Utils\Utils;
/**
* Describes an Error found during the parse, validate, or
* execute phases of performing a GraphQL operation. In addition to a message
* and stack trace, it also includes information about the locations in a
* GraphQL document and/or execution result that correspond to the Error.
*
* When the error was caused by an exception thrown in resolver, original exception
* is available via `getPrevious()`.
*
* Also read related docs on [error handling](error-handling.md)
*
* Class extends standard PHP `\Exception`, so all standard methods of base `\Exception` class
* are available in addition to those listed below.
*/
class Error extends \Exception implements \JsonSerializable, ClientAware
{
const CATEGORY_GRAPHQL = 'graphql';
const CATEGORY_INTERNAL = 'internal';
/**
* A message describing the Error for debugging purposes.
*
* @var string
*/
public $message;
/**
* @var SourceLocation[]
*/
private $locations;
/**
* An array describing the JSON-path into the execution response which
* corresponds to this error. Only included for errors during execution.
*
* @var array
*/
public $path;
/**
* An array of GraphQL AST Nodes corresponding to this error.
*
* @var array
*/
public $nodes;
/**
* The source GraphQL document corresponding to this error.
*
* @var Source|null
*/
private $source;
/**
* @var array
*/
private $positions;
/**
* @var bool
*/
private $isClientSafe;
/**
* @var string
*/
protected $category;
/**
* Given an arbitrary Error, presumably thrown while attempting to execute a
* GraphQL operation, produce a new GraphQLError aware of the location in the
* document responsible for the original Error.
*
* @param $error
* @param array|null $nodes
* @param array|null $path
* @return Error
*/
public static function createLocatedError($error, $nodes = null, $path = null)
{
if ($error instanceof self) {
if ($error->path && $error->nodes) {
return $error;
} else {
$nodes = $nodes ?: $error->nodes;
$path = $path ?: $error->path;
}
}
$source = $positions = $originalError = null;
if ($error instanceof self) {
$message = $error->getMessage();
$originalError = $error;
$nodes = $error->nodes ?: $nodes;
$source = $error->source;
$positions = $error->positions;
} else if ($error instanceof \Exception || $error instanceof \Throwable) {
$message = $error->getMessage();
$originalError = $error;
} else {
$message = (string) $error;
}
return new static(
$message ?: 'An unknown error occurred.',
$nodes,
$source,
$positions,
$path,
$originalError
);
}
/**
* @param Error $error
* @return array
*/
public static function formatError(Error $error)
{
return $error->toSerializableArray();
}
/**
* @param string $message
* @param array|null $nodes
* @param Source $source
* @param array|null $positions
* @param array|null $path
* @param \Throwable $previous
*/
public function __construct(
$message,
$nodes = null,
Source $source = null,
$positions = null,
$path = null,
$previous = null
)
{
parent::__construct($message, 0, $previous);
if ($nodes instanceof \Traversable) {
$nodes = iterator_to_array($nodes);
}
$this->nodes = $nodes;
$this->source = $source;
$this->positions = $positions;
$this->path = $path;
if ($previous instanceof ClientAware) {
$this->isClientSafe = $previous->isClientSafe();
$this->category = $previous->getCategory() ?: static::CATEGORY_INTERNAL;
} else if ($previous) {
$this->isClientSafe = false;
$this->category = static::CATEGORY_INTERNAL;
} else {
$this->isClientSafe = true;
$this->category = static::CATEGORY_GRAPHQL;
}
}
/**
* @inheritdoc
*/
public function isClientSafe()
{
return $this->isClientSafe;
}
/**
* @inheritdoc
*/
public function getCategory()
{
return $this->category;
}
/**
* @return Source|null
*/
public function getSource()
{
if (null === $this->source) {
if (!empty($this->nodes[0]) && !empty($this->nodes[0]->loc)) {
$this->source = $this->nodes[0]->loc->source;
}
}
return $this->source;
}
/**
* @return array
*/
public function getPositions()
{
if (null === $this->positions) {
if (!empty($this->nodes)) {
$positions = array_map(function($node) {
return isset($node->loc) ? $node->loc->start : null;
}, $this->nodes);
$this->positions = array_filter($positions, function($p) {
return $p !== null;
});
}
}
return $this->positions;
}
/**
* An array of locations within the source GraphQL document which correspond to this error.
*
* Each entry has information about `line` and `column` within source GraphQL document:
* $location->line;
* $location->column;
*
* Errors during validation often contain multiple locations, for example to
* point out to field mentioned in multiple fragments. Errors during execution include a
* single location, the field which produced the error.
*
* @api
* @return SourceLocation[]
*/
public function getLocations()
{
if (null === $this->locations) {
$positions = $this->getPositions();
$source = $this->getSource();
if ($positions && $source) {
$this->locations = array_map(function ($pos) use ($source) {
return $source->getLocation($pos);
}, $positions);
} else {
$this->locations = [];
}
}
return $this->locations;
}
/**
* Returns an array describing the path from the root value to the field which produced this error.
* Only included for execution errors.
*
* @api
* @return array|null
*/
public function getPath()
{
return $this->path;
}
/**
* Returns array representation of error suitable for serialization
*
* @deprecated Use FormattedError::createFromException() instead
* @return array
*/
public function toSerializableArray()
{
$arr = [
'message' => $this->getMessage()
];
$locations = Utils::map($this->getLocations(), function(SourceLocation $loc) {
return $loc->toSerializableArray();
});
if (!empty($locations)) {
$arr['locations'] = $locations;
}
if (!empty($this->path)) {
$arr['path'] = $this->path;
}
return $arr;
}
/**
* Specify data which should be serialized to JSON
* @link http://php.net/manual/en/jsonserializable.jsonserialize.php
* @return mixed data which can be serialized by <b>json_encode</b>,
* which is a value of any type other than a resource.
* @since 5.4.0
*/
function jsonSerialize()
{
return $this->toSerializableArray();
}
}

View File

@@ -0,0 +1,278 @@
<?php
namespace GraphQL\Error;
use GraphQL\Language\SourceLocation;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\WrappingType;
use GraphQL\Utils\Utils;
/**
* This class is used for [default error formatting](error-handling.md).
* It converts PHP exceptions to [spec-compliant errors](https://facebook.github.io/graphql/#sec-Errors)
* and provides tools for error debugging.
*/
class FormattedError
{
private static $internalErrorMessage = 'Internal server error';
/**
* Set default error message for internal errors formatted using createFormattedError().
* This value can be overridden by passing 3rd argument to `createFormattedError()`.
*
* @api
* @param string $msg
*/
public static function setInternalErrorMessage($msg)
{
self::$internalErrorMessage = $msg;
}
/**
* Standard GraphQL error formatter. Converts any exception to array
* conforming to GraphQL spec.
*
* This method only exposes exception message when exception implements ClientAware interface
* (or when debug flags are passed).
*
* For a list of available debug flags see GraphQL\Error\Debug constants.
*
* @api
* @param \Throwable $e
* @param bool|int $debug
* @param string $internalErrorMessage
* @return array
* @throws \Throwable
*/
public static function createFromException($e, $debug = false, $internalErrorMessage = null)
{
Utils::invariant(
$e instanceof \Exception || $e instanceof \Throwable,
"Expected exception, got %s",
Utils::getVariableType($e)
);
$internalErrorMessage = $internalErrorMessage ?: self::$internalErrorMessage;
if ($e instanceof ClientAware) {
$formattedError = [
'message' => $e->isClientSafe() ? $e->getMessage() : $internalErrorMessage,
'category' => $e->getCategory()
];
} else {
$formattedError = [
'message' => $internalErrorMessage,
'category' => Error::CATEGORY_INTERNAL
];
}
if ($e instanceof Error) {
$locations = Utils::map($e->getLocations(), function(SourceLocation $loc) {
return $loc->toSerializableArray();
});
if (!empty($locations)) {
$formattedError['locations'] = $locations;
}
if (!empty($e->path)) {
$formattedError['path'] = $e->path;
}
}
if ($debug) {
$formattedError = self::addDebugEntries($formattedError, $e, $debug);
}
return $formattedError;
}
/**
* Decorates spec-compliant $formattedError with debug entries according to $debug flags
* (see GraphQL\Error\Debug for available flags)
*
* @param array $formattedError
* @param \Throwable $e
* @param bool $debug
* @return array
* @throws \Throwable
*/
public static function addDebugEntries(array $formattedError, $e, $debug)
{
if (!$debug) {
return $formattedError;
}
Utils::invariant(
$e instanceof \Exception || $e instanceof \Throwable,
"Expected exception, got %s",
Utils::getVariableType($e)
);
$debug = (int) $debug;
if ($debug & Debug::RETHROW_INTERNAL_EXCEPTIONS) {
if (!$e instanceof Error) {
throw $e;
} else if ($e->getPrevious()) {
throw $e->getPrevious();
}
}
$isInternal = !$e instanceof ClientAware || !$e->isClientSafe();
if (($debug & Debug::INCLUDE_DEBUG_MESSAGE) && $isInternal) {
// Displaying debugMessage as a first entry:
$formattedError = ['debugMessage' => $e->getMessage()] + $formattedError;
}
if ($debug & Debug::INCLUDE_TRACE) {
if ($e instanceof \ErrorException || $e instanceof \Error) {
$formattedError += [
'file' => $e->getFile(),
'line' => $e->getLine(),
];
}
$isTrivial = $e instanceof Error && !$e->getPrevious();
if (!$isTrivial) {
$debugging = $e->getPrevious() ?: $e;
$formattedError['trace'] = static::toSafeTrace($debugging);
}
}
return $formattedError;
}
/**
* Prepares final error formatter taking in account $debug flags.
* If initial formatter is not set, FormattedError::createFromException is used
*
* @param callable|null $formatter
* @param $debug
* @return callable|\Closure
*/
public static function prepareFormatter(callable $formatter = null, $debug)
{
$formatter = $formatter ?: function($e) {
return FormattedError::createFromException($e);
};
if ($debug) {
$formatter = function($e) use ($formatter, $debug) {
return FormattedError::addDebugEntries($formatter($e), $e, $debug);
};
}
return $formatter;
}
/**
* Returns error trace as serializable array
*
* @api
* @param \Throwable $error
* @return array
*/
public static function toSafeTrace($error)
{
$trace = $error->getTrace();
// Remove invariant entries as they don't provide much value:
if (
isset($trace[0]['function']) && isset($trace[0]['class']) &&
('GraphQL\Utils\Utils::invariant' === $trace[0]['class'].'::'.$trace[0]['function'])) {
array_shift($trace);
}
// Remove root call as it's likely error handler trace:
else if (!isset($trace[0]['file'])) {
array_shift($trace);
}
return array_map(function($err) {
$safeErr = array_intersect_key($err, ['file' => true, 'line' => true]);
if (isset($err['function'])) {
$func = $err['function'];
$args = !empty($err['args']) ? array_map([__CLASS__, 'printVar'], $err['args']) : [];
$funcStr = $func . '(' . implode(", ", $args) . ')';
if (isset($err['class'])) {
$safeErr['call'] = $err['class'] . '::' . $funcStr;
} else {
$safeErr['function'] = $funcStr;
}
}
return $safeErr;
}, $trace);
}
/**
* @param $var
* @return string
*/
public static function printVar($var)
{
if ($var instanceof Type) {
// FIXME: Replace with schema printer call
if ($var instanceof WrappingType) {
$var = $var->getWrappedType(true);
}
return 'GraphQLType: ' . $var->name;
}
if (is_object($var)) {
return 'instance of ' . get_class($var) . ($var instanceof \Countable ? '(' . count($var) . ')' : '');
}
if (is_array($var)) {
return 'array(' . count($var) . ')';
}
if ('' === $var) {
return '(empty string)';
}
if (is_string($var)) {
return "'" . addcslashes($var, "'") . "'";
}
if (is_bool($var)) {
return $var ? 'true' : 'false';
}
if (is_scalar($var)) {
return $var;
}
if (null === $var) {
return 'null';
}
return gettype($var);
}
/**
* @deprecated as of v0.8.0
* @param $error
* @param SourceLocation[] $locations
* @return array
*/
public static function create($error, array $locations = [])
{
$formatted = [
'message' => $error
];
if (!empty($locations)) {
$formatted['locations'] = array_map(function($loc) { return $loc->toArray();}, $locations);
}
return $formatted;
}
/**
* @param \ErrorException $e
* @deprecated as of v0.10.0, use general purpose method createFromException() instead
* @return array
*/
public static function createFromPHPError(\ErrorException $e)
{
return [
'message' => $e->getMessage(),
'severity' => $e->getSeverity(),
'trace' => self::toSafeTrace($e)
];
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace GraphQL\Error;
/**
* Class InvariantVoilation
*
* Note:
* This exception should not inherit base Error exception as it is raised when there is an error somewhere in
* user-land code
*
* @package GraphQL\Error
*/
class InvariantViolation extends \LogicException
{
}

View File

@@ -0,0 +1,71 @@
<?php
namespace GraphQL\Error;
use GraphQL\Language\Source;
use GraphQL\Language\SourceLocation;
class SyntaxError extends Error
{
/**
* @param Source $source
* @param int $position
* @param string $description
*/
public function __construct(Source $source, $position, $description)
{
$location = $source->getLocation($position);
$line = $location->line + $source->locationOffset->line - 1;
$columnOffset = self::getColumnOffset($source, $location);
$column = $location->column + $columnOffset;
$syntaxError =
"Syntax Error {$source->name} ({$line}:{$column}) $description\n" .
"\n".
self::highlightSourceAtLocation($source, $location);
parent::__construct($syntaxError, null, $source, [$position]);
}
/**
* @param Source $source
* @param SourceLocation $location
* @return string
*/
public static function highlightSourceAtLocation(Source $source, SourceLocation $location)
{
$line = $location->line;
$lineOffset = $source->locationOffset->line - 1;
$columnOffset = self::getColumnOffset($source, $location);
$contextLine = $line + $lineOffset;
$prevLineNum = (string) ($contextLine - 1);
$lineNum = (string) $contextLine;
$nextLineNum = (string) ($contextLine + 1);
$padLen = mb_strlen($nextLineNum, 'UTF-8');
$unicodeChars = json_decode('"\u2028\u2029"'); // Quick hack to get js-compatible representation of these chars
$lines = preg_split('/\r\n|[\n\r' . $unicodeChars . ']/su', $source->body);
$whitespace = function ($len) {
return str_repeat(' ', $len);
};
$lpad = function ($len, $str) {
return str_pad($str, $len - mb_strlen($str, 'UTF-8') + 1, ' ', STR_PAD_LEFT);
};
$lines[0] = $whitespace($source->locationOffset->column - 1) . $lines[0];
return
($line >= 2 ? $lpad($padLen, $prevLineNum) . ': ' . $lines[$line - 2] . "\n" : '') .
($lpad($padLen, $lineNum) . ': ' . $lines[$line - 1] . "\n") .
($whitespace(2 + $padLen + $location->column - 1 + $columnOffset) . "^\n") .
($line < count($lines) ? $lpad($padLen, $nextLineNum) . ': ' . $lines[$line] . "\n" : '');
}
public static function getColumnOffset(Source $source, SourceLocation $location)
{
return $location->line === 1 ? $source->locationOffset->column - 1 : 0;
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace GraphQL\Error;
/**
* Class UserError
*
* Error caused by actions of GraphQL clients. Can be safely displayed to a client...
*
* @package GraphQL\Error
*/
class UserError extends \RuntimeException implements ClientAware
{
/**
* @return bool
*/
public function isClientSafe()
{
return true;
}
/**
* @return string
*/
public function getCategory()
{
return 'user';
}
}

View File

@@ -0,0 +1,104 @@
<?php
namespace GraphQL\Error;
/**
* Encapsulates warnings produced by the library.
*
* Warnings can be suppressed (individually or all) if required.
* Also it is possible to override warning handler (which is **trigger_error()** by default)
*/
final class Warning
{
const WARNING_NAME = 1;
const WARNING_ASSIGN = 2;
const WARNING_CONFIG = 4;
const WARNING_FULL_SCHEMA_SCAN = 8;
const WARNING_CONFIG_DEPRECATION = 16;
const WARNING_NOT_A_TYPE = 32;
const ALL = 63;
static $enableWarnings = self::ALL;
static $warned = [];
static private $warningHandler;
/**
* Sets warning handler which can intercept all system warnings.
* When not set, trigger_error() is used to notify about warnings.
*
* @api
* @param callable|null $warningHandler
*/
public static function setWarningHandler(callable $warningHandler = null)
{
self::$warningHandler = $warningHandler;
}
/**
* Suppress warning by id (has no effect when custom warning handler is set)
*
* Usage example:
* Warning::suppress(Warning::WARNING_NOT_A_TYPE)
*
* When passing true - suppresses all warnings.
*
* @api
* @param bool|int $suppress
*/
static function suppress($suppress = true)
{
if (true === $suppress) {
self::$enableWarnings = 0;
} else if (false === $suppress) {
self::$enableWarnings = self::ALL;
} else {
$suppress = (int) $suppress;
self::$enableWarnings &= ~$suppress;
}
}
/**
* Re-enable previously suppressed warning by id
*
* Usage example:
* Warning::suppress(Warning::WARNING_NOT_A_TYPE)
*
* When passing true - re-enables all warnings.
*
* @api
* @param bool|int $enable
*/
public static function enable($enable = true)
{
if (true === $enable) {
self::$enableWarnings = self::ALL;
} else if (false === $enable) {
self::$enableWarnings = 0;
} else {
$enable = (int) $enable;
self::$enableWarnings |= $enable;
}
}
static function warnOnce($errorMessage, $warningId, $messageLevel = null)
{
if (self::$warningHandler) {
$fn = self::$warningHandler;
$fn($errorMessage, $warningId);
} else if ((self::$enableWarnings & $warningId) > 0 && !isset(self::$warned[$warningId])) {
self::$warned[$warningId] = true;
trigger_error($errorMessage, $messageLevel ?: E_USER_WARNING);
}
}
static function warn($errorMessage, $warningId, $messageLevel = null)
{
if (self::$warningHandler) {
$fn = self::$warningHandler;
$fn($errorMessage, $warningId);
} else if ((self::$enableWarnings & $warningId) > 0) {
trigger_error($errorMessage, $messageLevel ?: E_USER_WARNING);
}
}
}

View File

@@ -0,0 +1,87 @@
<?php
namespace GraphQL\Executor;
use GraphQL\Error\Error;
use GraphQL\Language\AST\FragmentDefinitionNode;
use GraphQL\Language\AST\OperationDefinitionNode;
use GraphQL\Type\Schema;
/**
* Data that must be available at all points during query execution.
*
* Namely, schema of the type system that is currently executing,
* and the fragments defined in the query document
*
* @internal
*/
class ExecutionContext
{
/**
* @var Schema
*/
public $schema;
/**
* @var FragmentDefinitionNode[]
*/
public $fragments;
/**
* @var mixed
*/
public $rootValue;
/**
* @var mixed
*/
public $contextValue;
/**
* @var OperationDefinitionNode
*/
public $operation;
/**
* @var array
*/
public $variableValues;
/**
* @var callable
*/
public $fieldResolver;
/**
* @var array
*/
public $errors;
public function __construct(
$schema,
$fragments,
$root,
$contextValue,
$operation,
$variables,
$errors,
$fieldResolver,
$promiseAdapter
)
{
$this->schema = $schema;
$this->fragments = $fragments;
$this->rootValue = $root;
$this->contextValue = $contextValue;
$this->operation = $operation;
$this->variableValues = $variables;
$this->errors = $errors ?: [];
$this->fieldResolver = $fieldResolver;
$this->promises = $promiseAdapter;
}
public function addError(Error $error)
{
$this->errors[] = $error;
return $this;
}
}

View File

@@ -0,0 +1,158 @@
<?php
namespace GraphQL\Executor;
use GraphQL\Error\Error;
use GraphQL\Error\FormattedError;
/**
* Returned after [query execution](executing-queries.md).
* Represents both - result of successful execution and of a failed one
* (with errors collected in `errors` prop)
*
* Could be converted to [spec-compliant](https://facebook.github.io/graphql/#sec-Response-Format)
* serializable array using `toArray()`
*/
class ExecutionResult implements \JsonSerializable
{
/**
* Data collected from resolvers during query execution
*
* @api
* @var array
*/
public $data;
/**
* Errors registered during query execution.
*
* If an error was caused by exception thrown in resolver, $error->getPrevious() would
* contain original exception.
*
* @api
* @var \GraphQL\Error\Error[]
*/
public $errors;
/**
* User-defined serializable array of extensions included in serialized result.
* Conforms to
*
* @api
* @var array
*/
public $extensions;
/**
* @var callable
*/
private $errorFormatter;
/**
* @var callable
*/
private $errorsHandler;
/**
* @param array $data
* @param array $errors
* @param array $extensions
*/
public function __construct(array $data = null, array $errors = [], array $extensions = [])
{
$this->data = $data;
$this->errors = $errors;
$this->extensions = $extensions;
}
/**
* Define custom error formatting (must conform to http://facebook.github.io/graphql/#sec-Errors)
*
* Expected signature is: function (GraphQL\Error\Error $error): array
*
* Default formatter is "GraphQL\Error\FormattedError::createFromException"
*
* Expected returned value must be an array:
* array(
* 'message' => 'errorMessage',
* // ... other keys
* );
*
* @api
* @param callable $errorFormatter
* @return $this
*/
public function setErrorFormatter(callable $errorFormatter)
{
$this->errorFormatter = $errorFormatter;
return $this;
}
/**
* Define custom logic for error handling (filtering, logging, etc).
*
* Expected handler signature is: function (array $errors, callable $formatter): array
*
* Default handler is:
* function (array $errors, callable $formatter) {
* return array_map($formatter, $errors);
* }
*
* @api
* @param callable $handler
* @return $this
*/
public function setErrorsHandler(callable $handler)
{
$this->errorsHandler = $handler;
return $this;
}
/**
* Converts GraphQL query result to spec-compliant serializable array using provided
* errors handler and formatter.
*
* If debug argument is passed, output of error formatter is enriched which debugging information
* ("debugMessage", "trace" keys depending on flags).
*
* $debug argument must be either bool (only adds "debugMessage" to result) or sum of flags from
* GraphQL\Error\Debug
*
* @api
* @param bool|int $debug
* @return array
*/
public function toArray($debug = false)
{
$result = [];
if (!empty($this->errors)) {
$errorsHandler = $this->errorsHandler ?: function(array $errors, callable $formatter) {
return array_map($formatter, $errors);
};
$result['errors'] = $errorsHandler(
$this->errors,
FormattedError::prepareFormatter($this->errorFormatter, $debug)
);
}
if (null !== $this->data) {
$result['data'] = $this->data;
}
if (!empty($this->extensions)) {
$result['extensions'] = (array) $this->extensions;
}
return $result;
}
/**
* Part of \JsonSerializable interface
*
* @return array
*/
public function jsonSerialize()
{
return $this->toArray();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,86 @@
<?php
namespace GraphQL\Executor\Promise\Adapter;
use GraphQL\Executor\Promise\Promise;
use GraphQL\Executor\Promise\PromiseAdapter;
use GraphQL\Utils\Utils;
use React\Promise\Promise as ReactPromise;
use React\Promise\PromiseInterface as ReactPromiseInterface;
class ReactPromiseAdapter implements PromiseAdapter
{
/**
* @inheritdoc
*/
public function isThenable($value)
{
return $value instanceof ReactPromiseInterface;
}
/**
* @inheritdoc
*/
public function convertThenable($thenable)
{
return new Promise($thenable, $this);
}
/**
* @inheritdoc
*/
public function then(Promise $promise, callable $onFulfilled = null, callable $onRejected = null)
{
/** @var $adoptedPromise ReactPromiseInterface */
$adoptedPromise = $promise->adoptedPromise;
return new Promise($adoptedPromise->then($onFulfilled, $onRejected), $this);
}
/**
* @inheritdoc
*/
public function create(callable $resolver)
{
$promise = new ReactPromise($resolver);
return new Promise($promise, $this);
}
/**
* @inheritdoc
*/
public function createFulfilled($value = null)
{
$promise = \React\Promise\resolve($value);
return new Promise($promise, $this);
}
/**
* @inheritdoc
*/
public function createRejected($reason)
{
$promise = \React\Promise\reject($reason);
return new Promise($promise, $this);
}
/**
* @inheritdoc
*/
public function all(array $promisesOrValues)
{
// TODO: rework with generators when PHP minimum required version is changed to 5.5+
$promisesOrValues = Utils::map($promisesOrValues, function ($item) {
return $item instanceof Promise ? $item->adoptedPromise : $item;
});
$promise = \React\Promise\all($promisesOrValues)->then(function($values) use ($promisesOrValues) {
$orderedResults = [];
foreach ($promisesOrValues as $key => $value) {
$orderedResults[$key] = $values[$key];
}
return $orderedResults;
});
return new Promise($promise, $this);
}
}

View File

@@ -0,0 +1,158 @@
<?php
namespace GraphQL\Executor\Promise\Adapter;
use GraphQL\Utils\Utils;
/**
* Class SyncPromise
*
* Simplistic (yet full-featured) implementation of Promises A+ spec for regular PHP `sync` mode
* (using queue to defer promises execution)
*
* @package GraphQL\Executor\Promise\Adapter
*/
class SyncPromise
{
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
/**
* @var \SplQueue
*/
public static $queue;
public static function getQueue()
{
return self::$queue ?: self::$queue = new \SplQueue();
}
public static function runQueue()
{
$q = self::$queue;
while ($q && !$q->isEmpty()) {
$task = $q->dequeue();
$task();
}
}
public $state = self::PENDING;
public $result;
/**
* Promises created in `then` method of this promise and awaiting for resolution of this promise
* @var array
*/
private $waiting = [];
public function reject($reason)
{
if (!$reason instanceof \Exception && !$reason instanceof \Throwable) {
throw new \Exception('SyncPromise::reject() has to be called with an instance of \Throwable');
}
switch ($this->state) {
case self::PENDING:
$this->state = self::REJECTED;
$this->result = $reason;
$this->enqueueWaitingPromises();
break;
case self::REJECTED:
if ($reason !== $this->result) {
throw new \Exception("Cannot change rejection reason");
}
break;
case self::FULFILLED:
throw new \Exception("Cannot reject fulfilled promise");
}
return $this;
}
public function resolve($value)
{
switch ($this->state) {
case self::PENDING:
if ($value === $this) {
throw new \Exception("Cannot resolve promise with self");
}
if (is_object($value) && method_exists($value, 'then')) {
$value->then(
function($resolvedValue) {
$this->resolve($resolvedValue);
},
function($reason) {
$this->reject($reason);
}
);
return $this;
}
$this->state = self::FULFILLED;
$this->result = $value;
$this->enqueueWaitingPromises();
break;
case self::FULFILLED:
if ($this->result !== $value) {
throw new \Exception("Cannot change value of fulfilled promise");
}
break;
case self::REJECTED:
throw new \Exception("Cannot resolve rejected promise");
}
return $this;
}
public function then(callable $onFulfilled = null, callable $onRejected = null)
{
if ($this->state === self::REJECTED && !$onRejected) {
return $this;
}
if ($this->state === self::FULFILLED && !$onFulfilled) {
return $this;
}
$tmp = new self();
$this->waiting[] = [$tmp, $onFulfilled, $onRejected];
if ($this->state !== self::PENDING) {
$this->enqueueWaitingPromises();
}
return $tmp;
}
private function enqueueWaitingPromises()
{
Utils::invariant($this->state !== self::PENDING, 'Cannot enqueue derived promises when parent is still pending');
foreach ($this->waiting as $descriptor) {
self::getQueue()->enqueue(function () use ($descriptor) {
/** @var $promise self */
list($promise, $onFulfilled, $onRejected) = $descriptor;
if ($this->state === self::FULFILLED) {
try {
$promise->resolve($onFulfilled ? $onFulfilled($this->result) : $this->result);
} catch (\Exception $e) {
$promise->reject($e);
} catch (\Throwable $e) {
$promise->reject($e);
}
} else if ($this->state === self::REJECTED) {
try {
if ($onRejected) {
$promise->resolve($onRejected($this->result));
} else {
$promise->reject($this->result);
}
} catch (\Exception $e) {
$promise->reject($e);
} catch (\Throwable $e) {
$promise->reject($e);
}
}
});
}
$this->waiting = [];
}
}

View File

@@ -0,0 +1,173 @@
<?php
namespace GraphQL\Executor\Promise\Adapter;
use GraphQL\Deferred;
use GraphQL\Error\InvariantViolation;
use GraphQL\Executor\Promise\Promise;
use GraphQL\Executor\Promise\PromiseAdapter;
use GraphQL\Utils\Utils;
/**
* Class SyncPromiseAdapter
*
* Allows changing order of field resolution even in sync environments
* (by leveraging queue of deferreds and promises)
*
* @package GraphQL\Executor\Promise\Adapter
*/
class SyncPromiseAdapter implements PromiseAdapter
{
/**
* @inheritdoc
*/
public function isThenable($value)
{
return $value instanceof Deferred;
}
/**
* @inheritdoc
*/
public function convertThenable($thenable)
{
if (!$thenable instanceof Deferred) {
throw new InvariantViolation('Expected instance of GraphQL\Deferred, got ' . Utils::printSafe($thenable));
}
return new Promise($thenable->promise, $this);
}
/**
* @inheritdoc
*/
public function then(Promise $promise, callable $onFulfilled = null, callable $onRejected = null)
{
/** @var SyncPromise $promise */
$promise = $promise->adoptedPromise;
return new Promise($promise->then($onFulfilled, $onRejected), $this);
}
/**
* @inheritdoc
*/
public function create(callable $resolver)
{
$promise = new SyncPromise();
try {
$resolver(
[$promise, 'resolve'],
[$promise, 'reject']
);
} catch (\Exception $e) {
$promise->reject($e);
} catch (\Throwable $e) {
$promise->reject($e);
}
return new Promise($promise, $this);
}
/**
* @inheritdoc
*/
public function createFulfilled($value = null)
{
$promise = new SyncPromise();
return new Promise($promise->resolve($value), $this);
}
/**
* @inheritdoc
*/
public function createRejected($reason)
{
$promise = new SyncPromise();
return new Promise($promise->reject($reason), $this);
}
/**
* @inheritdoc
*/
public function all(array $promisesOrValues)
{
$all = new SyncPromise();
$total = count($promisesOrValues);
$count = 0;
$result = [];
foreach ($promisesOrValues as $index => $promiseOrValue) {
if ($promiseOrValue instanceof Promise) {
$result[$index] = null;
$promiseOrValue->then(
function($value) use ($index, &$count, $total, &$result, $all) {
$result[$index] = $value;
$count++;
if ($count >= $total) {
$all->resolve($result);
}
},
[$all, 'reject']
);
} else {
$result[$index] = $promiseOrValue;
$count++;
}
}
if ($count === $total) {
$all->resolve($result);
}
return new Promise($all, $this);
}
/**
* Synchronously wait when promise completes
*
* @param Promise $promise
* @return mixed
*/
public function wait(Promise $promise)
{
$this->beforeWait($promise);
$dfdQueue = Deferred::getQueue();
$promiseQueue = SyncPromise::getQueue();
while (
$promise->adoptedPromise->state === SyncPromise::PENDING &&
!($dfdQueue->isEmpty() && $promiseQueue->isEmpty())
) {
Deferred::runQueue();
SyncPromise::runQueue();
$this->onWait($promise);
}
/** @var SyncPromise $syncPromise */
$syncPromise = $promise->adoptedPromise;
if ($syncPromise->state === SyncPromise::FULFILLED) {
return $syncPromise->result;
} else if ($syncPromise->state === SyncPromise::REJECTED) {
throw $syncPromise->result;
}
throw new InvariantViolation("Could not resolve promise");
}
/**
* Execute just before starting to run promise completion
*
* @param Promise $promise
*/
protected function beforeWait(Promise $promise)
{
}
/**
* Execute while running promise completion
*
* @param Promise $promise
*/
protected function onWait(Promise $promise)
{
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace GraphQL\Executor\Promise;
use GraphQL\Utils\Utils;
/**
* Convenience wrapper for promises represented by Promise Adapter
*/
class Promise
{
private $adapter;
public $adoptedPromise;
/**
* Promise constructor.
*
* @param mixed $adoptedPromise
* @param PromiseAdapter $adapter
*/
public function __construct($adoptedPromise, PromiseAdapter $adapter)
{
Utils::invariant(!$adoptedPromise instanceof self, 'Expecting promise from adapted system, got ' . __CLASS__);
$this->adapter = $adapter;
$this->adoptedPromise = $adoptedPromise;
}
/**
* @param callable|null $onFulfilled
* @param callable|null $onRejected
*
* @return Promise
*/
public function then(callable $onFulfilled = null, callable $onRejected = null)
{
return $this->adapter->then($this, $onFulfilled, $onRejected);
}
}

View File

@@ -0,0 +1,80 @@
<?php
namespace GraphQL\Executor\Promise;
/**
* Provides a means for integration of async PHP platforms ([related docs](data-fetching.md#async-php))
*/
interface PromiseAdapter
{
/**
* Return true if the value is a promise or a deferred of the underlying platform
*
* @api
* @param mixed $value
* @return bool
*/
public function isThenable($value);
/**
* Converts thenable of the underlying platform into GraphQL\Executor\Promise\Promise instance
*
* @api
* @param object $thenable
* @return Promise
*/
public function convertThenable($thenable);
/**
* Accepts our Promise wrapper, extracts adopted promise out of it and executes actual `then` logic described
* in Promises/A+ specs. Then returns new wrapped instance of GraphQL\Executor\Promise\Promise.
*
* @api
* @param Promise $promise
* @param callable|null $onFulfilled
* @param callable|null $onRejected
*
* @return Promise
*/
public function then(Promise $promise, callable $onFulfilled = null, callable $onRejected = null);
/**
* Creates a Promise
*
* Expected resolver signature:
* function(callable $resolve, callable $reject)
*
* @api
* @param callable $resolver
* @return Promise
*/
public function create(callable $resolver);
/**
* Creates a fulfilled Promise for a value if the value is not a promise.
*
* @api
* @param mixed $value
* @return Promise
*/
public function createFulfilled($value = null);
/**
* Creates a rejected promise for a reason if the reason is not a promise. If
* the provided reason is a promise, then it is returned as-is.
*
* @api
* @param \Throwable $reason
* @return Promise
*/
public function createRejected($reason);
/**
* Given an array of promises (or values), returns a promise that is fulfilled when all the
* items in the array are fulfilled.
*
* @api
* @param array $promisesOrValues Promises or values.
* @return Promise
*/
public function all(array $promisesOrValues);
}

View File

@@ -0,0 +1,385 @@
<?php
namespace GraphQL\Executor;
use GraphQL\Error\Error;
use GraphQL\Error\InvariantViolation;
use GraphQL\Language\AST\ArgumentNode;
use GraphQL\Language\AST\DirectiveNode;
use GraphQL\Language\AST\EnumValueDefinitionNode;
use GraphQL\Language\AST\FieldDefinitionNode;
use GraphQL\Language\AST\FieldNode;
use GraphQL\Language\AST\FragmentSpreadNode;
use GraphQL\Language\AST\InlineFragmentNode;
use GraphQL\Language\AST\NodeList;
use GraphQL\Language\AST\VariableNode;
use GraphQL\Language\AST\VariableDefinitionNode;
use GraphQL\Language\Printer;
use GraphQL\Type\Schema;
use GraphQL\Type\Definition\Directive;
use GraphQL\Type\Definition\FieldDefinition;
use GraphQL\Type\Definition\InputObjectType;
use GraphQL\Type\Definition\InputType;
use GraphQL\Type\Definition\LeafType;
use GraphQL\Type\Definition\ListOfType;
use GraphQL\Type\Definition\NonNull;
use GraphQL\Type\Definition\Type;
use GraphQL\Utils\AST;
use GraphQL\Utils\TypeInfo;
use GraphQL\Utils\Utils;
use GraphQL\Validator\DocumentValidator;
class Values
{
/**
* Prepares an object map of variables of the correct type based on the provided
* variable definitions and arbitrary input. If the input cannot be coerced
* to match the variable definitions, a Error will be thrown.
*
* @param Schema $schema
* @param VariableDefinitionNode[] $definitionNodes
* @param array $inputs
* @return array
* @throws Error
*/
public static function getVariableValues(Schema $schema, $definitionNodes, array $inputs)
{
$coercedValues = [];
foreach ($definitionNodes as $definitionNode) {
$varName = $definitionNode->variable->name->value;
$varType = TypeInfo::typeFromAST($schema, $definitionNode->type);
if (!Type::isInputType($varType)) {
throw new Error(
'Variable "$'.$varName.'" expected value of type ' .
'"' . Printer::doPrint($definitionNode->type) . '" which cannot be used as an input type.',
[$definitionNode->type]
);
}
if (!array_key_exists($varName, $inputs)) {
$defaultValue = $definitionNode->defaultValue;
if ($defaultValue) {
$coercedValues[$varName] = AST::valueFromAST($defaultValue, $varType);
}
if ($varType instanceof NonNull) {
throw new Error(
'Variable "$'.$varName .'" of required type ' .
'"'. Utils::printSafe($varType) . '" was not provided.',
[$definitionNode]
);
}
} else {
$value = $inputs[$varName];
$errors = self::isValidPHPValue($value, $varType);
if (!empty($errors)) {
$message = "\n" . implode("\n", $errors);
throw new Error(
'Variable "$' . $varName . '" got invalid value ' .
json_encode($value) . '.' . $message,
[$definitionNode]
);
}
$coercedValue = self::coerceValue($varType, $value);
Utils::invariant($coercedValue !== Utils::undefined(), 'Should have reported error.');
$coercedValues[$varName] = $coercedValue;
}
}
return $coercedValues;
}
/**
* Prepares an object map of argument values given a list of argument
* definitions and list of argument AST nodes.
*
* @param FieldDefinition|Directive $def
* @param FieldNode|\GraphQL\Language\AST\DirectiveNode $node
* @param $variableValues
* @return array
* @throws Error
*/
public static function getArgumentValues($def, $node, $variableValues = null)
{
$argDefs = $def->args;
$argNodes = $node->arguments;
if (!$argDefs || null === $argNodes) {
return [];
}
$coercedValues = [];
$undefined = Utils::undefined();
/** @var ArgumentNode[] $argNodeMap */
$argNodeMap = $argNodes ? Utils::keyMap($argNodes, function (ArgumentNode $arg) {
return $arg->name->value;
}) : [];
foreach ($argDefs as $argDef) {
$name = $argDef->name;
$argType = $argDef->getType();
$argumentNode = isset($argNodeMap[$name]) ? $argNodeMap[$name] : null;
if (!$argumentNode) {
if ($argDef->defaultValueExists()) {
$coercedValues[$name] = $argDef->defaultValue;
} else if ($argType instanceof NonNull) {
throw new Error(
'Argument "' . $name . '" of required type ' .
'"' . Utils::printSafe($argType) . '" was not provided.',
[$node]
);
}
} else if ($argumentNode->value instanceof VariableNode) {
$variableName = $argumentNode->value->name->value;
if ($variableValues && array_key_exists($variableName, $variableValues)) {
// Note: this does not check that this variable value is correct.
// This assumes that this query has been validated and the variable
// usage here is of the correct type.
$coercedValues[$name] = $variableValues[$variableName];
} else if ($argDef->defaultValueExists()) {
$coercedValues[$name] = $argDef->defaultValue;
} else if ($argType instanceof NonNull) {
throw new Error(
'Argument "' . $name . '" of required type "' . Utils::printSafe($argType) . '" was ' .
'provided the variable "$' . $variableName . '" which was not provided ' .
'a runtime value.',
[ $argumentNode->value ]
);
}
} else {
$valueNode = $argumentNode->value;
$coercedValue = AST::valueFromAST($valueNode, $argType, $variableValues);
if ($coercedValue === $undefined) {
$errors = DocumentValidator::isValidLiteralValue($argType, $valueNode);
$message = !empty($errors) ? ("\n" . implode("\n", $errors)) : '';
throw new Error(
'Argument "' . $name . '" got invalid value ' . Printer::doPrint($valueNode) . '.' . $message,
[ $argumentNode->value ]
);
}
$coercedValues[$name] = $coercedValue;
}
}
return $coercedValues;
}
/**
* Prepares an object map of argument values given a directive definition
* and a AST node which may contain directives. Optionally also accepts a map
* of variable values.
*
* If the directive does not exist on the node, returns undefined.
*
* @param Directive $directiveDef
* @param FragmentSpreadNode | FieldNode | InlineFragmentNode | EnumValueDefinitionNode | FieldDefinitionNode $node
* @param array|null $variableValues
*
* @return array|null
*/
public static function getDirectiveValues(Directive $directiveDef, $node, $variableValues = null)
{
if (isset($node->directives) && $node->directives instanceof NodeList) {
$directiveNode = Utils::find($node->directives, function(DirectiveNode $directive) use ($directiveDef) {
return $directive->name->value === $directiveDef->name;
});
if ($directiveNode) {
return self::getArgumentValues($directiveDef, $directiveNode, $variableValues);
}
}
return null;
}
/**
* @deprecated as of 8.0 (Moved to \GraphQL\Utils\AST::valueFromAST)
*
* @param $valueNode
* @param InputType $type
* @param null $variables
* @return array|null|\stdClass
*/
public static function valueFromAST($valueNode, InputType $type, $variables = null)
{
return AST::valueFromAST($valueNode, $type, $variables);
}
/**
* Given a PHP value and a GraphQL type, determine if the value will be
* accepted for that type. This is primarily useful for validating the
* runtime values of query variables.
*
* @param $value
* @param InputType $type
* @return array
*/
public static function isValidPHPValue($value, InputType $type)
{
// A value must be provided if the type is non-null.
if ($type instanceof NonNull) {
if (null === $value) {
return ['Expected "' . Utils::printSafe($type) . '", found null.'];
}
return self::isValidPHPValue($value, $type->getWrappedType());
}
if (null === $value) {
return [];
}
// Lists accept a non-list value as a list of one.
if ($type instanceof ListOfType) {
$itemType = $type->getWrappedType();
if (is_array($value)) {
$tmp = [];
foreach ($value as $index => $item) {
$errors = self::isValidPHPValue($item, $itemType);
$tmp = array_merge($tmp, Utils::map($errors, function ($error) use ($index) {
return "In element #$index: $error";
}));
}
return $tmp;
}
return self::isValidPHPValue($value, $itemType);
}
// Input objects check each defined field.
if ($type instanceof InputObjectType) {
if (!is_object($value) && !is_array($value)) {
return ["Expected \"{$type->name}\", found not an object."];
}
$fields = $type->getFields();
$errors = [];
// Ensure every provided field is defined.
$props = is_object($value) ? get_object_vars($value) : $value;
foreach ($props as $providedField => $tmp) {
if (!isset($fields[$providedField])) {
$errors[] = "In field \"{$providedField}\": Unknown field.";
}
}
// Ensure every defined field is valid.
foreach ($fields as $fieldName => $tmp) {
$newErrors = self::isValidPHPValue(isset($value[$fieldName]) ? $value[$fieldName] : null, $fields[$fieldName]->getType());
$errors = array_merge(
$errors,
Utils::map($newErrors, function ($error) use ($fieldName) {
return "In field \"{$fieldName}\": {$error}";
})
);
}
return $errors;
}
if ($type instanceof LeafType) {
try {
// Scalar/Enum input checks to ensure the type can parse the value to
// a non-null value.
$parseResult = $type->parseValue($value);
if (null === $parseResult && !$type->isValidValue($value)) {
$v = Utils::printSafeJson($value);
return [
"Expected type \"{$type->name}\", found $v."
];
}
return [];
} catch (\Exception $e) {
return [
"Expected type \"{$type->name}\", found " . Utils::printSafeJson($value) . ': ' .
$e->getMessage()
];
} catch (\Throwable $e) {
return [
"Expected type \"{$type->name}\", found " . Utils::printSafeJson($value) . ': ' .
$e->getMessage()
];
}
}
throw new InvariantViolation('Must be input type');
}
/**
* Given a type and any value, return a runtime value coerced to match the type.
*/
private static function coerceValue(Type $type, $value)
{
$undefined = Utils::undefined();
if ($value === $undefined) {
return $undefined;
}
if ($type instanceof NonNull) {
if ($value === null) {
// Intentionally return no value.
return $undefined;
}
return self::coerceValue($type->getWrappedType(), $value);
}
if (null === $value) {
return null;
}
if ($type instanceof ListOfType) {
$itemType = $type->getWrappedType();
if (is_array($value) || $value instanceof \Traversable) {
$coercedValues = [];
foreach ($value as $item) {
$itemValue = self::coerceValue($itemType, $item);
if ($undefined === $itemValue) {
// Intentionally return no value.
return $undefined;
}
$coercedValues[] = $itemValue;
}
return $coercedValues;
} else {
$coercedValue = self::coerceValue($itemType, $value);
if ($coercedValue === $undefined) {
// Intentionally return no value.
return $undefined;
}
return [$coercedValue];
}
}
if ($type instanceof InputObjectType) {
$coercedObj = [];
$fields = $type->getFields();
foreach ($fields as $fieldName => $field) {
if (!array_key_exists($fieldName, $value)) {
if ($field->defaultValueExists()) {
$coercedObj[$fieldName] = $field->defaultValue;
} else if ($field->getType() instanceof NonNull) {
// Intentionally return no value.
return $undefined;
}
continue;
}
$fieldValue = self::coerceValue($field->getType(), $value[$fieldName]);
if ($fieldValue === $undefined) {
// Intentionally return no value.
return $undefined;
}
$coercedObj[$fieldName] = $fieldValue;
}
return $coercedObj;
}
if ($type instanceof LeafType) {
$parsed = $type->parseValue($value);
if (null === $parsed) {
// null or invalid values represent a failure to parse correctly,
// in which case no value is returned.
return $undefined;
}
return $parsed;
}
throw new InvariantViolation('Must be input type');
}
}

View File

@@ -0,0 +1,300 @@
<?php
namespace GraphQL;
use GraphQL\Error\Error;
use GraphQL\Executor\ExecutionResult;
use GraphQL\Executor\Executor;
use GraphQL\Executor\Promise\Adapter\SyncPromiseAdapter;
use GraphQL\Executor\Promise\Promise;
use GraphQL\Language\AST\DocumentNode;
use GraphQL\Language\Parser;
use GraphQL\Language\Source;
use GraphQL\Executor\Promise\PromiseAdapter;
use GraphQL\Type\Definition\Directive;
use GraphQL\Type\Definition\Type;
use GraphQL\Validator\DocumentValidator;
use GraphQL\Validator\Rules\AbstractValidationRule;
use GraphQL\Validator\Rules\QueryComplexity;
/**
* This is the primary facade for fulfilling GraphQL operations.
* See [related documentation](executing-queries.md).
*/
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).
* context:
* The value provided as the third argument to all resolvers.
* Use this to pass current session, user data, etc
* 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)
*
* @api
* @param \GraphQL\Type\Schema $schema
* @param string|DocumentNode $source
* @param mixed $rootValue
* @param mixed $context
* @param array|null $variableValues
* @param string|null $operationName
* @param callable $fieldResolver
* @param array $validationRules
*
* @return ExecutionResult
*/
public static function executeQuery(
\GraphQL\Type\Schema $schema,
$source,
$rootValue = null,
$context = null,
$variableValues = null,
$operationName = null,
callable $fieldResolver = null,
array $validationRules = null
)
{
$promiseAdapter = new SyncPromiseAdapter();
$promise = self::promiseToExecute($promiseAdapter, $schema, $source, $rootValue, $context,
$variableValues, $operationName, $fieldResolver, $validationRules);
return $promiseAdapter->wait($promise);
}
/**
* Same as executeQuery(), but requires PromiseAdapter and always returns a Promise.
* Useful for Async PHP platforms.
*
* @api
* @param PromiseAdapter $promiseAdapter
* @param \GraphQL\Type\Schema $schema
* @param string|DocumentNode $source
* @param mixed $rootValue
* @param mixed $context
* @param array|null $variableValues
* @param string|null $operationName
* @param callable $fieldResolver
* @param array $validationRules
*
* @return Promise
*/
public static function promiseToExecute(
PromiseAdapter $promiseAdapter,
\GraphQL\Type\Schema $schema,
$source,
$rootValue = null,
$context = null,
$variableValues = null,
$operationName = null,
callable $fieldResolver = null,
array $validationRules = null
)
{
try {
if ($source instanceof DocumentNode) {
$documentNode = $source;
} else {
$documentNode = Parser::parse(new Source($source ?: '', 'GraphQL'));
}
// FIXME
if (!empty($validationRules)) {
foreach ($validationRules as $rule) {
if ($rule instanceof QueryComplexity) {
$rule->setRawVariableValues($variableValues);
}
}
} else {
/** @var QueryComplexity $queryComplexity */
$queryComplexity = DocumentValidator::getRule(QueryComplexity::class);
$queryComplexity->setRawVariableValues($variableValues);
}
$validationErrors = DocumentValidator::validate($schema, $documentNode, $validationRules);
if (!empty($validationErrors)) {
return $promiseAdapter->createFulfilled(
new ExecutionResult(null, $validationErrors)
);
} else {
return Executor::promiseToExecute(
$promiseAdapter,
$schema,
$documentNode,
$rootValue,
$context,
$variableValues,
$operationName,
$fieldResolver
);
}
} catch (Error $e) {
return $promiseAdapter->createFulfilled(
new ExecutionResult(null, [$e])
);
}
}
/**
* @deprecated Use executeQuery()->toArray() instead
*
* @param \GraphQL\Type\Schema $schema
* @param string|DocumentNode $source
* @param mixed $rootValue
* @param mixed $contextValue
* @param array|null $variableValues
* @param string|null $operationName
* @return Promise|array
*/
public static function execute(
\GraphQL\Type\Schema $schema,
$source,
$rootValue = null,
$contextValue = null,
$variableValues = null,
$operationName = null
)
{
$result = self::promiseToExecute(
$promiseAdapter = Executor::getPromiseAdapter(),
$schema,
$source,
$rootValue,
$contextValue,
$variableValues,
$operationName
);
if ($promiseAdapter instanceof SyncPromiseAdapter) {
$result = $promiseAdapter->wait($result)->toArray();
} else {
$result = $result->then(function(ExecutionResult $r) {
return $r->toArray();
});
}
return $result;
}
/**
* @deprecated renamed to executeQuery()
*
* @param \GraphQL\Type\Schema $schema
* @param string|DocumentNode $source
* @param mixed $rootValue
* @param mixed $contextValue
* @param array|null $variableValues
* @param string|null $operationName
*
* @return ExecutionResult|Promise
*/
public static function executeAndReturnResult(
\GraphQL\Type\Schema $schema,
$source,
$rootValue = null,
$contextValue = null,
$variableValues = null,
$operationName = null
)
{
$result = self::promiseToExecute(
$promiseAdapter = Executor::getPromiseAdapter(),
$schema,
$source,
$rootValue,
$contextValue,
$variableValues,
$operationName
);
if ($promiseAdapter instanceof SyncPromiseAdapter) {
$result = $promiseAdapter->wait($result);
}
return $result;
}
/**
* Returns directives defined in GraphQL spec
*
* @api
* @return Directive[]
*/
public static function getStandardDirectives()
{
return array_values(Directive::getInternalDirectives());
}
/**
* Returns types defined in GraphQL spec
*
* @api
* @return Type[]
*/
public static function getStandardTypes()
{
return array_values(Type::getInternalTypes());
}
/**
* Returns standard validation rules implementing GraphQL spec
*
* @api
* @return AbstractValidationRule[]
*/
public static function getStandardValidationRules()
{
return array_values(DocumentValidator::defaultRules());
}
/**
* @param callable $fn
*/
public static function setDefaultFieldResolver(callable $fn)
{
Executor::setDefaultFieldResolver($fn);
}
/**
* @param PromiseAdapter|null $promiseAdapter
*/
public static function setPromiseAdapter(PromiseAdapter $promiseAdapter = null)
{
Executor::setPromiseAdapter($promiseAdapter);
}
/**
* Returns directives defined in GraphQL spec
*
* @deprecated Renamed to getStandardDirectives
* @return Directive[]
*/
public static function getInternalDirectives()
{
return self::getStandardDirectives();
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace GraphQL\Language\AST;
class ArgumentNode extends Node
{
public $kind = NodeKind::ARGUMENT;
/**
* @var ValueNode
*/
public $value;
/**
* @var NameNode
*/
public $name;
}

View File

@@ -0,0 +1,13 @@
<?php
namespace GraphQL\Language\AST;
class BooleanValueNode extends Node implements ValueNode
{
public $kind = NodeKind::BOOLEAN;
/**
* @var string
*/
public $value;
}

View File

@@ -0,0 +1,11 @@
<?php
namespace GraphQL\Language\AST;
interface DefinitionNode
{
/**
* export type DefinitionNode = OperationDefinitionNode
* | FragmentDefinitionNode
* | TypeSystemDefinitionNode // experimental non-spec addition.
*/
}

View File

@@ -0,0 +1,25 @@
<?php
namespace GraphQL\Language\AST;
class DirectiveDefinitionNode extends Node implements TypeSystemDefinitionNode
{
/**
* @var string
*/
public $kind = NodeKind::DIRECTIVE_DEFINITION;
/**
* @var NameNode
*/
public $name;
/**
* @var ArgumentNode[]
*/
public $arguments;
/**
* @var NameNode[]
*/
public $locations;
}

View File

@@ -0,0 +1,17 @@
<?php
namespace GraphQL\Language\AST;
class DirectiveNode extends Node
{
public $kind = NodeKind::DIRECTIVE;
/**
* @var NameNode
*/
public $name;
/**
* @var ArgumentNode[]
*/
public $arguments;
}

View File

@@ -0,0 +1,12 @@
<?php
namespace GraphQL\Language\AST;
class DocumentNode extends Node
{
public $kind = NodeKind::DOCUMENT;
/**
* @var DefinitionNode[]
*/
public $definitions;
}

View File

@@ -0,0 +1,30 @@
<?php
namespace GraphQL\Language\AST;
class EnumTypeDefinitionNode extends Node implements TypeDefinitionNode
{
/**
* @var string
*/
public $kind = NodeKind::ENUM_TYPE_DEFINITION;
/**
* @var NameNode
*/
public $name;
/**
* @var DirectiveNode[]
*/
public $directives;
/**
* @var EnumValueDefinitionNode[]
*/
public $values;
/**
* @var string
*/
public $description;
}

View File

@@ -0,0 +1,25 @@
<?php
namespace GraphQL\Language\AST;
class EnumValueDefinitionNode extends Node
{
/**
* @var string
*/
public $kind = NodeKind::ENUM_VALUE_DEFINITION;
/**
* @var NameNode
*/
public $name;
/**
* @var DirectiveNode[]
*/
public $directives;
/**
* @var string
*/
public $description;
}

View File

@@ -0,0 +1,12 @@
<?php
namespace GraphQL\Language\AST;
class EnumValueNode extends Node implements ValueNode
{
public $kind = NodeKind::ENUM;
/**
* @var string
*/
public $value;
}

View File

@@ -0,0 +1,35 @@
<?php
namespace GraphQL\Language\AST;
class FieldDefinitionNode extends Node
{
/**
* @var string
*/
public $kind = NodeKind::FIELD_DEFINITION;
/**
* @var NameNode
*/
public $name;
/**
* @var InputValueDefinitionNode[]
*/
public $arguments;
/**
* @var TypeNode
*/
public $type;
/**
* @var DirectiveNode[]
*/
public $directives;
/**
* @var string
*/
public $description;
}

View File

@@ -0,0 +1,32 @@
<?php
namespace GraphQL\Language\AST;
class FieldNode extends Node implements SelectionNode
{
public $kind = NodeKind::FIELD;
/**
* @var NameNode
*/
public $name;
/**
* @var NameNode|null
*/
public $alias;
/**
* @var ArgumentNode[]|null
*/
public $arguments;
/**
* @var DirectiveNode[]|null
*/
public $directives;
/**
* @var SelectionSetNode|null
*/
public $selectionSet;
}

View File

@@ -0,0 +1,12 @@
<?php
namespace GraphQL\Language\AST;
class FloatValueNode extends Node implements ValueNode
{
public $kind = NodeKind::FLOAT;
/**
* @var string
*/
public $value;
}

View File

@@ -0,0 +1,27 @@
<?php
namespace GraphQL\Language\AST;
class FragmentDefinitionNode extends Node implements DefinitionNode, HasSelectionSet
{
public $kind = NodeKind::FRAGMENT_DEFINITION;
/**
* @var NameNode
*/
public $name;
/**
* @var NamedTypeNode
*/
public $typeCondition;
/**
* @var DirectiveNode[]
*/
public $directives;
/**
* @var SelectionSetNode
*/
public $selectionSet;
}

View File

@@ -0,0 +1,17 @@
<?php
namespace GraphQL\Language\AST;
class FragmentSpreadNode extends Node implements SelectionNode
{
public $kind = NodeKind::FRAGMENT_SPREAD;
/**
* @var NameNode
*/
public $name;
/**
* @var DirectiveNode[]
*/
public $directives;
}

View File

@@ -0,0 +1,10 @@
<?php
namespace GraphQL\Language\AST;
interface HasSelectionSet
{
/**
* export type DefinitionNode = OperationDefinitionNode
* | FragmentDefinitionNode
*/
}

View File

@@ -0,0 +1,22 @@
<?php
namespace GraphQL\Language\AST;
class InlineFragmentNode extends Node implements SelectionNode
{
public $kind = NodeKind::INLINE_FRAGMENT;
/**
* @var NamedTypeNode
*/
public $typeCondition;
/**
* @var DirectiveNode[]|null
*/
public $directives;
/**
* @var SelectionSetNode
*/
public $selectionSet;
}

View File

@@ -0,0 +1,30 @@
<?php
namespace GraphQL\Language\AST;
class InputObjectTypeDefinitionNode extends Node implements TypeDefinitionNode
{
/**
* @var string
*/
public $kind = NodeKind::INPUT_OBJECT_TYPE_DEFINITION;
/**
* @var NameNode
*/
public $name;
/**
* @var DirectiveNode[]
*/
public $directives;
/**
* @var InputValueDefinitionNode[]
*/
public $fields;
/**
* @var string
*/
public $description;
}

View File

@@ -0,0 +1,35 @@
<?php
namespace GraphQL\Language\AST;
class InputValueDefinitionNode extends Node
{
/**
* @var string
*/
public $kind = NodeKind::INPUT_VALUE_DEFINITION;
/**
* @var NameNode
*/
public $name;
/**
* @var TypeNode
*/
public $type;
/**
* @var ValueNode
*/
public $defaultValue;
/**
* @var DirectiveNode[]
*/
public $directives;
/**
* @var string
*/
public $description;
}

View File

@@ -0,0 +1,12 @@
<?php
namespace GraphQL\Language\AST;
class IntValueNode extends Node implements ValueNode
{
public $kind = NodeKind::INT;
/**
* @var string
*/
public $value;
}

View File

@@ -0,0 +1,30 @@
<?php
namespace GraphQL\Language\AST;
class InterfaceTypeDefinitionNode extends Node implements TypeDefinitionNode
{
/**
* @var string
*/
public $kind = NodeKind::INTERFACE_TYPE_DEFINITION;
/**
* @var NameNode
*/
public $name;
/**
* @var DirectiveNode[]
*/
public $directives;
/**
* @var FieldDefinitionNode[]
*/
public $fields = [];
/**
* @var string
*/
public $description;
}

View File

@@ -0,0 +1,12 @@
<?php
namespace GraphQL\Language\AST;
class ListTypeNode extends Node implements TypeNode
{
public $kind = NodeKind::LIST_TYPE;
/**
* @var Node
*/
public $type;
}

View File

@@ -0,0 +1,13 @@
<?php
namespace GraphQL\Language\AST;
class ListValueNode extends Node implements ValueNode
{
public $kind = NodeKind::LST;
/**
* @var ValueNode[]
*/
public $values;
}

View File

@@ -0,0 +1,72 @@
<?php
namespace GraphQL\Language\AST;
use GraphQL\Language\Source;
use GraphQL\Language\Token;
/**
* Contains a range of UTF-8 character offsets and token references that
* identify the region of the source from which the AST derived.
*/
class Location
{
/**
* The character offset at which this Node begins.
*
* @var int
*/
public $start;
/**
* The character offset at which this Node ends.
*
* @var int
*/
public $end;
/**
* The Token at which this Node begins.
*
* @var Token
*/
public $startToken;
/**
* The Token at which this Node ends.
*
* @var Token
*/
public $endToken;
/**
* The Source document the AST represents.
*
* @var Source|null
*/
public $source;
/**
* @param $start
* @param $end
* @return static
*/
public static function create($start, $end)
{
$tmp = new static();
$tmp->start = $start;
$tmp->end = $end;
return $tmp;
}
public function __construct(Token $startToken = null, Token $endToken = null, Source $source = null)
{
$this->startToken = $startToken;
$this->endToken = $endToken;
$this->source = $source;
if ($startToken && $endToken) {
$this->start = $startToken->start;
$this->end = $endToken->end;
}
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace GraphQL\Language\AST;
class NameNode extends Node implements TypeNode
{
public $kind = NodeKind::NAME;
/**
* @var string
*/
public $value;
}

View File

@@ -0,0 +1,12 @@
<?php
namespace GraphQL\Language\AST;
class NamedTypeNode extends Node implements TypeNode
{
public $kind = NodeKind::NAMED_TYPE;
/**
* @var NameNode
*/
public $name;
}

View File

@@ -0,0 +1,146 @@
<?php
namespace GraphQL\Language\AST;
use GraphQL\Error\InvariantViolation;
use GraphQL\Utils\Utils;
abstract class Node
{
/**
type Node = NameNode
| DocumentNode
| OperationDefinitionNode
| VariableDefinitionNode
| VariableNode
| SelectionSetNode
| FieldNode
| ArgumentNode
| FragmentSpreadNode
| InlineFragmentNode
| FragmentDefinitionNode
| IntValueNode
| FloatValueNode
| StringValueNode
| BooleanValueNode
| EnumValueNode
| ListValueNode
| ObjectValueNode
| ObjectFieldNode
| DirectiveNode
| ListTypeNode
| NonNullTypeNode
*/
public $kind;
/**
* @var Location
*/
public $loc;
/**
* @param array $vars
*/
public function __construct(array $vars)
{
if (!empty($vars)) {
Utils::assign($this, $vars);
}
}
/**
* @return $this
*/
public function cloneDeep()
{
return $this->cloneValue($this);
}
/**
* @param $value
* @return array|Node
*/
private function cloneValue($value)
{
if (is_array($value)) {
$cloned = [];
foreach ($value as $key => $arrValue) {
$cloned[$key] = $this->cloneValue($arrValue);
}
} else if ($value instanceof Node) {
$cloned = clone $value;
foreach (get_object_vars($cloned) as $prop => $propValue) {
$cloned->{$prop} = $this->cloneValue($propValue);
}
} else {
$cloned = $value;
}
return $cloned;
}
/**
* @return string
*/
public function __toString()
{
$tmp = $this->toArray(true);
return json_encode($tmp);
}
/**
* @param bool $recursive
* @return array
*/
public function toArray($recursive = false)
{
if ($recursive) {
return $this->recursiveToArray($this);
} else {
$tmp = (array) $this;
$tmp['loc'] = [
'start' => $this->loc->start,
'end' => $this->loc->end
];
return $tmp;
}
}
/**
* @param Node $node
* @return array
*/
private function recursiveToArray(Node $node)
{
$result = [
'kind' => $node->kind,
'loc' => [
'start' => $node->loc->start,
'end' => $node->loc->end
]
];
foreach (get_object_vars($node) as $prop => $propValue) {
if (isset($result[$prop]))
continue;
if (is_array($propValue) || $propValue instanceof NodeList) {
$tmp = [];
foreach ($propValue as $tmp1) {
$tmp[] = $tmp1 instanceof Node ? $this->recursiveToArray($tmp1) : (array) $tmp1;
}
} else if ($propValue instanceof Node) {
$tmp = $this->recursiveToArray($propValue);
} else if (is_scalar($propValue) || null === $propValue) {
$tmp = $propValue;
} else {
$tmp = null;
}
$result[$prop] = $tmp;
}
return $result;
}
}

View File

@@ -0,0 +1,135 @@
<?php
namespace GraphQL\Language\AST;
class NodeKind
{
// constants from language/kinds.js:
const NAME = 'Name';
// Document
const DOCUMENT = 'Document';
const OPERATION_DEFINITION = 'OperationDefinition';
const VARIABLE_DEFINITION = 'VariableDefinition';
const VARIABLE = 'Variable';
const SELECTION_SET = 'SelectionSet';
const FIELD = 'Field';
const ARGUMENT = 'Argument';
// Fragments
const FRAGMENT_SPREAD = 'FragmentSpread';
const INLINE_FRAGMENT = 'InlineFragment';
const FRAGMENT_DEFINITION = 'FragmentDefinition';
// Values
const INT = 'IntValue';
const FLOAT = 'FloatValue';
const STRING = 'StringValue';
const BOOLEAN = 'BooleanValue';
const ENUM = 'EnumValue';
const NULL = 'NullValue';
const LST = 'ListValue';
const OBJECT = 'ObjectValue';
const OBJECT_FIELD = 'ObjectField';
// Directives
const DIRECTIVE = 'Directive';
// Types
const NAMED_TYPE = 'NamedType';
const LIST_TYPE = 'ListType';
const NON_NULL_TYPE = 'NonNullType';
// Type System Definitions
const SCHEMA_DEFINITION = 'SchemaDefinition';
const OPERATION_TYPE_DEFINITION = 'OperationTypeDefinition';
// Type Definitions
const SCALAR_TYPE_DEFINITION = 'ScalarTypeDefinition';
const OBJECT_TYPE_DEFINITION = 'ObjectTypeDefinition';
const FIELD_DEFINITION = 'FieldDefinition';
const INPUT_VALUE_DEFINITION = 'InputValueDefinition';
const INTERFACE_TYPE_DEFINITION = 'InterfaceTypeDefinition';
const UNION_TYPE_DEFINITION = 'UnionTypeDefinition';
const ENUM_TYPE_DEFINITION = 'EnumTypeDefinition';
const ENUM_VALUE_DEFINITION = 'EnumValueDefinition';
const INPUT_OBJECT_TYPE_DEFINITION = 'InputObjectTypeDefinition';
// Type Extensions
const TYPE_EXTENSION_DEFINITION = 'TypeExtensionDefinition';
// Directive Definitions
const DIRECTIVE_DEFINITION = 'DirectiveDefinition';
/**
* @todo conver to const array when moving to PHP5.6
* @var array
*/
public static $classMap = [
NodeKind::NAME => NameNode::class,
// Document
NodeKind::DOCUMENT => DocumentNode::class,
NodeKind::OPERATION_DEFINITION => OperationDefinitionNode::class,
NodeKind::VARIABLE_DEFINITION => VariableDefinitionNode::class,
NodeKind::VARIABLE => VariableNode::class,
NodeKind::SELECTION_SET => SelectionSetNode::class,
NodeKind::FIELD => FieldNode::class,
NodeKind::ARGUMENT => ArgumentNode::class,
// Fragments
NodeKind::FRAGMENT_SPREAD => FragmentSpreadNode::class,
NodeKind::INLINE_FRAGMENT => InlineFragmentNode::class,
NodeKind::FRAGMENT_DEFINITION => FragmentDefinitionNode::class,
// Values
NodeKind::INT => IntValueNode::class,
NodeKind::FLOAT => FloatValueNode::class,
NodeKind::STRING => StringValueNode::class,
NodeKind::BOOLEAN => BooleanValueNode::class,
NodeKind::ENUM => EnumValueNode::class,
NodeKind::NULL => NullValueNode::class,
NodeKind::LST => ListValueNode::class,
NodeKind::OBJECT => ObjectValueNode::class,
NodeKind::OBJECT_FIELD => ObjectFieldNode::class,
// Directives
NodeKind::DIRECTIVE => DirectiveNode::class,
// Types
NodeKind::NAMED_TYPE => NamedTypeNode::class,
NodeKind::LIST_TYPE => ListTypeNode::class,
NodeKind::NON_NULL_TYPE => NonNullTypeNode::class,
// Type System Definitions
NodeKind::SCHEMA_DEFINITION => SchemaDefinitionNode::class,
NodeKind::OPERATION_TYPE_DEFINITION => OperationTypeDefinitionNode::class,
// Type Definitions
NodeKind::SCALAR_TYPE_DEFINITION => ScalarTypeDefinitionNode::class,
NodeKind::OBJECT_TYPE_DEFINITION => ObjectTypeDefinitionNode::class,
NodeKind::FIELD_DEFINITION => FieldDefinitionNode::class,
NodeKind::INPUT_VALUE_DEFINITION => InputValueDefinitionNode::class,
NodeKind::INTERFACE_TYPE_DEFINITION => InterfaceTypeDefinitionNode::class,
NodeKind::UNION_TYPE_DEFINITION => UnionTypeDefinitionNode::class,
NodeKind::ENUM_TYPE_DEFINITION => EnumTypeDefinitionNode::class,
NodeKind::ENUM_VALUE_DEFINITION => EnumValueDefinitionNode::class,
NodeKind::INPUT_OBJECT_TYPE_DEFINITION =>InputObjectTypeDefinitionNode::class,
// Type Extensions
NodeKind::TYPE_EXTENSION_DEFINITION => TypeExtensionDefinitionNode::class,
// Directive Definitions
NodeKind::DIRECTIVE_DEFINITION => DirectiveDefinitionNode::class
];
}

View File

@@ -0,0 +1,121 @@
<?php
namespace GraphQL\Language\AST;
use GraphQL\Utils\AST;
/**
* Class NodeList
*
* @package GraphQL\Utils
*/
class NodeList implements \ArrayAccess, \IteratorAggregate, \Countable
{
/**
* @var array
*/
private $nodes;
/**
* @param array $nodes
* @return static
*/
public static function create(array $nodes)
{
return new static($nodes);
}
/**
* NodeList constructor.
* @param array $nodes
*/
public function __construct(array $nodes)
{
$this->nodes = $nodes;
}
/**
* @param mixed $offset
* @return bool
*/
public function offsetExists($offset)
{
return isset($this->nodes[$offset]);
}
/**
* @param mixed $offset
* @return mixed
*/
public function offsetGet($offset)
{
$item = $this->nodes[$offset];
if (is_array($item) && isset($item['kind'])) {
$this->nodes[$offset] = $item = AST::fromArray($item);
}
return $item;
}
/**
* @param mixed $offset
* @param mixed $value
*/
public function offsetSet($offset, $value)
{
if (is_array($value) && isset($value['kind'])) {
$value = AST::fromArray($value);
}
$this->nodes[$offset] = $value;
}
/**
* @param mixed $offset
*/
public function offsetUnset($offset)
{
unset($this->nodes[$offset]);
}
/**
* @param int $offset
* @param int $length
* @param mixed $replacement
* @return NodeList
*/
public function splice($offset, $length, $replacement = null)
{
return new NodeList(array_splice($this->nodes, $offset, $length, $replacement));
}
/**
* @param $list
* @return NodeList
*/
public function merge($list)
{
if ($list instanceof NodeList) {
$list = $list->nodes;
}
return new NodeList(array_merge($this->nodes, $list));
}
/**
* @return \Generator
*/
public function getIterator()
{
$count = count($this->nodes);
for ($i = 0; $i < $count; $i++) {
yield $this->offsetGet($i);
}
}
/**
* @return int
*/
public function count()
{
return count($this->nodes);
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace GraphQL\Language\AST;
class NonNullTypeNode extends Node implements TypeNode
{
public $kind = NodeKind::NON_NULL_TYPE;
/**
* @var NameNode | ListTypeNode
*/
public $type;
}

View File

@@ -0,0 +1,7 @@
<?php
namespace GraphQL\Language\AST;
class NullValueNode extends Node implements ValueNode
{
public $kind = NodeKind::NULL;
}

View File

@@ -0,0 +1,18 @@
<?php
namespace GraphQL\Language\AST;
class ObjectFieldNode extends Node
{
public $kind = NodeKind::OBJECT_FIELD;
/**
* @var NameNode
*/
public $name;
/**
* @var ValueNode
*/
public $value;
}

View File

@@ -0,0 +1,35 @@
<?php
namespace GraphQL\Language\AST;
class ObjectTypeDefinitionNode extends Node implements TypeDefinitionNode
{
/**
* @var string
*/
public $kind = NodeKind::OBJECT_TYPE_DEFINITION;
/**
* @var NameNode
*/
public $name;
/**
* @var NamedTypeNode[]
*/
public $interfaces = [];
/**
* @var DirectiveNode[]
*/
public $directives;
/**
* @var FieldDefinitionNode[]
*/
public $fields;
/**
* @var string
*/
public $description;
}

View File

@@ -0,0 +1,12 @@
<?php
namespace GraphQL\Language\AST;
class ObjectValueNode extends Node implements ValueNode
{
public $kind = NodeKind::OBJECT;
/**
* @var ObjectFieldNode[]
*/
public $fields;
}

View File

@@ -0,0 +1,35 @@
<?php
namespace GraphQL\Language\AST;
class OperationDefinitionNode extends Node implements DefinitionNode, HasSelectionSet
{
/**
* @var string
*/
public $kind = NodeKind::OPERATION_DEFINITION;
/**
* @var NameNode
*/
public $name;
/**
* @var string (oneOf 'query', 'mutation'))
*/
public $operation;
/**
* @var VariableDefinitionNode[]
*/
public $variableDefinitions;
/**
* @var DirectiveNode[]
*/
public $directives;
/**
* @var SelectionSetNode
*/
public $selectionSet;
}

View File

@@ -0,0 +1,22 @@
<?php
namespace GraphQL\Language\AST;
class OperationTypeDefinitionNode extends Node
{
/**
* @var string
*/
public $kind = NodeKind::OPERATION_TYPE_DEFINITION;
/**
* One of 'query' | 'mutation' | 'subscription'
*
* @var string
*/
public $operation;
/**
* @var NamedTypeNode
*/
public $type;
}

View File

@@ -0,0 +1,25 @@
<?php
namespace GraphQL\Language\AST;
class ScalarTypeDefinitionNode extends Node implements TypeDefinitionNode
{
/**
* @var string
*/
public $kind = NodeKind::SCALAR_TYPE_DEFINITION;
/**
* @var NameNode
*/
public $name;
/**
* @var DirectiveNode[]
*/
public $directives;
/**
* @var string
*/
public $description;
}

View File

@@ -0,0 +1,20 @@
<?php
namespace GraphQL\Language\AST;
class SchemaDefinitionNode extends Node implements TypeSystemDefinitionNode
{
/**
* @var string
*/
public $kind = NodeKind::SCHEMA_DEFINITION;
/**
* @var DirectiveNode[]
*/
public $directives;
/**
* @var OperationTypeDefinitionNode[]
*/
public $operationTypes;
}

View File

@@ -0,0 +1,9 @@
<?php
namespace GraphQL\Language\AST;
interface SelectionNode
{
/**
* export type SelectionNode = FieldNode | FragmentSpreadNode | InlineFragmentNode
*/
}

View File

@@ -0,0 +1,12 @@
<?php
namespace GraphQL\Language\AST;
class SelectionSetNode extends Node
{
public $kind = NodeKind::SELECTION_SET;
/**
* @var SelectionNode[]
*/
public $selections;
}

View File

@@ -0,0 +1,12 @@
<?php
namespace GraphQL\Language\AST;
class StringValueNode extends Node implements ValueNode
{
public $kind = NodeKind::STRING;
/**
* @var string
*/
public $value;
}

View File

@@ -0,0 +1,14 @@
<?php
namespace GraphQL\Language\AST;
interface TypeDefinitionNode extends TypeSystemDefinitionNode
{
/**
export type TypeDefinitionNode = ScalarTypeDefinitionNode
| ObjectTypeDefinitionNode
| InterfaceTypeDefinitionNode
| UnionTypeDefinitionNode
| EnumTypeDefinitionNode
| InputObjectTypeDefinitionNode
*/
}

View File

@@ -0,0 +1,15 @@
<?php
namespace GraphQL\Language\AST;
class TypeExtensionDefinitionNode extends Node implements TypeSystemDefinitionNode
{
/**
* @var string
*/
public $kind = NodeKind::TYPE_EXTENSION_DEFINITION;
/**
* @var ObjectTypeDefinitionNode
*/
public $definition;
}

View File

@@ -0,0 +1,13 @@
<?php
namespace GraphQL\Language\AST;
interface TypeNode
{
/**
export type TypeNode = NamedTypeNode
| ListTypeNode
| NonNullTypeNode
*/
}

View File

@@ -0,0 +1,12 @@
<?php
namespace GraphQL\Language\AST;
interface TypeSystemDefinitionNode extends DefinitionNode
{
/**
export type TypeSystemDefinitionNode = SchemaDefinitionNode
| TypeDefinitionNode
| TypeExtensionDefinitionNode
| DirectiveDefinitionNode
*/
}

View File

@@ -0,0 +1,30 @@
<?php
namespace GraphQL\Language\AST;
class UnionTypeDefinitionNode extends Node implements TypeDefinitionNode
{
/**
* @var string
*/
public $kind = NodeKind::UNION_TYPE_DEFINITION;
/**
* @var NameNode
*/
public $name;
/**
* @var DirectiveNode[]
*/
public $directives;
/**
* @var NamedTypeNode[]
*/
public $types = [];
/**
* @var string
*/
public $description;
}

View File

@@ -0,0 +1,17 @@
<?php
namespace GraphQL\Language\AST;
/**
export type ValueNode = VariableNode
| IntValueNode
| FloatValueNode
| StringValueNode
| BooleanValueNode
| EnumValueNode
| ListValueNode
| ObjectValueNode
*/
interface ValueNode
{
}

View File

@@ -0,0 +1,22 @@
<?php
namespace GraphQL\Language\AST;
class VariableDefinitionNode extends Node implements DefinitionNode
{
public $kind = NodeKind::VARIABLE_DEFINITION;
/**
* @var VariableNode
*/
public $variable;
/**
* @var TypeNode
*/
public $type;
/**
* @var ValueNode|null
*/
public $defaultValue;
}

View File

@@ -0,0 +1,12 @@
<?php
namespace GraphQL\Language\AST;
class VariableNode extends Node
{
public $kind = NodeKind::VARIABLE;
/**
* @var NameNode
*/
public $name;
}

View File

@@ -0,0 +1,612 @@
<?php
namespace GraphQL\Language;
use GraphQL\Error\SyntaxError;
use GraphQL\Utils\Utils;
/**
* A Lexer is a stateful stream generator in that every time
* it is advanced, it returns the next token in the Source. Assuming the
* source lexes, the final Token emitted by the lexer will be of kind
* EOF, after which the lexer will repeatedly return the same EOF token
* whenever called.
*
* Algorithm is O(N) both on memory and time
*/
class Lexer
{
/**
* @var Source
*/
public $source;
/**
* @var array
*/
public $options;
/**
* The previously focused non-ignored token.
*
* @var Token
*/
public $lastToken;
/**
* The currently focused non-ignored token.
*
* @var Token
*/
public $token;
/**
* The (1-indexed) line containing the current token.
*
* @var int
*/
public $line;
/**
* The character offset at which the current line begins.
*
* @var int
*/
public $lineStart;
/**
* Current cursor position for UTF8 encoding of the source
*
* @var int
*/
private $position;
/**
* Current cursor position for ASCII representation of the source
*
* @var int
*/
private $byteStreamPosition;
/**
* Lexer constructor.
*
* @param Source $source
* @param array $options
*/
public function __construct(Source $source, array $options = [])
{
$startOfFileToken = new Token(Token::SOF, 0, 0, 0, 0, null);
$this->source = $source;
$this->options = $options;
$this->lastToken = $startOfFileToken;
$this->token = $startOfFileToken;
$this->line = 1;
$this->lineStart = 0;
$this->position = $this->byteStreamPosition = 0;
}
/**
* @return Token
*/
public function advance()
{
$token = $this->lastToken = $this->token;
if ($token->kind !== Token::EOF) {
do {
$token = $token->next = $this->readToken($token);
} while ($token->kind === Token::COMMENT);
$this->token = $token;
}
return $token;
}
/**
* @return Token
*/
public function nextToken()
{
trigger_error(__METHOD__ . ' is deprecated in favor of advance()', E_USER_DEPRECATED);
return $this->advance();
}
/**
* @param Token $prev
* @return Token
* @throws SyntaxError
*/
private function readToken(Token $prev)
{
$bodyLength = $this->source->length;
$this->positionAfterWhitespace();
$position = $this->position;
$line = $this->line;
$col = 1 + $position - $this->lineStart;
if ($position >= $bodyLength) {
return new Token(Token::EOF, $bodyLength, $bodyLength, $line, $col, $prev);
}
// Read next char and advance string cursor:
list (, $code, $bytes) = $this->readChar(true);
// SourceCharacter
if ($code < 0x0020 && $code !== 0x0009 && $code !== 0x000A && $code !== 0x000D) {
throw new SyntaxError(
$this->source,
$position,
'Cannot contain the invalid character ' . Utils::printCharCode($code)
);
}
switch ($code) {
case 33: // !
return new Token(Token::BANG, $position, $position + 1, $line, $col, $prev);
case 35: // #
$this->moveStringCursor(-1, -1 * $bytes);
return $this->readComment($line, $col, $prev);
case 36: // $
return new Token(Token::DOLLAR, $position, $position + 1, $line, $col, $prev);
case 40: // (
return new Token(Token::PAREN_L, $position, $position + 1, $line, $col, $prev);
case 41: // )
return new Token(Token::PAREN_R, $position, $position + 1, $line, $col, $prev);
case 46: // .
list (, $charCode1) = $this->readChar(true);
list (, $charCode2) = $this->readChar(true);
if ($charCode1 === 46 && $charCode2 === 46) {
return new Token(Token::SPREAD, $position, $position + 3, $line, $col, $prev);
}
break;
case 58: // :
return new Token(Token::COLON, $position, $position + 1, $line, $col, $prev);
case 61: // =
return new Token(Token::EQUALS, $position, $position + 1, $line, $col, $prev);
case 64: // @
return new Token(Token::AT, $position, $position + 1, $line, $col, $prev);
case 91: // [
return new Token(Token::BRACKET_L, $position, $position + 1, $line, $col, $prev);
case 93: // ]
return new Token(Token::BRACKET_R, $position, $position + 1, $line, $col, $prev);
case 123: // {
return new Token(Token::BRACE_L, $position, $position + 1, $line, $col, $prev);
case 124: // |
return new Token(Token::PIPE, $position, $position + 1, $line, $col, $prev);
case 125: // }
return new Token(Token::BRACE_R, $position, $position + 1, $line, $col, $prev);
// A-Z
case 65: case 66: case 67: case 68: case 69: case 70: case 71: case 72:
case 73: case 74: case 75: case 76: case 77: case 78: case 79: case 80:
case 81: case 82: case 83: case 84: case 85: case 86: case 87: case 88:
case 89: case 90:
// _
case 95:
// a-z
case 97: case 98: case 99: case 100: case 101: case 102: case 103: case 104:
case 105: case 106: case 107: case 108: case 109: case 110: case 111:
case 112: case 113: case 114: case 115: case 116: case 117: case 118:
case 119: case 120: case 121: case 122:
return $this->moveStringCursor(-1, -1 * $bytes)
->readName($line, $col, $prev);
// -
case 45:
// 0-9
case 48: case 49: case 50: case 51: case 52:
case 53: case 54: case 55: case 56: case 57:
return $this->moveStringCursor(-1, -1 * $bytes)
->readNumber($line, $col, $prev);
// "
case 34:
return $this->moveStringCursor(-1, -1 * $bytes)
->readString($line, $col, $prev);
}
$errMessage = $code === 39
? "Unexpected single quote character ('), did you mean to use ". 'a double quote (")?'
: 'Cannot parse the unexpected character ' . Utils::printCharCode($code) . '.';
throw new SyntaxError(
$this->source,
$position,
$errMessage
);
}
/**
* Reads an alphanumeric + underscore name from the source.
*
* [_A-Za-z][_0-9A-Za-z]*
*
* @param int $line
* @param int $col
* @param Token $prev
* @return Token
*/
private function readName($line, $col, Token $prev)
{
$value = '';
$start = $this->position;
list ($char, $code) = $this->readChar();
while ($code && (
$code === 95 || // _
$code >= 48 && $code <= 57 || // 0-9
$code >= 65 && $code <= 90 || // A-Z
$code >= 97 && $code <= 122 // a-z
)) {
$value .= $char;
list ($char, $code) = $this->moveStringCursor(1, 1)->readChar();
}
return new Token(
Token::NAME,
$start,
$this->position,
$line,
$col,
$prev,
$value
);
}
/**
* Reads a number token from the source file, either a float
* or an int depending on whether a decimal point appears.
*
* Int: -?(0|[1-9][0-9]*)
* Float: -?(0|[1-9][0-9]*)(\.[0-9]+)?((E|e)(+|-)?[0-9]+)?
*
* @param int $line
* @param int $col
* @param Token $prev
* @return Token
* @throws SyntaxError
*/
private function readNumber($line, $col, Token $prev)
{
$value = '';
$start = $this->position;
list ($char, $code) = $this->readChar();
$isFloat = false;
if ($code === 45) { // -
$value .= $char;
list ($char, $code) = $this->moveStringCursor(1, 1)->readChar();
}
// guard against leading zero's
if ($code === 48) { // 0
$value .= $char;
list ($char, $code) = $this->moveStringCursor(1, 1)->readChar();
if ($code >= 48 && $code <= 57) {
throw new SyntaxError($this->source, $this->position, "Invalid number, unexpected digit after 0: " . Utils::printCharCode($code));
}
} else {
$value .= $this->readDigits();
list ($char, $code) = $this->readChar();
}
if ($code === 46) { // .
$isFloat = true;
$this->moveStringCursor(1, 1);
$value .= $char;
$value .= $this->readDigits();
list ($char, $code) = $this->readChar();
}
if ($code === 69 || $code === 101) { // E e
$isFloat = true;
$value .= $char;
list ($char, $code) = $this->moveStringCursor(1, 1)->readChar();
if ($code === 43 || $code === 45) { // + -
$value .= $char;
$this->moveStringCursor(1, 1);
}
$value .= $this->readDigits();
}
return new Token(
$isFloat ? Token::FLOAT : Token::INT,
$start,
$this->position,
$line,
$col,
$prev,
$value
);
}
/**
* Returns string with all digits + changes current string cursor position to point to the first char after digits
*/
private function readDigits()
{
list ($char, $code) = $this->readChar();
if ($code >= 48 && $code <= 57) { // 0 - 9
$value = '';
do {
$value .= $char;
list ($char, $code) = $this->moveStringCursor(1, 1)->readChar();
} while ($code >= 48 && $code <= 57); // 0 - 9
return $value;
}
if ($this->position > $this->source->length - 1) {
$code = null;
}
throw new SyntaxError(
$this->source,
$this->position,
'Invalid number, expected digit but got: ' . Utils::printCharCode($code)
);
}
/**
* @param int $line
* @param int $col
* @param Token $prev
* @return Token
* @throws SyntaxError
*/
private function readString($line, $col, Token $prev)
{
$start = $this->position;
// Skip leading quote and read first string char:
list ($char, $code, $bytes) = $this->moveStringCursor(1, 1)->readChar();
$chunk = '';
$value = '';
while (
$code &&
// not LineTerminator
$code !== 10 && $code !== 13 &&
// not Quote (")
$code !== 34
) {
$this->assertValidStringCharacterCode($code, $this->position);
$this->moveStringCursor(1, $bytes);
if ($code === 92) { // \
$value .= $chunk;
list (, $code) = $this->readChar(true);
switch ($code) {
case 34: $value .= '"'; break;
case 47: $value .= '/'; break;
case 92: $value .= '\\'; break;
case 98: $value .= chr(8); break; // \b (backspace)
case 102: $value .= "\f"; break;
case 110: $value .= "\n"; break;
case 114: $value .= "\r"; break;
case 116: $value .= "\t"; break;
case 117:
$position = $this->position;
list ($hex) = $this->readChars(4, true);
if (!preg_match('/[0-9a-fA-F]{4}/', $hex)) {
throw new SyntaxError(
$this->source,
$position - 1,
'Invalid character escape sequence: \\u' . $hex
);
}
$code = hexdec($hex);
$this->assertValidStringCharacterCode($code, $position - 2);
$value .= Utils::chr($code);
break;
default:
throw new SyntaxError(
$this->source,
$this->position - 1,
'Invalid character escape sequence: \\' . Utils::chr($code)
);
}
$chunk = '';
} else {
$chunk .= $char;
}
list ($char, $code, $bytes) = $this->readChar();
}
if ($code !== 34) {
throw new SyntaxError(
$this->source,
$this->position,
'Unterminated string.'
);
}
$value .= $chunk;
// Skip trailing quote:
$this->moveStringCursor(1, 1);
return new Token(
Token::STRING,
$start,
$this->position,
$line,
$col,
$prev,
$value
);
}
private function assertValidStringCharacterCode($code, $position)
{
// SourceCharacter
if ($code < 0x0020 && $code !== 0x0009) {
throw new SyntaxError(
$this->source,
$position,
'Invalid character within String: ' . Utils::printCharCode($code)
);
}
}
/**
* Reads from body starting at startPosition until it finds a non-whitespace
* or commented character, then places cursor to the position of that character.
*/
private function positionAfterWhitespace()
{
while ($this->position < $this->source->length) {
list(, $code, $bytes) = $this->readChar();
// Skip whitespace
// tab | space | comma | BOM
if ($code === 9 || $code === 32 || $code === 44 || $code === 0xFEFF) {
$this->moveStringCursor(1, $bytes);
} else if ($code === 10) { // new line
$this->moveStringCursor(1, $bytes);
$this->line++;
$this->lineStart = $this->position;
} else if ($code === 13) { // carriage return
list(, $nextCode, $nextBytes) = $this->moveStringCursor(1, $bytes)->readChar();
if ($nextCode === 10) { // lf after cr
$this->moveStringCursor(1, $nextBytes);
}
$this->line++;
$this->lineStart = $this->position;
} else {
break;
}
}
}
/**
* Reads a comment token from the source file.
*
* #[\u0009\u0020-\uFFFF]*
*
* @param $line
* @param $col
* @param Token $prev
* @return Token
*/
private function readComment($line, $col, Token $prev)
{
$start = $this->position;
$value = '';
$bytes = 1;
do {
list ($char, $code, $bytes) = $this->moveStringCursor(1, $bytes)->readChar();
$value .= $char;
} while (
$code &&
// SourceCharacter but not LineTerminator
($code > 0x001F || $code === 0x0009)
);
return new Token(
Token::COMMENT,
$start,
$this->position,
$line,
$col,
$prev,
$value
);
}
/**
* Reads next UTF8Character from the byte stream, starting from $byteStreamPosition.
*
* @param bool $advance
* @param int $byteStreamPosition
* @return array
*/
private function readChar($advance = false, $byteStreamPosition = null)
{
if ($byteStreamPosition === null) {
$byteStreamPosition = $this->byteStreamPosition;
}
$code = 0;
$utf8char = '';
$bytes = 0;
$positionOffset = 0;
if (isset($this->source->body[$byteStreamPosition])) {
$ord = ord($this->source->body[$byteStreamPosition]);
if ($ord < 128) {
$bytes = 1;
} else if ($ord < 224) {
$bytes = 2;
} elseif ($ord < 240) {
$bytes = 3;
} else {
$bytes = 4;
}
$utf8char = '';
for ($pos = $byteStreamPosition; $pos < $byteStreamPosition + $bytes; $pos++) {
$utf8char .= $this->source->body[$pos];
}
$positionOffset = 1;
$code = $bytes === 1 ? $ord : Utils::ord($utf8char);
}
if ($advance) {
$this->moveStringCursor($positionOffset, $bytes);
}
return [$utf8char, $code, $bytes];
}
/**
* Reads next $numberOfChars UTF8 characters from the byte stream, starting from $byteStreamPosition.
*
* @param $numberOfChars
* @param bool $advance
* @param null $byteStreamPosition
* @return array
*/
private function readChars($numberOfChars, $advance = false, $byteStreamPosition = null)
{
$result = '';
$totalBytes = 0;
$byteOffset = $byteStreamPosition ?: $this->byteStreamPosition;
for ($i = 0; $i < $numberOfChars; $i++) {
list ($char, $code, $bytes) = $this->readChar(false, $byteOffset);
$totalBytes += $bytes;
$byteOffset += $bytes;
$result .= $char;
}
if ($advance) {
$this->moveStringCursor($numberOfChars, $totalBytes);
}
return [$result, $totalBytes];
}
/**
* Moves internal string cursor position
*
* @param $positionOffset
* @param $byteStreamOffset
* @return $this
*/
private function moveStringCursor($positionOffset, $byteStreamOffset)
{
$this->position += $positionOffset;
$this->byteStreamPosition += $byteStreamOffset;
return $this;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,310 @@
<?php
namespace GraphQL\Language;
use GraphQL\Language\AST\ArgumentNode;
use GraphQL\Language\AST\DirectiveDefinitionNode;
use GraphQL\Language\AST\EnumTypeDefinitionNode;
use GraphQL\Language\AST\EnumValueDefinitionNode;
use GraphQL\Language\AST\FieldDefinitionNode;
use GraphQL\Language\AST\InputObjectTypeDefinitionNode;
use GraphQL\Language\AST\InputValueDefinitionNode;
use GraphQL\Language\AST\InterfaceTypeDefinitionNode;
use GraphQL\Language\AST\ListValueNode;
use GraphQL\Language\AST\BooleanValueNode;
use GraphQL\Language\AST\DirectiveNode;
use GraphQL\Language\AST\DocumentNode;
use GraphQL\Language\AST\EnumValueNode;
use GraphQL\Language\AST\FieldNode;
use GraphQL\Language\AST\FloatValueNode;
use GraphQL\Language\AST\FragmentDefinitionNode;
use GraphQL\Language\AST\FragmentSpreadNode;
use GraphQL\Language\AST\InlineFragmentNode;
use GraphQL\Language\AST\IntValueNode;
use GraphQL\Language\AST\ListTypeNode;
use GraphQL\Language\AST\NamedTypeNode;
use GraphQL\Language\AST\Node;
use GraphQL\Language\AST\NodeKind;
use GraphQL\Language\AST\NonNullTypeNode;
use GraphQL\Language\AST\NullValueNode;
use GraphQL\Language\AST\ObjectFieldNode;
use GraphQL\Language\AST\ObjectTypeDefinitionNode;
use GraphQL\Language\AST\ObjectValueNode;
use GraphQL\Language\AST\OperationDefinitionNode;
use GraphQL\Language\AST\OperationTypeDefinitionNode;
use GraphQL\Language\AST\ScalarTypeDefinitionNode;
use GraphQL\Language\AST\SchemaDefinitionNode;
use GraphQL\Language\AST\SelectionSetNode;
use GraphQL\Language\AST\StringValueNode;
use GraphQL\Language\AST\TypeExtensionDefinitionNode;
use GraphQL\Language\AST\UnionTypeDefinitionNode;
use GraphQL\Language\AST\VariableDefinitionNode;
use GraphQL\Utils\Utils;
/**
* Prints AST to string. Capable of printing GraphQL queries and Type definition language.
* Useful for pretty-printing queries or printing back AST for logging, documentation, etc.
*
* Usage example:
*
* ```php
* $query = 'query myQuery {someField}';
* $ast = GraphQL\Language\Parser::parse($query);
* $printed = GraphQL\Language\Printer::doPrint($ast);
* ```
*/
class Printer
{
/**
* Prints AST to string. Capable of printing GraphQL queries and Type definition language.
*
* @api
* @param Node $ast
* @return string
*/
public static function doPrint($ast)
{
static $instance;
$instance = $instance ?: new static();
return $instance->printAST($ast);
}
protected function __construct()
{}
public function printAST($ast)
{
return Visitor::visit($ast, [
'leave' => [
NodeKind::NAME => function(Node $node) {
return '' . $node->value;
},
NodeKind::VARIABLE => function($node) {
return '$' . $node->name;
},
NodeKind::DOCUMENT => function(DocumentNode $node) {
return $this->join($node->definitions, "\n\n") . "\n";
},
NodeKind::OPERATION_DEFINITION => function(OperationDefinitionNode $node) {
$op = $node->operation;
$name = $node->name;
$varDefs = $this->wrap('(', $this->join($node->variableDefinitions, ', '), ')');
$directives = $this->join($node->directives, ' ');
$selectionSet = $node->selectionSet;
// Anonymous queries with no directives or variable definitions can use
// the query short form.
return !$name && !$directives && !$varDefs && $op === 'query'
? $selectionSet
: $this->join([$op, $this->join([$name, $varDefs]), $directives, $selectionSet], ' ');
},
NodeKind::VARIABLE_DEFINITION => function(VariableDefinitionNode $node) {
return $node->variable . ': ' . $node->type . $this->wrap(' = ', $node->defaultValue);
},
NodeKind::SELECTION_SET => function(SelectionSetNode $node) {
return $this->block($node->selections);
},
NodeKind::FIELD => function(FieldNode $node) {
return $this->join([
$this->wrap('', $node->alias, ': ') . $node->name . $this->wrap('(', $this->join($node->arguments, ', '), ')'),
$this->join($node->directives, ' '),
$node->selectionSet
], ' ');
},
NodeKind::ARGUMENT => function(ArgumentNode $node) {
return $node->name . ': ' . $node->value;
},
// Fragments
NodeKind::FRAGMENT_SPREAD => function(FragmentSpreadNode $node) {
return '...' . $node->name . $this->wrap(' ', $this->join($node->directives, ' '));
},
NodeKind::INLINE_FRAGMENT => function(InlineFragmentNode $node) {
return $this->join([
"...",
$this->wrap('on ', $node->typeCondition),
$this->join($node->directives, ' '),
$node->selectionSet
], ' ');
},
NodeKind::FRAGMENT_DEFINITION => function(FragmentDefinitionNode $node) {
return "fragment {$node->name} on {$node->typeCondition} "
. $this->wrap('', $this->join($node->directives, ' '), ' ')
. $node->selectionSet;
},
// Value
NodeKind::INT => function(IntValueNode $node) {
return $node->value;
},
NodeKind::FLOAT => function(FloatValueNode $node) {
return $node->value;
},
NodeKind::STRING => function(StringValueNode $node) {
return json_encode($node->value);
},
NodeKind::BOOLEAN => function(BooleanValueNode $node) {
return $node->value ? 'true' : 'false';
},
NodeKind::NULL => function(NullValueNode $node) {
return 'null';
},
NodeKind::ENUM => function(EnumValueNode $node) {
return $node->value;
},
NodeKind::LST => function(ListValueNode $node) {
return '[' . $this->join($node->values, ', ') . ']';
},
NodeKind::OBJECT => function(ObjectValueNode $node) {
return '{' . $this->join($node->fields, ', ') . '}';
},
NodeKind::OBJECT_FIELD => function(ObjectFieldNode $node) {
return $node->name . ': ' . $node->value;
},
// DirectiveNode
NodeKind::DIRECTIVE => function(DirectiveNode $node) {
return '@' . $node->name . $this->wrap('(', $this->join($node->arguments, ', '), ')');
},
// Type
NodeKind::NAMED_TYPE => function(NamedTypeNode $node) {
return $node->name;
},
NodeKind::LIST_TYPE => function(ListTypeNode $node) {
return '[' . $node->type . ']';
},
NodeKind::NON_NULL_TYPE => function(NonNullTypeNode $node) {
return $node->type . '!';
},
// Type System Definitions
NodeKind::SCHEMA_DEFINITION => function(SchemaDefinitionNode $def) {
return $this->join([
'schema',
$this->join($def->directives, ' '),
$this->block($def->operationTypes)
], ' ');
},
NodeKind::OPERATION_TYPE_DEFINITION => function(OperationTypeDefinitionNode $def) {
return $def->operation . ': ' . $def->type;
},
NodeKind::SCALAR_TYPE_DEFINITION => function(ScalarTypeDefinitionNode $def) {
return $this->join(['scalar', $def->name, $this->join($def->directives, ' ')], ' ');
},
NodeKind::OBJECT_TYPE_DEFINITION => function(ObjectTypeDefinitionNode $def) {
return $this->join([
'type',
$def->name,
$this->wrap('implements ', $this->join($def->interfaces, ', ')),
$this->join($def->directives, ' '),
$this->block($def->fields)
], ' ');
},
NodeKind::FIELD_DEFINITION => function(FieldDefinitionNode $def) {
return $def->name
. $this->wrap('(', $this->join($def->arguments, ', '), ')')
. ': ' . $def->type
. $this->wrap(' ', $this->join($def->directives, ' '));
},
NodeKind::INPUT_VALUE_DEFINITION => function(InputValueDefinitionNode $def) {
return $this->join([
$def->name . ': ' . $def->type,
$this->wrap('= ', $def->defaultValue),
$this->join($def->directives, ' ')
], ' ');
},
NodeKind::INTERFACE_TYPE_DEFINITION => function(InterfaceTypeDefinitionNode $def) {
return $this->join([
'interface',
$def->name,
$this->join($def->directives, ' '),
$this->block($def->fields)
], ' ');
},
NodeKind::UNION_TYPE_DEFINITION => function(UnionTypeDefinitionNode $def) {
return $this->join([
'union',
$def->name,
$this->join($def->directives, ' '),
'= ' . $this->join($def->types, ' | ')
], ' ');
},
NodeKind::ENUM_TYPE_DEFINITION => function(EnumTypeDefinitionNode $def) {
return $this->join([
'enum',
$def->name,
$this->join($def->directives, ' '),
$this->block($def->values)
], ' ');
},
NodeKind::ENUM_VALUE_DEFINITION => function(EnumValueDefinitionNode $def) {
return $this->join([
$def->name,
$this->join($def->directives, ' ')
], ' ');
},
NodeKind::INPUT_OBJECT_TYPE_DEFINITION => function(InputObjectTypeDefinitionNode $def) {
return $this->join([
'input',
$def->name,
$this->join($def->directives, ' '),
$this->block($def->fields)
], ' ');
},
NodeKind::TYPE_EXTENSION_DEFINITION => function(TypeExtensionDefinitionNode $def) {
return "extend {$def->definition}";
},
NodeKind::DIRECTIVE_DEFINITION => function(DirectiveDefinitionNode $def) {
return 'directive @' . $def->name . $this->wrap('(', $this->join($def->arguments, ', '), ')')
. ' on ' . $this->join($def->locations, ' | ');
}
]
]);
}
/**
* If maybeString is not null or empty, then wrap with start and end, otherwise
* print an empty string.
*/
public function wrap($start, $maybeString, $end = '')
{
return $maybeString ? ($start . $maybeString . $end) : '';
}
/**
* Given array, print each item on its own line, wrapped in an
* indented "{ }" block.
*/
public function block($array)
{
return $array && $this->length($array) ? $this->indent("{\n" . $this->join($array, "\n")) . "\n}" : '{}';
}
public function indent($maybeString)
{
return $maybeString ? str_replace("\n", "\n ", $maybeString) : '';
}
public function manyList($start, $list, $separator, $end)
{
return $this->length($list) === 0 ? null : ($start . $this->join($list, $separator) . $end);
}
public function length($maybeArray)
{
return $maybeArray ? count($maybeArray) : 0;
}
public function join($maybeArray, $separator = '')
{
return $maybeArray
? implode(
$separator,
Utils::filter(
$maybeArray,
function($x) { return !!$x;}
)
)
: '';
}
}

View File

@@ -0,0 +1,89 @@
<?php
namespace GraphQL\Language;
use GraphQL\Utils\Utils;
/**
* Class Source
* @package GraphQL\Language
*/
class Source
{
/**
* @var string
*/
public $body;
/**
* @var int
*/
public $length;
/**
* @var string
*/
public $name;
/**
* @var SourceLocation
*/
public $locationOffset;
/**
* Source constructor.
*
* A representation of source input to GraphQL.
* `name` and `locationOffset` are optional. They are useful for clients who
* store GraphQL documents in source files; for example, if the GraphQL input
* starts at line 40 in a file named Foo.graphql, it might be useful for name to
* be "Foo.graphql" and location to be `{ line: 40, column: 0 }`.
* line and column in locationOffset are 1-indexed
*
* @param $body
* @param null $name
* @param SourceLocation|null $location
*/
public function __construct($body, $name = null, SourceLocation $location = null)
{
Utils::invariant(
is_string($body),
'GraphQL query body is expected to be string, but got ' . Utils::getVariableType($body)
);
$this->body = $body;
$this->length = mb_strlen($body, 'UTF-8');
$this->name = $name ?: 'GraphQL';
$this->locationOffset = $location ?: new SourceLocation(1, 1);
Utils::invariant(
$this->locationOffset->line > 0,
'line in locationOffset is 1-indexed and must be positive'
);
Utils::invariant(
$this->locationOffset->column > 0,
'column in locationOffset is 1-indexed and must be positive'
);
}
/**
* @param $position
* @return SourceLocation
*/
public function getLocation($position)
{
$line = 1;
$column = $position + 1;
$utfChars = json_decode('"\u2028\u2029"');
$lineRegexp = '/\r\n|[\n\r'.$utfChars.']/su';
$matches = [];
preg_match_all($lineRegexp, mb_substr($this->body, 0, $position, 'UTF-8'), $matches, PREG_OFFSET_CAPTURE);
foreach ($matches[0] as $index => $match) {
$line += 1;
$column = $position + 1 - ($match[1] + mb_strlen($match[0], 'UTF-8'));
}
return new SourceLocation($line, $column);
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace GraphQL\Language;
class SourceLocation implements \JsonSerializable
{
public $line;
public $column;
public function __construct($line, $col)
{
$this->line = $line;
$this->column = $col;
}
/**
* @return array
*/
public function toArray()
{
return [
'line' => $this->line,
'column' => $this->column
];
}
/**
* @return array
*/
public function toSerializableArray()
{
return $this->toArray();
}
/**
* Specify data which should be serialized to JSON
* @link http://php.net/manual/en/jsonserializable.jsonserialize.php
* @return mixed data which can be serialized by <b>json_encode</b>,
* which is a value of any type other than a resource.
* @since 5.4.0
*/
function jsonSerialize()
{
return $this->toSerializableArray();
}
}

View File

@@ -0,0 +1,161 @@
<?php
namespace GraphQL\Language;
/**
* Represents a range of characters represented by a lexical token
* within a Source.
*/
class Token
{
// Each kind of token.
const SOF = '<SOF>';
const EOF = '<EOF>';
const BANG = '!';
const DOLLAR = '$';
const PAREN_L = '(';
const PAREN_R = ')';
const SPREAD = '...';
const COLON = ':';
const EQUALS = '=';
const AT = '@';
const BRACKET_L = '[';
const BRACKET_R = ']';
const BRACE_L = '{';
const PIPE = '|';
const BRACE_R = '}';
const NAME = 'Name';
const INT = 'Int';
const FLOAT = 'Float';
const STRING = 'String';
const COMMENT = 'Comment';
/**
* @param $kind
* @return mixed
*/
public static function getKindDescription($kind)
{
trigger_error('Deprecated as of 16.10.2016 ($kind itself contains description string now)', E_USER_DEPRECATED);
$description = [];
$description[self::SOF] = '<SOF>';
$description[self::EOF] = '<EOF>';
$description[self::BANG] = '!';
$description[self::DOLLAR] = '$';
$description[self::PAREN_L] = '(';
$description[self::PAREN_R] = ')';
$description[self::SPREAD] = '...';
$description[self::COLON] = ':';
$description[self::EQUALS] = '=';
$description[self::AT] = '@';
$description[self::BRACKET_L] = '[';
$description[self::BRACKET_R] = ']';
$description[self::BRACE_L] = '{';
$description[self::PIPE] = '|';
$description[self::BRACE_R] = '}';
$description[self::NAME] = 'Name';
$description[self::INT] = 'Int';
$description[self::FLOAT] = 'Float';
$description[self::STRING] = 'String';
$description[self::COMMENT] = 'Comment';
return $description[$kind];
}
/**
* The kind of Token (see one of constants above).
*
* @var string
*/
public $kind;
/**
* The character offset at which this Node begins.
*
* @var int
*/
public $start;
/**
* The character offset at which this Node ends.
*
* @var int
*/
public $end;
/**
* The 1-indexed line number on which this Token appears.
*
* @var int
*/
public $line;
/**
* The 1-indexed column number at which this Token begins.
*
* @var int
*/
public $column;
/**
* @var string|null
*/
public $value;
/**
* Tokens exist as nodes in a double-linked-list amongst all tokens
* including ignored tokens. <SOF> is always the first node and <EOF>
* the last.
*
* @var Token
*/
public $prev;
/**
* @var Token
*/
public $next;
/**
* Token constructor.
* @param $kind
* @param $start
* @param $end
* @param $line
* @param $column
* @param Token $previous
* @param null $value
*/
public function __construct($kind, $start, $end, $line, $column, Token $previous = null, $value = null)
{
$this->kind = $kind;
$this->start = (int) $start;
$this->end = (int) $end;
$this->line = (int) $line;
$this->column = (int) $column;
$this->prev = $previous;
$this->next = null;
$this->value = $value;
}
/**
* @return string
*/
public function getDescription()
{
return $this->kind . ($this->value ? ' "' . $this->value . '"' : '');
}
/**
* @return array
*/
public function toArray()
{
return [
'kind' => $this->kind,
'value' => $this->value,
'line' => $this->line,
'column' => $this->column
];
}
}

View File

@@ -0,0 +1,486 @@
<?php
namespace GraphQL\Language;
use GraphQL\Language\AST\Node;
use GraphQL\Language\AST\NodeKind;
use GraphQL\Language\AST\NodeList;
use GraphQL\Utils\TypeInfo;
class VisitorOperation
{
public $doBreak;
public $doContinue;
public $removeNode;
}
/**
* Utility for efficient AST traversal and modification.
*
* `visit()` will walk through an AST using a depth first traversal, calling
* the visitor's enter function at each node in the traversal, and calling the
* leave function after visiting that node and all of it's child nodes.
*
* By returning different values from the enter and leave functions, the
* behavior of the visitor can be altered, including skipping over a sub-tree of
* the AST (by returning false), editing the AST by returning a value or null
* to remove the value, or to stop the whole traversal by returning BREAK.
*
* When using `visit()` to edit an AST, the original AST will not be modified, and
* a new version of the AST with the changes applied will be returned from the
* visit function.
*
* $editedAST = Visitor::visit($ast, [
* 'enter' => function ($node, $key, $parent, $path, $ancestors) {
* // return
* // null: no action
* // Visitor::skipNode(): skip visiting this node
* // Visitor::stop(): stop visiting altogether
* // Visitor::removeNode(): delete this node
* // any value: replace this node with the returned value
* },
* 'leave' => function ($node, $key, $parent, $path, $ancestors) {
* // return
* // null: no action
* // Visitor::stop(): stop visiting altogether
* // Visitor::removeNode(): delete this node
* // any value: replace this node with the returned value
* }
* ]);
*
* Alternatively to providing enter() and leave() functions, a visitor can
* instead provide functions named the same as the [kinds of AST nodes](reference.md#graphqllanguageastnodekind),
* or enter/leave visitors at a named key, leading to four permutations of
* visitor API:
*
* 1) Named visitors triggered when entering a node a specific kind.
*
* Visitor::visit($ast, [
* 'Kind' => function ($node) {
* // enter the "Kind" node
* }
* ]);
*
* 2) Named visitors that trigger upon entering and leaving a node of
* a specific kind.
*
* Visitor::visit($ast, [
* 'Kind' => [
* 'enter' => function ($node) {
* // enter the "Kind" node
* }
* 'leave' => function ($node) {
* // leave the "Kind" node
* }
* ]
* ]);
*
* 3) Generic visitors that trigger upon entering and leaving any node.
*
* Visitor::visit($ast, [
* 'enter' => function ($node) {
* // enter any node
* },
* 'leave' => function ($node) {
* // leave any node
* }
* ]);
*
* 4) Parallel visitors for entering and leaving nodes of a specific kind.
*
* Visitor::visit($ast, [
* 'enter' => [
* 'Kind' => function($node) {
* // enter the "Kind" node
* }
* },
* 'leave' => [
* 'Kind' => function ($node) {
* // leave the "Kind" node
* }
* ]
* ]);
*/
class Visitor
{
public static $visitorKeys = [
NodeKind::NAME => [],
NodeKind::DOCUMENT => ['definitions'],
NodeKind::OPERATION_DEFINITION => ['name', 'variableDefinitions', 'directives', 'selectionSet'],
NodeKind::VARIABLE_DEFINITION => ['variable', 'type', 'defaultValue'],
NodeKind::VARIABLE => ['name'],
NodeKind::SELECTION_SET => ['selections'],
NodeKind::FIELD => ['alias', 'name', 'arguments', 'directives', 'selectionSet'],
NodeKind::ARGUMENT => ['name', 'value'],
NodeKind::FRAGMENT_SPREAD => ['name', 'directives'],
NodeKind::INLINE_FRAGMENT => ['typeCondition', 'directives', 'selectionSet'],
NodeKind::FRAGMENT_DEFINITION => ['name', 'typeCondition', 'directives', 'selectionSet'],
NodeKind::INT => [],
NodeKind::FLOAT => [],
NodeKind::STRING => [],
NodeKind::BOOLEAN => [],
NodeKind::NULL => [],
NodeKind::ENUM => [],
NodeKind::LST => ['values'],
NodeKind::OBJECT => ['fields'],
NodeKind::OBJECT_FIELD => ['name', 'value'],
NodeKind::DIRECTIVE => ['name', 'arguments'],
NodeKind::NAMED_TYPE => ['name'],
NodeKind::LIST_TYPE => ['type'],
NodeKind::NON_NULL_TYPE => ['type'],
NodeKind::SCHEMA_DEFINITION => ['directives', 'operationTypes'],
NodeKind::OPERATION_TYPE_DEFINITION => ['type'],
NodeKind::SCALAR_TYPE_DEFINITION => ['name', 'directives'],
NodeKind::OBJECT_TYPE_DEFINITION => ['name', 'interfaces', 'directives', 'fields'],
NodeKind::FIELD_DEFINITION => ['name', 'arguments', 'type', 'directives'],
NodeKind::INPUT_VALUE_DEFINITION => ['name', 'type', 'defaultValue', 'directives'],
NodeKind::INTERFACE_TYPE_DEFINITION => [ 'name', 'directives', 'fields' ],
NodeKind::UNION_TYPE_DEFINITION => [ 'name', 'directives', 'types' ],
NodeKind::ENUM_TYPE_DEFINITION => [ 'name', 'directives', 'values' ],
NodeKind::ENUM_VALUE_DEFINITION => [ 'name', 'directives' ],
NodeKind::INPUT_OBJECT_TYPE_DEFINITION => [ 'name', 'directives', 'fields' ],
NodeKind::TYPE_EXTENSION_DEFINITION => [ 'definition' ],
NodeKind::DIRECTIVE_DEFINITION => [ 'name', 'arguments', 'locations' ]
];
/**
* Visit the AST (see class description for details)
*
* @api
* @param Node $root
* @param array $visitor
* @param array $keyMap
* @return Node|mixed
* @throws \Exception
*/
public static function visit($root, $visitor, $keyMap = null)
{
$visitorKeys = $keyMap ?: self::$visitorKeys;
$stack = null;
$inArray = $root instanceof NodeList || is_array($root);
$keys = [$root];
$index = -1;
$edits = [];
$parent = null;
$path = [];
$ancestors = [];
$newRoot = $root;
$UNDEFINED = null;
do {
$index++;
$isLeaving = $index === count($keys);
$key = null;
$node = null;
$isEdited = $isLeaving && count($edits) !== 0;
if ($isLeaving) {
$key = count($ancestors) === 0 ? $UNDEFINED : array_pop($path);
$node = $parent;
$parent = array_pop($ancestors);
if ($isEdited) {
if ($inArray) {
// $node = $node; // arrays are value types in PHP
if ($node instanceof NodeList) {
$node = clone $node;
}
} else {
$node = clone $node;
}
$editOffset = 0;
for ($ii = 0; $ii < count($edits); $ii++) {
$editKey = $edits[$ii][0];
$editValue = $edits[$ii][1];
if ($inArray) {
$editKey -= $editOffset;
}
if ($inArray && $editValue === null) {
if ($node instanceof NodeList) {
$node->splice($editKey, 1);
} else {
array_splice($node, $editKey, 1);
}
$editOffset++;
} else {
if ($node instanceof NodeList || is_array($node)) {
$node[$editKey] = $editValue;
} else {
$node->{$editKey} = $editValue;
}
}
}
}
$index = $stack['index'];
$keys = $stack['keys'];
$edits = $stack['edits'];
$inArray = $stack['inArray'];
$stack = $stack['prev'];
} else {
$key = $parent ? ($inArray ? $index : $keys[$index]) : $UNDEFINED;
$node = $parent ? (($parent instanceof NodeList || is_array($parent)) ? $parent[$key] : $parent->{$key}) : $newRoot;
if ($node === null || $node === $UNDEFINED) {
continue;
}
if ($parent) {
$path[] = $key;
}
}
$result = null;
if (!$node instanceof NodeList && !is_array($node)) {
if (!($node instanceof Node)) {
throw new \Exception('Invalid AST Node: ' . json_encode($node));
}
$visitFn = self::getVisitFn($visitor, $node->kind, $isLeaving);
if ($visitFn) {
$result = call_user_func($visitFn, $node, $key, $parent, $path, $ancestors);
if ($result !== null) {
if ($result instanceof VisitorOperation) {
if ($result->doBreak) {
break;
}
if (!$isLeaving && $result->doContinue) {
array_pop($path);
continue;
}
if ($result->removeNode) {
$editValue = null;
}
} else {
$editValue = $result;
}
$edits[] = [$key, $editValue];
if (!$isLeaving) {
if ($editValue instanceof Node) {
$node = $editValue;
} else {
array_pop($path);
continue;
}
}
}
}
}
if ($result === null && $isEdited) {
$edits[] = [$key, $node];
}
if (!$isLeaving) {
$stack = [
'inArray' => $inArray,
'index' => $index,
'keys' => $keys,
'edits' => $edits,
'prev' => $stack
];
$inArray = $node instanceof NodeList || is_array($node);
$keys = ($inArray ? $node : $visitorKeys[$node->kind]) ?: [];
$index = -1;
$edits = [];
if ($parent) {
$ancestors[] = $parent;
}
$parent = $node;
}
} while ($stack);
if (count($edits) !== 0) {
$newRoot = $edits[0][1];
}
return $newRoot;
}
/**
* Returns marker for visitor break
*
* @api
* @return VisitorOperation
*/
public static function stop()
{
$r = new VisitorOperation();
$r->doBreak = true;
return $r;
}
/**
* Returns marker for skipping current node
*
* @api
* @return VisitorOperation
*/
public static function skipNode()
{
$r = new VisitorOperation();
$r->doContinue = true;
return $r;
}
/**
* Returns marker for removing a node
*
* @api
* @return VisitorOperation
*/
public static function removeNode()
{
$r = new VisitorOperation();
$r->removeNode = true;
return $r;
}
/**
* @param $visitors
* @return array
*/
static function visitInParallel($visitors)
{
$visitorsCount = count($visitors);
$skipping = new \SplFixedArray($visitorsCount);
return [
'enter' => function ($node) use ($visitors, $skipping, $visitorsCount) {
for ($i = 0; $i < $visitorsCount; $i++) {
if (empty($skipping[$i])) {
$fn = self::getVisitFn($visitors[$i], $node->kind, /* isLeaving */ false);
if ($fn) {
$result = call_user_func_array($fn, func_get_args());
if ($result instanceof VisitorOperation) {
if ($result->doContinue) {
$skipping[$i] = $node;
} else if ($result->doBreak) {
$skipping[$i] = $result;
} else if ($result->removeNode) {
return $result;
}
} else if ($result !== null) {
return $result;
}
}
}
}
},
'leave' => function ($node) use ($visitors, $skipping, $visitorsCount) {
for ($i = 0; $i < $visitorsCount; $i++) {
if (empty($skipping[$i])) {
$fn = self::getVisitFn($visitors[$i], $node->kind, /* isLeaving */ true);
if ($fn) {
$result = call_user_func_array($fn, func_get_args());
if ($result instanceof VisitorOperation) {
if ($result->doBreak) {
$skipping[$i] = $result;
} else if ($result->removeNode) {
return $result;
}
} else if ($result !== null) {
return $result;
}
}
} else if ($skipping[$i] === $node) {
$skipping[$i] = null;
}
}
}
];
}
/**
* Creates a new visitor instance which maintains a provided TypeInfo instance
* along with visiting visitor.
*/
static function visitWithTypeInfo(TypeInfo $typeInfo, $visitor)
{
return [
'enter' => function ($node) use ($typeInfo, $visitor) {
$typeInfo->enter($node);
$fn = self::getVisitFn($visitor, $node->kind, false);
if ($fn) {
$result = call_user_func_array($fn, func_get_args());
if ($result) {
$typeInfo->leave($node);
if ($result instanceof Node) {
$typeInfo->enter($result);
}
}
return $result;
}
return null;
},
'leave' => function ($node) use ($typeInfo, $visitor) {
$fn = self::getVisitFn($visitor, $node->kind, true);
$result = $fn ? call_user_func_array($fn, func_get_args()) : null;
$typeInfo->leave($node);
return $result;
}
];
}
/**
* @param $visitor
* @param $kind
* @param $isLeaving
* @return null
*/
public static function getVisitFn($visitor, $kind, $isLeaving)
{
if (!$visitor) {
return null;
}
$kindVisitor = isset($visitor[$kind]) ? $visitor[$kind] : null;
if (!$isLeaving && is_callable($kindVisitor)) {
// { Kind() {} }
return $kindVisitor;
}
if (is_array($kindVisitor)) {
if ($isLeaving) {
$kindSpecificVisitor = isset($kindVisitor['leave']) ? $kindVisitor['leave'] : null;
} else {
$kindSpecificVisitor = isset($kindVisitor['enter']) ? $kindVisitor['enter'] : null;
}
if ($kindSpecificVisitor && is_callable($kindSpecificVisitor)) {
// { Kind: { enter() {}, leave() {} } }
return $kindSpecificVisitor;
}
return null;
}
$visitor += ['leave' => null, 'enter' => null];
$specificVisitor = $isLeaving ? $visitor['leave'] : $visitor['enter'];
if ($specificVisitor) {
if (is_callable($specificVisitor)) {
// { enter() {}, leave() {} }
return $specificVisitor;
}
$specificKindVisitor = isset($specificVisitor[$kind]) ? $specificVisitor[$kind] : null;
if (is_callable($specificKindVisitor)) {
// { enter: { Kind() {} }, leave: { Kind() {} } }
return $specificKindVisitor;
}
}
return null;
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace GraphQL;
/**
* Schema Definition
*
* @deprecated moved to GraphQL\Type\Schema
*/
class Schema extends \GraphQL\Type\Schema
{
}

View File

@@ -0,0 +1,603 @@
<?php
namespace GraphQL;
use GraphQL\Error\Error;
use GraphQL\Error\InvariantViolation;
use GraphQL\Executor\ExecutionResult;
use GraphQL\Executor\Executor;
use GraphQL\Executor\Promise\PromiseAdapter;
use GraphQL\Language\AST\DocumentNode;
use GraphQL\Language\Parser;
use GraphQL\Type\Definition\Directive;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Resolution;
use GraphQL\Validator\DocumentValidator;
use GraphQL\Utils\Utils;
trigger_error(
'GraphQL\Server is deprecated in favor of new implementation: GraphQL\Server\StandardServer and will be removed in next version',
E_USER_DEPRECATED
);
class Server
{
const DEBUG_PHP_ERRORS = 1;
const DEBUG_EXCEPTIONS = 2;
const DEBUG_ALL = 7;
private $queryType;
private $mutationType;
private $subscriptionType;
private $directives;
private $types = [];
private $schema;
private $debug = 0;
private $contextValue;
private $rootValue;
/**
* @var callable
*/
private $phpErrorFormatter = ['GraphQL\Error\FormattedError', 'createFromPHPError'];
/**
* @var callable
*/
private $exceptionFormatter = ['GraphQL\Error\FormattedError', 'createFromException'];
private $unexpectedErrorMessage = 'Unexpected Error';
private $unexpectedErrorStatus = 500;
private $validationRules;
/**
* @var Resolution
*/
private $typeResolutionStrategy;
/**
* @var PromiseAdapter
*/
private $promiseAdapter;
private $phpErrors = [];
/**
* @return static
*/
public static function create()
{
return new static();
}
/**
* @return ObjectType|null
*/
public function getQueryType()
{
return $this->queryType;
}
/**
* @param ObjectType $queryType
* @return Server
*/
public function setQueryType(ObjectType $queryType)
{
$this->assertSchemaNotSet('Query Type', __METHOD__);
$this->queryType = $queryType;
return $this;
}
/**
* @return ObjectType|null
*/
public function getMutationType()
{
return $this->mutationType;
}
/**
* @param ObjectType $mutationType
* @return Server
*/
public function setMutationType(ObjectType $mutationType)
{
$this->assertSchemaNotSet('Mutation Type', __METHOD__);
$this->mutationType = $mutationType;
return $this;
}
/**
* @return ObjectType|null
*/
public function getSubscriptionType()
{
return $this->subscriptionType;
}
/**
* @param ObjectType $subscriptionType
* @return Server
*/
public function setSubscriptionType($subscriptionType)
{
$this->assertSchemaNotSet('Subscription Type', __METHOD__);
$this->subscriptionType = $subscriptionType;
return $this;
}
/**
* @param Type[] $types
* @return Server
*/
public function addTypes(array $types)
{
if (!empty($types)) {
$this->assertSchemaNotSet('Types', __METHOD__);
$this->types = array_merge($this->types, $types);
}
return $this;
}
/**
* @return array
*/
public function getTypes()
{
return $this->types;
}
/**
* @return Directive[]
*/
public function getDirectives()
{
if (null === $this->directives) {
$this->directives = Directive::getInternalDirectives();
}
return $this->directives;
}
/**
* @param Directive[] $directives
* @return Server
*/
public function setDirectives(array $directives)
{
$this->assertSchemaNotSet('Directives', __METHOD__);
$this->directives = $directives;
return $this;
}
/**
* @return int
*/
public function getDebug()
{
return $this->debug;
}
/**
* @param int $debug
* @return Server
*/
public function setDebug($debug = self::DEBUG_ALL)
{
$this->debug = (int) $debug;
return $this;
}
/**
* @return mixed
*/
public function getContext()
{
return $this->contextValue;
}
/**
* @param mixed $context
* @return Server
*/
public function setContext($context)
{
$this->contextValue = $context;
return $this;
}
/**
* @param $rootValue
* @return Server
*/
public function setRootValue($rootValue)
{
$this->rootValue = $rootValue;
return $this;
}
/**
* @return mixed
*/
public function getRootValue()
{
return $this->rootValue;
}
/**
* Set schema instance manually. Mutually exclusive with `setQueryType`, `setMutationType`, `setSubscriptionType`, `setDirectives`, `addTypes`
*
* @param Schema $schema
* @return $this
*/
public function setSchema(Schema $schema)
{
if ($this->queryType) {
$err = 'Query Type is already set';
$errMethod = __CLASS__ . '::setQueryType';
} else if ($this->mutationType) {
$err = 'Mutation Type is already set';
$errMethod = __CLASS__ . '::setMutationType';
} else if ($this->subscriptionType) {
$err = 'Subscription Type is already set';
$errMethod = __CLASS__ . '::setSubscriptionType';
} else if ($this->directives) {
$err = 'Directives are already set';
$errMethod = __CLASS__ . '::setDirectives';
} else if ($this->types) {
$err = 'Additional types are already set';
$errMethod = __CLASS__ . '::addTypes';
} else if ($this->typeResolutionStrategy) {
$err = 'Type Resolution Strategy is already set';
$errMethod = __CLASS__ . '::setTypeResolutionStrategy';
} else if ($this->schema && $this->schema !== $schema) {
$err = 'Different schema is already set';
}
if (isset($err)) {
if (isset($errMethod)) {
$err .= " ($errMethod is mutually exclusive with " . __METHOD__ . ")";
}
throw new InvariantViolation("Cannot set Schema on Server: $err");
}
$this->schema = $schema;
return $this;
}
/**
* @param $entry
* @param $mutuallyExclusiveMethod
*/
private function assertSchemaNotSet($entry, $mutuallyExclusiveMethod)
{
if ($this->schema) {
$schemaMethod = __CLASS__ . '::setSchema';
throw new InvariantViolation("Cannot set $entry on Server: Schema is already set ($mutuallyExclusiveMethod is mutually exclusive with $schemaMethod)");
}
}
/**
* @return Schema
*/
public function getSchema()
{
if (null === $this->schema) {
$this->schema = new Schema([
'query' => $this->queryType,
'mutation' => $this->mutationType,
'subscription' => $this->subscriptionType,
'directives' => $this->directives,
'types' => $this->types,
'typeResolution' => $this->typeResolutionStrategy
]);
}
return $this->schema;
}
/**
* @return callable
*/
public function getPhpErrorFormatter()
{
return $this->phpErrorFormatter;
}
/**
* Expects function(\ErrorException $e) : array
*
* @param callable $phpErrorFormatter
* @return $this
*/
public function setPhpErrorFormatter(callable $phpErrorFormatter)
{
$this->phpErrorFormatter = $phpErrorFormatter;
return $this;
}
/**
* @return callable
*/
public function getExceptionFormatter()
{
return $this->exceptionFormatter;
}
/**
* Expects function(Exception $e) : array
*
* @param callable $exceptionFormatter
* @return $this
*/
public function setExceptionFormatter(callable $exceptionFormatter)
{
$this->exceptionFormatter = $exceptionFormatter;
return $this;
}
/**
* @return string
*/
public function getUnexpectedErrorMessage()
{
return $this->unexpectedErrorMessage;
}
/**
* @param string $unexpectedErrorMessage
* @return $this
*/
public function setUnexpectedErrorMessage($unexpectedErrorMessage)
{
$this->unexpectedErrorMessage = $unexpectedErrorMessage;
return $this;
}
/**
* @return int
*/
public function getUnexpectedErrorStatus()
{
return $this->unexpectedErrorStatus;
}
/**
* @param int $unexpectedErrorStatus
* @return $this
*/
public function setUnexpectedErrorStatus($unexpectedErrorStatus)
{
$this->unexpectedErrorStatus = $unexpectedErrorStatus;
return $this;
}
/**
* Parses GraphQL query string and returns Abstract Syntax Tree for this query
*
* @param string $query
* @return Language\AST\DocumentNode
* @throws \GraphQL\Error\SyntaxError
*/
public function parse($query)
{
return Parser::parse($query);
}
/**
* @return array
*/
public function getValidationRules()
{
if (null === $this->validationRules) {
$this->validationRules = DocumentValidator::allRules();
}
return $this->validationRules;
}
/**
* @param array $validationRules
* @return $this
*/
public function setValidationRules(array $validationRules)
{
$this->validationRules = $validationRules;
return $this;
}
/**
* EXPERIMENTAL!
* This method can be removed or changed in future versions without a prior notice.
*
* @return Resolution
*/
public function getTypeResolutionStrategy()
{
return $this->typeResolutionStrategy;
}
/**
* EXPERIMENTAL!
* This method can be removed or changed in future versions without a prior notice.
*
* @param Resolution $typeResolutionStrategy
* @return Server
*/
public function setTypeResolutionStrategy(Resolution $typeResolutionStrategy)
{
$this->assertSchemaNotSet('Type Resolution Strategy', __METHOD__);
$this->typeResolutionStrategy = $typeResolutionStrategy;
return $this;
}
/**
* @return PromiseAdapter|null
*/
public function getPromiseAdapter()
{
return $this->promiseAdapter;
}
/**
* See /docs/data-fetching.md#async-php
*
* @param PromiseAdapter $promiseAdapter
* @return Server
*/
public function setPromiseAdapter(PromiseAdapter $promiseAdapter)
{
if ($this->promiseAdapter && $promiseAdapter !== $this->promiseAdapter) {
throw new InvariantViolation("Cannot set promise adapter: Different adapter is already set");
}
$this->promiseAdapter = $promiseAdapter;
return $this;
}
/**
* Returns array with validation errors (empty when there are no validation errors)
*
* @param DocumentNode $query
* @return array
*/
public function validate(DocumentNode $query)
{
try {
$schema = $this->getSchema();
} catch (InvariantViolation $e) {
throw new InvariantViolation("Cannot validate, schema contains errors: {$e->getMessage()}", null, $e);
}
return DocumentValidator::validate($schema, $query, $this->validationRules);
}
/**
* Executes GraphQL query against this server and returns execution result
*
* @param string|DocumentNode $query
* @param array|null $variables
* @param string|null $operationName
* @return ExecutionResult
*/
public function executeQuery($query, array $variables = null, $operationName = null)
{
$this->phpErrors = [];
if ($this->debug & static::DEBUG_PHP_ERRORS) {
// Catch custom errors (to report them in query results)
set_error_handler(function($severity, $message, $file, $line) {
$this->phpErrors[] = new \ErrorException($message, 0, $severity, $file, $line);
});
}
if ($this->promiseAdapter) {
// TODO: inline GraphQL::executeAndReturnResult and pass promise adapter to executor constructor directly
$promiseAdapter = Executor::getPromiseAdapter();
Executor::setPromiseAdapter($this->promiseAdapter);
}
$result = GraphQL::executeAndReturnResult(
$this->getSchema(),
$query,
$this->getRootValue(),
$this->getContext(),
$variables,
$operationName
);
if (isset($promiseAdapter)) {
Executor::setPromiseAdapter($promiseAdapter);
}
// Add details about original exception in error entry (if any)
if ($this->debug & static::DEBUG_EXCEPTIONS) {
$result->setErrorFormatter([$this, 'formatError']);
}
// Add reported PHP errors to result (if any)
if (!empty($this->phpErrors) && ($this->debug & static::DEBUG_PHP_ERRORS)) {
$result->extensions['phpErrors'] = array_map($this->phpErrorFormatter, $this->phpErrors);
}
if ($this->debug & static::DEBUG_PHP_ERRORS) {
restore_error_handler();
}
return $result;
}
/**
* GraphQL HTTP endpoint compatible with express-graphql
*/
public function handleRequest()
{
try {
$httpStatus = 200;
if (isset($_SERVER['CONTENT_TYPE']) && strpos($_SERVER['CONTENT_TYPE'], 'application/json') !== false) {
$raw = $this->readInput();
$data = json_decode($raw, true);
Utils::invariant(
is_array($data),
"GraphQL Server expects JSON object with keys 'query' and 'variables', but got " . Utils::getVariableType($data)
);
} else {
$data = $_REQUEST ?: [];
}
$data += ['query' => null, 'variables' => null];
$result = $this->executeQuery($data['query'], (array) $data['variables'])->toArray();
} catch (\Exception $e) {
// This is only possible for schema creation errors and some very unpredictable errors,
// (all errors which occur during query execution are caught and included in final response)
$httpStatus = $this->unexpectedErrorStatus;
$error = new Error($this->unexpectedErrorMessage, null, null, null, null, $e);
$result = ['errors' => [$this->formatError($error)]];
} catch (\Throwable $e) {
$httpStatus = $this->unexpectedErrorStatus;
$error = new Error($this->unexpectedErrorMessage, null, null, null, null, $e);
$result = ['errors' => [$this->formatError($error)]];
}
$this->produceOutput($result, $httpStatus);
}
/**
* @param \Throwable $e
*/
private function formatException($e)
{
$formatter = $this->exceptionFormatter;
return $formatter($e);
}
/**
* @param Error $e
* @return array
*/
public function formatError(\GraphQL\Error\Error $e)
{
$result = $e->toSerializableArray();
if (($this->debug & static::DEBUG_EXCEPTIONS) && $e->getPrevious()) {
$result['exception'] = $this->formatException($e->getPrevious());
}
return $result;
}
protected function readInput()
{
return file_get_contents('php://input') ?: '';
}
protected function produceOutput(array $result, $httpStatus)
{
header('Content-Type: application/json', true, $httpStatus);
echo json_encode($result);
}
}

View File

@@ -0,0 +1,559 @@
<?php
namespace GraphQL\Server;
use GraphQL\Error\Error;
use GraphQL\Error\FormattedError;
use GraphQL\Error\InvariantViolation;
use GraphQL\Executor\ExecutionResult;
use GraphQL\Executor\Executor;
use GraphQL\Executor\Promise\Adapter\SyncPromiseAdapter;
use GraphQL\Executor\Promise\Promise;
use GraphQL\Executor\Promise\PromiseAdapter;
use GraphQL\GraphQL;
use GraphQL\Language\AST\DocumentNode;
use GraphQL\Language\Parser;
use GraphQL\Utils\AST;
use GraphQL\Utils\Utils;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamInterface;
/**
* Contains functionality that could be re-used by various server implementations
*/
class Helper
{
/**
* Parses HTTP request using PHP globals and returns GraphQL OperationParams
* contained in this request. For batched requests it returns an array of OperationParams.
*
* This function does not check validity of these params
* (validation is performed separately in validateOperationParams() method).
*
* If $readRawBodyFn argument is not provided - will attempt to read raw request body
* from `php://input` stream.
*
* Internally it normalizes input to $method, $bodyParams and $queryParams and
* calls `parseRequestParams()` to produce actual return value.
*
* For PSR-7 request parsing use `parsePsrRequest()` instead.
*
* @api
* @param callable|null $readRawBodyFn
* @return OperationParams|OperationParams[]
* @throws RequestError
*/
public function parseHttpRequest(callable $readRawBodyFn = null)
{
$method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : null;
$bodyParams = [];
$urlParams = $_GET;
if ($method === 'POST') {
$contentType = isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : null;
if (stripos($contentType, 'application/graphql') !== false) {
$rawBody = $readRawBodyFn ? $readRawBodyFn() : $this->readRawBody();
$bodyParams = ['query' => $rawBody ?: ''];
} else if (stripos($contentType, 'application/json') !== false) {
$rawBody = $readRawBodyFn ? $readRawBodyFn() : $this->readRawBody();
$bodyParams = json_decode($rawBody ?: '', true);
if (json_last_error()) {
throw new RequestError("Could not parse JSON: " . json_last_error_msg());
}
if (!is_array($bodyParams)) {
throw new RequestError(
"GraphQL Server expects JSON object or array, but got " .
Utils::printSafeJson($bodyParams)
);
}
} else if (stripos($contentType, 'application/x-www-form-urlencoded') !== false) {
$bodyParams = $_POST;
} else if (null === $contentType) {
throw new RequestError('Missing "Content-Type" header');
} else {
throw new RequestError("Unexpected content type: " . Utils::printSafeJson($contentType));
}
}
return $this->parseRequestParams($method, $bodyParams, $urlParams);
}
/**
* Parses normalized request params and returns instance of OperationParams
* or array of OperationParams in case of batch operation.
*
* Returned value is a suitable input for `executeOperation` or `executeBatch` (if array)
*
* @api
* @param string $method
* @param array $bodyParams
* @param array $queryParams
* @return OperationParams|OperationParams[]
* @throws RequestError
*/
public function parseRequestParams($method, array $bodyParams, array $queryParams)
{
if ($method === 'GET') {
$result = OperationParams::create($queryParams, true);
} else if ($method === 'POST') {
if (isset($bodyParams[0])) {
$result = [];
foreach ($bodyParams as $index => $entry) {
$op = OperationParams::create($entry);
$result[] = $op;
}
} else {
$result = OperationParams::create($bodyParams);
}
} else {
throw new RequestError('HTTP Method "' . $method . '" is not supported');
}
return $result;
}
/**
* Checks validity of OperationParams extracted from HTTP request and returns an array of errors
* if params are invalid (or empty array when params are valid)
*
* @api
* @param OperationParams $params
* @return Error[]
*/
public function validateOperationParams(OperationParams $params)
{
$errors = [];
if (!$params->query && !$params->queryId) {
$errors[] = new RequestError('GraphQL Request must include at least one of those two parameters: "query" or "queryId"');
}
if ($params->query && $params->queryId) {
$errors[] = new RequestError('GraphQL Request parameters "query" and "queryId" are mutually exclusive');
}
if ($params->query !== null && (!is_string($params->query) || empty($params->query))) {
$errors[] = new RequestError(
'GraphQL Request parameter "query" must be string, but got ' .
Utils::printSafeJson($params->query)
);
}
if ($params->queryId !== null && (!is_string($params->queryId) || empty($params->queryId))) {
$errors[] = new RequestError(
'GraphQL Request parameter "queryId" must be string, but got ' .
Utils::printSafeJson($params->queryId)
);
}
if ($params->operation !== null && (!is_string($params->operation) || empty($params->operation))) {
$errors[] = new RequestError(
'GraphQL Request parameter "operation" must be string, but got ' .
Utils::printSafeJson($params->operation)
);
}
if ($params->variables !== null && (!is_array($params->variables) || isset($params->variables[0]))) {
$errors[] = new RequestError(
'GraphQL Request parameter "variables" must be object or JSON string parsed to object, but got ' .
Utils::printSafeJson($params->getOriginalInput('variables'))
);
}
return $errors;
}
/**
* Executes GraphQL operation with given server configuration and returns execution result
* (or promise when promise adapter is different from SyncPromiseAdapter)
*
* @api
* @param ServerConfig $config
* @param OperationParams $op
*
* @return ExecutionResult|Promise
*/
public function executeOperation(ServerConfig $config, OperationParams $op)
{
$promiseAdapter = $config->getPromiseAdapter() ?: Executor::getPromiseAdapter();
$result = $this->promiseToExecuteOperation($promiseAdapter, $config, $op);
if ($promiseAdapter instanceof SyncPromiseAdapter) {
$result = $promiseAdapter->wait($result);
}
return $result;
}
/**
* Executes batched GraphQL operations with shared promise queue
* (thus, effectively batching deferreds|promises of all queries at once)
*
* @api
* @param ServerConfig $config
* @param OperationParams[] $operations
* @return ExecutionResult[]|Promise
*/
public function executeBatch(ServerConfig $config, array $operations)
{
$promiseAdapter = $config->getPromiseAdapter() ?: Executor::getPromiseAdapter();
$result = [];
foreach ($operations as $operation) {
$result[] = $this->promiseToExecuteOperation($promiseAdapter, $config, $operation, true);
}
$result = $promiseAdapter->all($result);
// Wait for promised results when using sync promises
if ($promiseAdapter instanceof SyncPromiseAdapter) {
$result = $promiseAdapter->wait($result);
}
return $result;
}
/**
* @param PromiseAdapter $promiseAdapter
* @param ServerConfig $config
* @param OperationParams $op
* @param bool $isBatch
* @return Promise
*/
private function promiseToExecuteOperation(PromiseAdapter $promiseAdapter, ServerConfig $config, OperationParams $op, $isBatch = false)
{
try {
if (!$config->getSchema()) {
throw new InvariantViolation("Schema is required for the server");
}
if ($isBatch && !$config->getQueryBatching()) {
throw new RequestError("Batched queries are not supported by this server");
}
$errors = $this->validateOperationParams($op);
if (!empty($errors)) {
$errors = Utils::map($errors, function(RequestError $err) {
return Error::createLocatedError($err, null, null);
});
return $promiseAdapter->createFulfilled(
new ExecutionResult(null, $errors)
);
}
$doc = $op->queryId ? $this->loadPersistedQuery($config, $op) : $op->query;
if (!$doc instanceof DocumentNode) {
$doc = Parser::parse($doc);
}
$operationType = AST::getOperation($doc, $op->operation);
if ($op->isReadOnly() && $operationType !== 'query') {
throw new RequestError("GET supports only query operation");
}
$result = GraphQL::promiseToExecute(
$promiseAdapter,
$config->getSchema(),
$doc,
$this->resolveRootValue($config, $op, $doc, $operationType),
$this->resolveContextValue($config, $op, $doc, $operationType),
$op->variables,
$op->operation,
$config->getFieldResolver(),
$this->resolveValidationRules($config, $op, $doc, $operationType)
);
} catch (RequestError $e) {
$result = $promiseAdapter->createFulfilled(
new ExecutionResult(null, [Error::createLocatedError($e)])
);
} catch (Error $e) {
$result = $promiseAdapter->createFulfilled(
new ExecutionResult(null, [$e])
);
}
$applyErrorHandling = function (ExecutionResult $result) use ($config) {
if ($config->getErrorsHandler()) {
$result->setErrorsHandler($config->getErrorsHandler());
}
if ($config->getErrorFormatter() || $config->getDebug()) {
$result->setErrorFormatter(
FormattedError::prepareFormatter($config->getErrorFormatter(),
$config->getDebug())
);
}
return $result;
};
return $result->then($applyErrorHandling);
}
/**
* @param ServerConfig $config
* @param OperationParams $op
* @return mixed
* @throws RequestError
*/
private function loadPersistedQuery(ServerConfig $config, OperationParams $op)
{
// Load query if we got persisted query id:
$loader = $config->getPersistentQueryLoader();
if (!$loader) {
throw new RequestError("Persisted queries are not supported by this server");
}
$source = $loader($op->queryId, $op);
if (!is_string($source) && !$source instanceof DocumentNode) {
throw new InvariantViolation(sprintf(
"Persistent query loader must return query string or instance of %s but got: %s",
DocumentNode::class,
Utils::printSafe($source)
));
}
return $source;
}
/**
* @param ServerConfig $config
* @param OperationParams $params
* @param DocumentNode $doc
* @param $operationType
* @return array
*/
private function resolveValidationRules(ServerConfig $config, OperationParams $params, DocumentNode $doc, $operationType)
{
// Allow customizing validation rules per operation:
$validationRules = $config->getValidationRules();
if (is_callable($validationRules)) {
$validationRules = $validationRules($params, $doc, $operationType);
if (!is_array($validationRules)) {
throw new InvariantViolation(sprintf(
"Expecting validation rules to be array or callable returning array, but got: %s",
Utils::printSafe($validationRules)
));
}
}
return $validationRules;
}
/**
* @param ServerConfig $config
* @param OperationParams $params
* @param DocumentNode $doc
* @param $operationType
* @return mixed
*/
private function resolveRootValue(ServerConfig $config, OperationParams $params, DocumentNode $doc, $operationType)
{
$root = $config->getRootValue();
if ($root instanceof \Closure) {
$root = $root($params, $doc, $operationType);
}
return $root;
}
/**
* @param ServerConfig $config
* @param OperationParams $params
* @param DocumentNode $doc
* @param $operationType
* @return mixed
*/
private function resolveContextValue(ServerConfig $config, OperationParams $params, DocumentNode $doc, $operationType)
{
$context = $config->getContext();
if ($context instanceof \Closure) {
$context = $context($params, $doc, $operationType);
}
return $context;
}
/**
* Send response using standard PHP `header()` and `echo`.
*
* @api
* @param Promise|ExecutionResult|ExecutionResult[] $result
* @param bool $exitWhenDone
*/
public function sendResponse($result, $exitWhenDone = false)
{
if ($result instanceof Promise) {
$result->then(function($actualResult) use ($exitWhenDone) {
$this->doSendResponse($actualResult, $exitWhenDone);
});
} else {
$this->doSendResponse($result, $exitWhenDone);
}
}
/**
* @param $result
* @param $exitWhenDone
*/
private function doSendResponse($result, $exitWhenDone)
{
$httpStatus = $this->resolveHttpStatus($result);
$this->emitResponse($result, $httpStatus, $exitWhenDone);
}
/**
* @param array|\JsonSerializable $jsonSerializable
* @param int $httpStatus
* @param bool $exitWhenDone
*/
public function emitResponse($jsonSerializable, $httpStatus, $exitWhenDone)
{
$body = json_encode($jsonSerializable);
header('Content-Type: application/json', true, $httpStatus);
echo $body;
if ($exitWhenDone) {
exit;
}
}
/**
* @return bool|string
*/
private function readRawBody()
{
return file_get_contents('php://input');
}
/**
* @param $result
* @return int
*/
private function resolveHttpStatus($result)
{
if (is_array($result) && isset($result[0])) {
Utils::each($result, function ($executionResult, $index) {
if (!$executionResult instanceof ExecutionResult) {
throw new InvariantViolation(sprintf(
"Expecting every entry of batched query result to be instance of %s but entry at position %d is %s",
ExecutionResult::class,
$index,
Utils::printSafe($executionResult)
));
}
});
$httpStatus = 200;
} else {
if (!$result instanceof ExecutionResult) {
throw new InvariantViolation(sprintf(
"Expecting query result to be instance of %s but got %s",
ExecutionResult::class,
Utils::printSafe($result)
));
}
if ($result->data === null && !empty($result->errors)) {
$httpStatus = 400;
} else {
$httpStatus = 200;
}
}
return $httpStatus;
}
/**
* Converts PSR-7 request to OperationParams[]
*
* @api
* @param ServerRequestInterface $request
* @return array|Helper
* @throws RequestError
*/
public function parsePsrRequest(ServerRequestInterface $request)
{
if ($request->getMethod() === 'GET') {
$bodyParams = [];
} else {
$contentType = $request->getHeader('content-type');
if (!isset($contentType[0])) {
throw new RequestError('Missing "Content-Type" header');
}
if (stripos('application/graphql', $contentType[0]) !== false) {
$bodyParams = ['query' => $request->getBody()->getContents()];
} else if (stripos('application/json', $contentType[0]) !== false) {
$bodyParams = $request->getParsedBody();
if (null === $bodyParams) {
throw new InvariantViolation(
"PSR-7 request is expected to provide parsed body for \"application/json\" requests but got null"
);
}
// Try parsing ourselves if PSR-7 implementation doesn't parse JSON automatically
if (is_array($bodyParams) && empty($bodyParams)) {
$bodyParams = json_decode($request->getBody(), true);
if (json_last_error()) {
throw new RequestError("Could not parse JSON: " . json_last_error_msg());
}
}
if (!is_array($bodyParams)) {
throw new RequestError(
"GraphQL Server expects JSON object or array, but got " .
Utils::printSafeJson($bodyParams)
);
}
} else {
$bodyParams = $request->getParsedBody();
if (!is_array($bodyParams)) {
throw new RequestError("Unexpected content type: " . Utils::printSafeJson($contentType[0]));
}
}
}
return $this->parseRequestParams(
$request->getMethod(),
$bodyParams,
$request->getQueryParams()
);
}
/**
* Converts query execution result to PSR-7 response
*
* @api
* @param Promise|ExecutionResult|ExecutionResult[] $result
* @param ResponseInterface $response
* @param StreamInterface $writableBodyStream
* @return Promise|ResponseInterface
*/
public function toPsrResponse($result, ResponseInterface $response, StreamInterface $writableBodyStream)
{
if ($result instanceof Promise) {
return $result->then(function($actualResult) use ($response, $writableBodyStream) {
return $this->doConvertToPsrResponse($actualResult, $response, $writableBodyStream);
});
} else {
return $this->doConvertToPsrResponse($result, $response, $writableBodyStream);
}
}
private function doConvertToPsrResponse($result, ResponseInterface $response, StreamInterface $writableBodyStream)
{
$httpStatus = $this->resolveHttpStatus($result);
$result = json_encode($result);
$writableBodyStream->write($result);
return $response
->withStatus($httpStatus)
->withHeader('Content-Type', 'application/json')
->withBody($writableBodyStream);
}
}

View File

@@ -0,0 +1,115 @@
<?php
namespace GraphQL\Server;
/**
* Structure representing parsed HTTP parameters for GraphQL operation
*/
class OperationParams
{
/**
* Id of the query (when using persistent queries).
*
* Valid aliases (case-insensitive):
* - id
* - queryId
* - documentId
*
* @api
* @var string
*/
public $queryId;
/**
* @api
* @var string
*/
public $query;
/**
* @api
* @var string
*/
public $operation;
/**
* @api
* @var array
*/
public $variables;
/**
* @var array
*/
private $originalInput;
/**
* @var bool
*/
private $readOnly;
/**
* Creates an instance from given array
*
* @api
* @param array $params
* @param bool $readonly
* @return OperationParams
*/
public static function create(array $params, $readonly = false)
{
$instance = new static();
$params = array_change_key_case($params, CASE_LOWER);
$instance->originalInput = $params;
$params += [
'query' => null,
'queryid' => null,
'documentid' => null, // alias to queryid
'id' => null, // alias to queryid
'operation' => null,
'variables' => null
];
if ($params['variables'] === "") {
$params['variables'] = null;
}
if (is_string($params['variables'])) {
$tmp = json_decode($params['variables'], true);
if (!json_last_error()) {
$params['variables'] = $tmp;
}
}
$instance->query = $params['query'];
$instance->queryId = $params['queryid'] ?: $params['documentid'] ?: $params['id'];
$instance->operation = $params['operation'];
$instance->variables = $params['variables'];
$instance->readOnly = (bool) $readonly;
return $instance;
}
/**
* @api
* @param string $key
* @return mixed
*/
public function getOriginalInput($key)
{
return isset($this->originalInput[$key]) ? $this->originalInput[$key] : null;
}
/**
* Indicates that operation is executed in read-only context
* (e.g. via HTTP GET request)
*
* @api
* @return bool
*/
public function isReadOnly()
{
return $this->readOnly;
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace GraphQL\Server;
use GraphQL\Error\ClientAware;
class RequestError extends \Exception implements ClientAware
{
/**
* Returns true when exception message is safe to be displayed to client
*
* @return bool
*/
public function isClientSafe()
{
return true;
}
/**
* Returns string describing error category. E.g. "validation" for your own validation errors.
*
* Value "graphql" is reserved for errors produced by query parsing or validation, do not use it.
*
* @return string
*/
public function getCategory()
{
return 'request';
}
}

View File

@@ -0,0 +1,329 @@
<?php
namespace GraphQL\Server;
use GraphQL\Error\InvariantViolation;
use GraphQL\Executor\Promise\PromiseAdapter;
use GraphQL\Type\Schema;
use GraphQL\Utils\Utils;
/**
* Server configuration class.
* Could be passed directly to server constructor. List of options accepted by **create** method is
* [described in docs](executing-queries.md#server-configuration-options).
*
* Usage example:
*
* $config = GraphQL\Server\ServerConfig::create()
* ->setSchema($mySchema)
* ->setContext($myContext);
*
* $server = new GraphQL\Server\StandardServer($config);
*/
class ServerConfig
{
/**
* Converts an array of options to instance of ServerConfig
* (or just returns empty config when array is not passed).
*
* @api
* @param array $config
* @return ServerConfig
*/
public static function create(array $config = [])
{
$instance = new static();
foreach ($config as $key => $value) {
$method = 'set' . ucfirst($key);
if (!method_exists($instance, $method)) {
throw new InvariantViolation("Unknown server config option \"$key\"");
}
$instance->$method($value);
}
return $instance;
}
/**
* @var Schema
*/
private $schema;
/**
* @var mixed|\Closure
*/
private $context;
/**
* @var mixed|\Closure
*/
private $rootValue;
/**
* @var callable|null
*/
private $errorFormatter;
/**
* @var callable|null
*/
private $errorsHandler;
/**
* @var bool
*/
private $debug = false;
/**
* @var bool
*/
private $queryBatching = false;
/**
* @var array|callable
*/
private $validationRules;
/**
* @var callable
*/
private $fieldResolver;
/**
* @var PromiseAdapter
*/
private $promiseAdapter;
/**
* @var callable
*/
private $persistentQueryLoader;
/**
* @api
* @param Schema $schema
* @return $this
*/
public function setSchema(Schema $schema)
{
$this->schema = $schema;
return $this;
}
/**
* @api
* @param mixed|\Closure $context
* @return $this
*/
public function setContext($context)
{
$this->context = $context;
return $this;
}
/**
* @api
* @param mixed|\Closure $rootValue
* @return $this
*/
public function setRootValue($rootValue)
{
$this->rootValue = $rootValue;
return $this;
}
/**
* Expects function(Throwable $e) : array
*
* @api
* @param callable $errorFormatter
* @return $this
*/
public function setErrorFormatter(callable $errorFormatter)
{
$this->errorFormatter = $errorFormatter;
return $this;
}
/**
* Expects function(array $errors, callable $formatter) : array
*
* @api
* @param callable $handler
* @return $this
*/
public function setErrorsHandler(callable $handler)
{
$this->errorsHandler = $handler;
return $this;
}
/**
* Set validation rules for this server.
*
* @api
* @param array|callable
* @return $this
*/
public function setValidationRules($validationRules)
{
if (!is_callable($validationRules) && !is_array($validationRules) && $validationRules !== null) {
throw new InvariantViolation(
'Server config expects array of validation rules or callable returning such array, but got ' .
Utils::printSafe($validationRules)
);
}
$this->validationRules = $validationRules;
return $this;
}
/**
* @api
* @param callable $fieldResolver
* @return $this
*/
public function setFieldResolver(callable $fieldResolver)
{
$this->fieldResolver = $fieldResolver;
return $this;
}
/**
* Expects function($queryId, OperationParams $params) : string|DocumentNode
*
* This function must return query string or valid DocumentNode.
*
* @api
* @param callable $persistentQueryLoader
* @return $this
*/
public function setPersistentQueryLoader(callable $persistentQueryLoader)
{
$this->persistentQueryLoader = $persistentQueryLoader;
return $this;
}
/**
* Set response debug flags. See GraphQL\Error\Debug class for a list of all available flags
*
* @api
* @param bool|int $set
* @return $this
*/
public function setDebug($set = true)
{
$this->debug = $set;
return $this;
}
/**
* Allow batching queries (disabled by default)
*
* @api
* @param bool $enableBatching
* @return $this
*/
public function setQueryBatching($enableBatching)
{
$this->queryBatching = (bool) $enableBatching;
return $this;
}
/**
* @api
* @param PromiseAdapter $promiseAdapter
* @return $this
*/
public function setPromiseAdapter(PromiseAdapter $promiseAdapter)
{
$this->promiseAdapter = $promiseAdapter;
return $this;
}
/**
* @return mixed|callable
*/
public function getContext()
{
return $this->context;
}
/**
* @return mixed|callable
*/
public function getRootValue()
{
return $this->rootValue;
}
/**
* @return Schema
*/
public function getSchema()
{
return $this->schema;
}
/**
* @return callable|null
*/
public function getErrorFormatter()
{
return $this->errorFormatter;
}
/**
* @return callable|null
*/
public function getErrorsHandler()
{
return $this->errorsHandler;
}
/**
* @return PromiseAdapter
*/
public function getPromiseAdapter()
{
return $this->promiseAdapter;
}
/**
* @return array|callable
*/
public function getValidationRules()
{
return $this->validationRules;
}
/**
* @return callable
*/
public function getFieldResolver()
{
return $this->fieldResolver;
}
/**
* @return callable
*/
public function getPersistentQueryLoader()
{
return $this->persistentQueryLoader;
}
/**
* @return bool
*/
public function getDebug()
{
return $this->debug;
}
/**
* @return bool
*/
public function getQueryBatching()
{
return $this->queryBatching;
}
}

View File

@@ -0,0 +1,181 @@
<?php
namespace GraphQL\Server;
use GraphQL\Error\FormattedError;
use GraphQL\Error\InvariantViolation;
use GraphQL\Executor\ExecutionResult;
use GraphQL\Executor\Promise\Promise;
use GraphQL\Utils;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamInterface;
/**
* GraphQL server compatible with both: [express-graphql](https://github.com/graphql/express-graphql)
* and [Apollo Server](https://github.com/apollographql/graphql-server).
* Usage Example:
*
* $server = new StandardServer([
* 'schema' => $mySchema
* ]);
* $server->handleRequest();
*
* Or using [ServerConfig](reference.md#graphqlserverserverconfig) instance:
*
* $config = GraphQL\Server\ServerConfig::create()
* ->setSchema($mySchema)
* ->setContext($myContext);
*
* $server = new GraphQL\Server\StandardServer($config);
* $server->handleRequest();
*
* See [dedicated section in docs](executing-queries.md#using-server) for details.
*
*/
class StandardServer
{
/**
* @var ServerConfig
*/
private $config;
/**
* @var Helper
*/
private $helper;
/**
* Converts and exception to error and sends spec-compliant HTTP 500 error.
* Useful when an exception is thrown somewhere outside of server execution context
* (e.g. during schema instantiation).
*
* @api
* @param \Throwable $error
* @param bool $debug
* @param bool $exitWhenDone
*/
public static function send500Error($error, $debug = false, $exitWhenDone = false)
{
$response = [
'errors' => [
FormattedError::createFromException($error, $debug)
]
];
$helper = new Helper();
$helper->emitResponse($response, 500, $exitWhenDone);
}
/**
* Creates new instance of a standard GraphQL HTTP server
*
* @api
* @param ServerConfig|array $config
*/
public function __construct($config)
{
if (is_array($config)) {
$config = ServerConfig::create($config);
}
if (!$config instanceof ServerConfig) {
throw new InvariantViolation("Expecting valid server config, but got " . Utils::printSafe($config));
}
$this->config = $config;
$this->helper = new Helper();
}
/**
* Parses HTTP request, executes and emits response (using standard PHP `header` function and `echo`)
*
* By default (when $parsedBody is not set) it uses PHP globals to parse a request.
* It is possible to implement request parsing elsewhere (e.g. using framework Request instance)
* and then pass it to the server.
*
* See `executeRequest()` if you prefer to emit response yourself
* (e.g. using Response object of some framework)
*
* @api
* @param OperationParams|OperationParams[] $parsedBody
* @param bool $exitWhenDone
*/
public function handleRequest($parsedBody = null, $exitWhenDone = false)
{
$result = $this->executeRequest($parsedBody);
$this->helper->sendResponse($result, $exitWhenDone);
}
/**
* Executes GraphQL operation and returns execution result
* (or promise when promise adapter is different from SyncPromiseAdapter).
*
* By default (when $parsedBody is not set) it uses PHP globals to parse a request.
* It is possible to implement request parsing elsewhere (e.g. using framework Request instance)
* and then pass it to the server.
*
* PSR-7 compatible method executePsrRequest() does exactly this.
*
* @api
* @param OperationParams|OperationParams[] $parsedBody
* @return ExecutionResult|ExecutionResult[]|Promise
* @throws InvariantViolation
*/
public function executeRequest($parsedBody = null)
{
if (null === $parsedBody) {
$parsedBody = $this->helper->parseHttpRequest();
}
if (is_array($parsedBody)) {
return $this->helper->executeBatch($this->config, $parsedBody);
} else {
return $this->helper->executeOperation($this->config, $parsedBody);
}
}
/**
* Executes PSR-7 request and fulfills PSR-7 response.
*
* See `executePsrRequest()` if you prefer to create response yourself
* (e.g. using specific JsonResponse instance of some framework).
*
* @api
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param StreamInterface $writableBodyStream
* @return ResponseInterface|Promise
*/
public function processPsrRequest(
ServerRequestInterface $request,
ResponseInterface $response,
StreamInterface $writableBodyStream
)
{
$result = $this->executePsrRequest($request);
return $this->helper->toPsrResponse($result, $response, $writableBodyStream);
}
/**
* Executes GraphQL operation and returns execution result
* (or promise when promise adapter is different from SyncPromiseAdapter)
*
* @api
* @param ServerRequestInterface $request
* @return ExecutionResult|ExecutionResult[]|Promise
*/
public function executePsrRequest(ServerRequestInterface $request)
{
$parsedBody = $this->helper->parsePsrRequest($request);
return $this->executeRequest($parsedBody);
}
/**
* Returns an instance of Server helper, which contains most of the actual logic for
* parsing / validating / executing request (which could be re-used by other server implementations)
*
* @api
* @return Helper
*/
public function getHelper()
{
return $this->helper;
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace GraphQL\Type\Definition;
/*
export type GraphQLAbstractType =
GraphQLInterfaceType |
GraphQLUnionType;
*/
interface AbstractType
{
/**
* Resolves concrete ObjectType for given object value
*
* @param $objectValue
* @param $context
* @param ResolveInfo $info
* @return mixed
*/
public function resolveType($objectValue, $context, ResolveInfo $info);
}

View File

@@ -0,0 +1,51 @@
<?php
namespace GraphQL\Type\Definition;
use GraphQL\Language\AST\BooleanValueNode;
/**
* Class BooleanType
* @package GraphQL\Type\Definition
*/
class BooleanType extends ScalarType
{
/**
* @var string
*/
public $name = Type::BOOLEAN;
/**
* @var string
*/
public $description = 'The `Boolean` scalar type represents `true` or `false`.';
/**
* @param mixed $value
* @return bool
*/
public function serialize($value)
{
return !!$value;
}
/**
* @param mixed $value
* @return bool
*/
public function parseValue($value)
{
return is_bool($value) ? $value : null;
}
/**
* @param $ast
* @return bool|null
*/
public function parseLiteral($ast)
{
if ($ast instanceof BooleanValueNode) {
return (bool) $ast->value;
}
return null;
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace GraphQL\Type\Definition;
/*
export type GraphQLCompositeType =
GraphQLObjectType |
GraphQLInterfaceType |
GraphQLUnionType;
*/
interface CompositeType
{
}

Some files were not shown because too many files have changed in this diff Show More