mirror of
https://github.com/retailcrm/graphql-php.git
synced 2024-11-29 08:26:02 +03:00
Schema validation + tests (#148)
This commit is contained in:
parent
d3580e959e
commit
34eae0b891
@ -64,19 +64,6 @@ $episodeEnum = new EnumType([
|
|||||||
|
|
||||||
which is equivalent of:
|
which is equivalent of:
|
||||||
```php
|
```php
|
||||||
$episodeEnum = new EnumType([
|
|
||||||
'name' => 'Episode',
|
|
||||||
'description' => 'One of the films in the Star Wars Trilogy',
|
|
||||||
'values' => [
|
|
||||||
'NEWHOPE' => 'NEWHOPE',
|
|
||||||
'EMPIRE' => 'EMPIRE',
|
|
||||||
'JEDI' => 'JEDI'
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
```
|
|
||||||
|
|
||||||
which is in turn equivalent of:
|
|
||||||
```php
|
|
||||||
$episodeEnum = new EnumType([
|
$episodeEnum = new EnumType([
|
||||||
'name' => 'Episode',
|
'name' => 'Episode',
|
||||||
'description' => 'One of the films in the Star Wars Trilogy',
|
'description' => 'One of the films in the Star Wars Trilogy',
|
||||||
|
@ -14,6 +14,13 @@ final class Warning
|
|||||||
|
|
||||||
static $warned = [];
|
static $warned = [];
|
||||||
|
|
||||||
|
static private $warningHandler;
|
||||||
|
|
||||||
|
public static function setWarningHandler(callable $warningHandler = null)
|
||||||
|
{
|
||||||
|
self::$warningHandler = $warningHandler;
|
||||||
|
}
|
||||||
|
|
||||||
static function suppress($suppress = true)
|
static function suppress($suppress = true)
|
||||||
{
|
{
|
||||||
if (true === $suppress) {
|
if (true === $suppress) {
|
||||||
@ -40,7 +47,10 @@ final class Warning
|
|||||||
|
|
||||||
static function warnOnce($errorMessage, $warningId)
|
static function warnOnce($errorMessage, $warningId)
|
||||||
{
|
{
|
||||||
if ((self::$enableWarnings & $warningId) > 0 && !isset(self::$warned[$warningId])) {
|
if (self::$warningHandler) {
|
||||||
|
$fn = self::$warningHandler;
|
||||||
|
$fn($errorMessage, $warningId);
|
||||||
|
} else if ((self::$enableWarnings & $warningId) > 0 && !isset(self::$warned[$warningId])) {
|
||||||
self::$warned[$warningId] = true;
|
self::$warned[$warningId] = true;
|
||||||
trigger_error($errorMessage, E_USER_WARNING);
|
trigger_error($errorMessage, E_USER_WARNING);
|
||||||
}
|
}
|
||||||
@ -48,7 +58,10 @@ final class Warning
|
|||||||
|
|
||||||
static function warn($errorMessage, $warningId)
|
static function warn($errorMessage, $warningId)
|
||||||
{
|
{
|
||||||
if ((self::$enableWarnings & $warningId) > 0) {
|
if (self::$warningHandler) {
|
||||||
|
$fn = self::$warningHandler;
|
||||||
|
$fn($errorMessage, $warningId);
|
||||||
|
} else if ((self::$enableWarnings & $warningId) > 0) {
|
||||||
trigger_error($errorMessage, E_USER_WARNING);
|
trigger_error($errorMessage, E_USER_WARNING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Type\Definition;
|
namespace GraphQL\Type\Definition;
|
||||||
|
|
||||||
|
use GraphQL\Utils\Utils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class CustomScalarType
|
* Class CustomScalarType
|
||||||
* @package GraphQL\Type\Definition
|
* @package GraphQL\Type\Definition
|
||||||
@ -38,7 +40,11 @@ class CustomScalarType extends ScalarType
|
|||||||
*/
|
*/
|
||||||
public function parseValue($value)
|
public function parseValue($value)
|
||||||
{
|
{
|
||||||
|
if (isset($this->config['parseValue'])) {
|
||||||
return call_user_func($this->config['parseValue'], $value);
|
return call_user_func($this->config['parseValue'], $value);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,6 +53,29 @@ class CustomScalarType extends ScalarType
|
|||||||
*/
|
*/
|
||||||
public function parseLiteral(/* GraphQL\Language\AST\ValueNode */ $valueNode)
|
public function parseLiteral(/* GraphQL\Language\AST\ValueNode */ $valueNode)
|
||||||
{
|
{
|
||||||
|
if (isset($this->config['parseLiteral'])) {
|
||||||
return call_user_func($this->config['parseLiteral'], $valueNode);
|
return call_user_func($this->config['parseLiteral'], $valueNode);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function assertValid()
|
||||||
|
{
|
||||||
|
parent::assertValid();
|
||||||
|
|
||||||
|
Utils::invariant(
|
||||||
|
isset($this->config['serialize']) && is_callable($this->config['serialize']),
|
||||||
|
"{$this->name} must provide \"serialize\" function. If this custom Scalar " .
|
||||||
|
'is also used as an input type, ensure "parseValue" and "parseLiteral" ' .
|
||||||
|
'functions are also provided.'
|
||||||
|
);
|
||||||
|
if (isset($this->config['parseValue']) || isset($this->config['parseLiteral'])) {
|
||||||
|
Utils::invariant(
|
||||||
|
isset($this->config['parseValue']) && isset($this->config['parseLiteral']) &&
|
||||||
|
is_callable($this->config['parseValue']) && is_callable($this->config['parseLiteral']),
|
||||||
|
"{$this->name} must provide both \"parseValue\" and \"parseLiteral\" functions."
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Type\Definition;
|
namespace GraphQL\Type\Definition;
|
||||||
|
|
||||||
|
use GraphQL\Error\InvariantViolation;
|
||||||
use GraphQL\Language\AST\EnumValueNode;
|
use GraphQL\Language\AST\EnumValueNode;
|
||||||
use GraphQL\Utils\MixedStore;
|
use GraphQL\Utils\MixedStore;
|
||||||
use GraphQL\Utils\Utils;
|
use GraphQL\Utils\Utils;
|
||||||
@ -26,6 +27,11 @@ class EnumType extends Type implements InputType, OutputType, LeafType
|
|||||||
*/
|
*/
|
||||||
private $nameLookup;
|
private $nameLookup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $config;
|
||||||
|
|
||||||
public function __construct($config)
|
public function __construct($config)
|
||||||
{
|
{
|
||||||
if (!isset($config['name'])) {
|
if (!isset($config['name'])) {
|
||||||
@ -47,21 +53,7 @@ class EnumType extends Type implements InputType, OutputType, LeafType
|
|||||||
|
|
||||||
$this->name = $config['name'];
|
$this->name = $config['name'];
|
||||||
$this->description = isset($config['description']) ? $config['description'] : null;
|
$this->description = isset($config['description']) ? $config['description'] : null;
|
||||||
$this->values = [];
|
$this->config = $config;
|
||||||
|
|
||||||
if (!empty($config['values'])) {
|
|
||||||
foreach ($config['values'] as $name => $value) {
|
|
||||||
if (!is_array($value)) {
|
|
||||||
if (is_string($name)) {
|
|
||||||
$value = ['name' => $name, 'value' => $value];
|
|
||||||
} else if (is_int($name) && is_string($value)) {
|
|
||||||
$value = ['name' => $value, 'value' => $value];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// value will be equal to name only if 'value' is not set in definition
|
|
||||||
$this->values[] = new EnumValueDefinition($value + ['name' => $name, 'value' => $name]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -69,6 +61,33 @@ class EnumType extends Type implements InputType, OutputType, LeafType
|
|||||||
*/
|
*/
|
||||||
public function getValues()
|
public function getValues()
|
||||||
{
|
{
|
||||||
|
if ($this->values === null) {
|
||||||
|
$this->values = [];
|
||||||
|
$config = $this->config;
|
||||||
|
|
||||||
|
if (isset($config['values'])) {
|
||||||
|
if (!is_array($config['values'])) {
|
||||||
|
throw new InvariantViolation("{$this->name} values must be an array");
|
||||||
|
}
|
||||||
|
foreach ($config['values'] as $name => $value) {
|
||||||
|
if (is_string($name)) {
|
||||||
|
if (!is_array($value)) {
|
||||||
|
throw new InvariantViolation(
|
||||||
|
"{$this->name}.$name must refer to an associative array with a " .
|
||||||
|
'"value" key representing an internal value but got: ' . Utils::printSafe($value)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$value += ['name' => $name, 'value' => $name];
|
||||||
|
} else if (is_int($name) && is_string($value)) {
|
||||||
|
$value = ['name' => $value, 'value' => $value];
|
||||||
|
} else {
|
||||||
|
throw new InvariantViolation("{$this->name} values must be an array with value names as keys.");
|
||||||
|
}
|
||||||
|
$this->values[] = new EnumValueDefinition($value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $this->values;
|
return $this->values;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,4 +187,42 @@ class EnumType extends Type implements InputType, OutputType, LeafType
|
|||||||
}
|
}
|
||||||
return $this->nameLookup;
|
return $this->nameLookup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws InvariantViolation
|
||||||
|
*/
|
||||||
|
public function assertValid()
|
||||||
|
{
|
||||||
|
parent::assertValid();
|
||||||
|
|
||||||
|
Utils::invariant(
|
||||||
|
isset($this->config['values']),
|
||||||
|
"{$this->name} values must be an array."
|
||||||
|
);
|
||||||
|
|
||||||
|
$values = $this->getValues();
|
||||||
|
|
||||||
|
Utils::invariant(
|
||||||
|
!empty($values),
|
||||||
|
"{$this->name} values must be not empty."
|
||||||
|
);
|
||||||
|
foreach ($values as $value) {
|
||||||
|
try {
|
||||||
|
Utils::assertValidName($value->name);
|
||||||
|
} catch (InvariantViolation $e) {
|
||||||
|
throw new InvariantViolation(
|
||||||
|
"{$this->name} has value with invalid name: " .
|
||||||
|
Utils::printSafe($value->name) . " ({$e->getMessage()})"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Utils::invariant(
|
||||||
|
!in_array($value->name, ['true', 'false', 'null']),
|
||||||
|
"{$this->name}: \"{$value->name}\" can not be used as an Enum value."
|
||||||
|
);
|
||||||
|
Utils::invariant(
|
||||||
|
!isset($value->config['isDeprecated']),
|
||||||
|
"{$this->name}.{$value->name} should provide \"deprecationReason\" instead of \"isDeprecated\"."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,9 +28,19 @@ class EnumValueDefinition
|
|||||||
*/
|
*/
|
||||||
public $description;
|
public $description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $config;
|
||||||
|
|
||||||
public function __construct(array $config)
|
public function __construct(array $config)
|
||||||
{
|
{
|
||||||
Utils::assign($this, $config);
|
$this->name = isset($config['name']) ? $config['name'] : null;
|
||||||
|
$this->value = isset($config['value']) ? $config['value'] : null;
|
||||||
|
$this->deprecationReason = isset($config['deprecationReason']) ? $config['deprecationReason'] : null;
|
||||||
|
$this->description = isset($config['description']) ? $config['description'] : null;
|
||||||
|
|
||||||
|
$this->config = $config;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Type\Definition;
|
namespace GraphQL\Type\Definition;
|
||||||
|
|
||||||
|
use GraphQL\Error\InvariantViolation;
|
||||||
|
use GraphQL\Utils\Utils;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class FieldArgument
|
* Class FieldArgument
|
||||||
@ -105,4 +108,29 @@ class FieldArgument
|
|||||||
{
|
{
|
||||||
return $this->defaultValueExists;
|
return $this->defaultValueExists;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function assertValid(FieldDefinition $parentField, Type $parentType)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Utils::assertValidName($this->name);
|
||||||
|
} catch (InvariantViolation $e) {
|
||||||
|
throw new InvariantViolation(
|
||||||
|
"{$parentType->name}.{$parentField->name}({$this->name}:) {$e->getMessage()}")
|
||||||
|
;
|
||||||
|
}
|
||||||
|
$type = $this->type;
|
||||||
|
if ($type instanceof WrappingType) {
|
||||||
|
$type = $type->getWrappedType(true);
|
||||||
|
}
|
||||||
|
Utils::invariant(
|
||||||
|
$type instanceof InputType,
|
||||||
|
"{$parentType->name}.{$parentField->name}({$this->name}): argument type must be " .
|
||||||
|
"Input Type but got: " . Utils::printSafe($this->type)
|
||||||
|
);
|
||||||
|
Utils::invariant(
|
||||||
|
$this->description === null || is_string($this->description),
|
||||||
|
"{$parentType->name}.{$parentField->name}({$this->name}): argument description type must be " .
|
||||||
|
"string but got: " . Utils::printSafe($this->description)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,28 +89,72 @@ class FieldDefinition
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public static function defineFieldMap(Type $type, $fields)
|
||||||
* @param array|Config $fields
|
|
||||||
* @param string $parentTypeName
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public static function createMap(array $fields, $parentTypeName = null)
|
|
||||||
{
|
{
|
||||||
|
if (is_callable($fields)) {
|
||||||
|
$fields = $fields();
|
||||||
|
}
|
||||||
|
if (!is_array($fields)) {
|
||||||
|
throw new InvariantViolation(
|
||||||
|
"{$type->name} fields must be an array or a callable which returns such an array."
|
||||||
|
);
|
||||||
|
}
|
||||||
$map = [];
|
$map = [];
|
||||||
foreach ($fields as $name => $field) {
|
foreach ($fields as $name => $field) {
|
||||||
if (is_array($field)) {
|
if (is_array($field)) {
|
||||||
if (!isset($field['name']) && is_string($name)) {
|
if (!isset($field['name']) && is_string($name)) {
|
||||||
$field['name'] = $name;
|
$field['name'] = $name;
|
||||||
}
|
}
|
||||||
$fieldDef = self::create($field, $parentTypeName);
|
if (isset($field['args']) && !is_array($field['args'])) {
|
||||||
|
throw new InvariantViolation(
|
||||||
|
"{$type->name}.{$name} args must be an array."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$fieldDef = self::create($field);
|
||||||
|
} else if ($field instanceof FieldDefinition) {
|
||||||
|
$fieldDef = $field;
|
||||||
|
} else {
|
||||||
|
if (is_string($name) && $field) {
|
||||||
|
$fieldDef = self::create(['name' => $name, 'type' => $field]);
|
||||||
|
} else {
|
||||||
|
throw new InvariantViolation(
|
||||||
|
"{$type->name}.$name field config must be an array, but got: " . Utils::printSafe($field)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$map[$fieldDef->name] = $fieldDef;
|
||||||
|
}
|
||||||
|
return $map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array|Config $fields
|
||||||
|
* @param string $parentTypeName
|
||||||
|
* @deprecated
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function createMap(array $fields, $parentTypeName = null)
|
||||||
|
{
|
||||||
|
trigger_error(
|
||||||
|
__METHOD__ . ' is deprecated, use ' . __CLASS__ . '::defineFieldMap() instead',
|
||||||
|
E_USER_DEPRECATED
|
||||||
|
);
|
||||||
|
|
||||||
|
$map = [];
|
||||||
|
foreach ($fields as $name => $field) {
|
||||||
|
if (is_array($field)) {
|
||||||
|
if (!isset($field['name']) && is_string($name)) {
|
||||||
|
$field['name'] = $name;
|
||||||
|
}
|
||||||
|
$fieldDef = self::create($field);
|
||||||
} else if ($field instanceof FieldDefinition) {
|
} else if ($field instanceof FieldDefinition) {
|
||||||
$fieldDef = $field;
|
$fieldDef = $field;
|
||||||
} else {
|
} else {
|
||||||
if (is_string($name)) {
|
if (is_string($name)) {
|
||||||
$fieldDef = self::create(['name' => $name, 'type' => $field], $parentTypeName);
|
$fieldDef = self::create(['name' => $name, 'type' => $field]);
|
||||||
} else {
|
} else {
|
||||||
throw new InvariantViolation(
|
throw new InvariantViolation(
|
||||||
"Unexpected field definition for type $parentTypeName at key $name: " . Utils::printSafe($field)
|
"Unexpected field definition for type $parentTypeName at field $name: " . Utils::printSafe($field)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -195,6 +239,37 @@ class FieldDefinition
|
|||||||
return $this->complexityFn;
|
return $this->complexityFn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Type $parentType
|
||||||
|
* @throws InvariantViolation
|
||||||
|
*/
|
||||||
|
public function assertValid(Type $parentType)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Utils::assertValidName($this->name);
|
||||||
|
} catch (InvariantViolation $e) {
|
||||||
|
throw new InvariantViolation("{$parentType->name}.{$this->name}: {$e->getMessage()}");
|
||||||
|
}
|
||||||
|
Utils::invariant(
|
||||||
|
!isset($this->config['isDeprecated']),
|
||||||
|
"{$parentType->name}.{$this->name} should provide \"deprecationReason\" instead of \"isDeprecated\"."
|
||||||
|
);
|
||||||
|
|
||||||
|
$type = $this->type;
|
||||||
|
if ($type instanceof WrappingType) {
|
||||||
|
$type = $type->getWrappedType(true);
|
||||||
|
}
|
||||||
|
Utils::invariant(
|
||||||
|
$type instanceof OutputType,
|
||||||
|
"{$parentType->name}.{$this->name} field type must be Output Type but got: " . Utils::printSafe($this->type)
|
||||||
|
);
|
||||||
|
Utils::invariant(
|
||||||
|
$this->resolveFn === null || is_callable($this->resolveFn),
|
||||||
|
"{$parentType->name}.{$this->name} field resolver must be a function if provided, but got: %s",
|
||||||
|
Utils::printSafe($this->resolveFn)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $childrenComplexity
|
* @param $childrenComplexity
|
||||||
* @return mixed
|
* @return mixed
|
||||||
|
@ -27,6 +27,11 @@ class InputObjectField
|
|||||||
*/
|
*/
|
||||||
public $type;
|
public $type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helps to differentiate when `defaultValue` is `null` and when it was not even set initially
|
* Helps to differentiate when `defaultValue` is `null` and when it was not even set initially
|
||||||
*
|
*
|
||||||
@ -52,6 +57,7 @@ class InputObjectField
|
|||||||
$this->{$k} = $v;
|
$this->{$k} = $v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$this->config = $opts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Type\Definition;
|
namespace GraphQL\Type\Definition;
|
||||||
|
|
||||||
|
use GraphQL\Error\InvariantViolation;
|
||||||
use GraphQL\Utils\Utils;
|
use GraphQL\Utils\Utils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,6 +57,13 @@ class InputObjectType extends Type implements InputType
|
|||||||
$this->fields = [];
|
$this->fields = [];
|
||||||
$fields = isset($this->config['fields']) ? $this->config['fields'] : [];
|
$fields = isset($this->config['fields']) ? $this->config['fields'] : [];
|
||||||
$fields = is_callable($fields) ? call_user_func($fields) : $fields;
|
$fields = is_callable($fields) ? call_user_func($fields) : $fields;
|
||||||
|
|
||||||
|
if (!is_array($fields)) {
|
||||||
|
throw new InvariantViolation(
|
||||||
|
"{$this->name} fields must be an array or a callable which returns such an array."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($fields as $name => $field) {
|
foreach ($fields as $name => $field) {
|
||||||
if ($field instanceof Type) {
|
if ($field instanceof Type) {
|
||||||
$field = ['type' => $field];
|
$field = ['type' => $field];
|
||||||
@ -81,4 +89,41 @@ class InputObjectType extends Type implements InputType
|
|||||||
Utils::invariant(isset($this->fields[$name]), "Field '%s' is not defined for type '%s'", $name, $this->name);
|
Utils::invariant(isset($this->fields[$name]), "Field '%s' is not defined for type '%s'", $name, $this->name);
|
||||||
return $this->fields[$name];
|
return $this->fields[$name];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws InvariantViolation
|
||||||
|
*/
|
||||||
|
public function assertValid()
|
||||||
|
{
|
||||||
|
parent::assertValid();
|
||||||
|
|
||||||
|
$fields = $this->getFields();
|
||||||
|
|
||||||
|
Utils::invariant(
|
||||||
|
!empty($fields),
|
||||||
|
"{$this->name} fields must not be empty"
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($fields as $field) {
|
||||||
|
try {
|
||||||
|
Utils::assertValidName($field->name);
|
||||||
|
} catch (InvariantViolation $e) {
|
||||||
|
throw new InvariantViolation("{$this->name}.{$field->name}: {$e->getMessage()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
$fieldType = $field->type;
|
||||||
|
if ($fieldType instanceof WrappingType) {
|
||||||
|
$fieldType = $fieldType->getWrappedType(true);
|
||||||
|
}
|
||||||
|
Utils::invariant(
|
||||||
|
$fieldType instanceof InputType,
|
||||||
|
"{$this->name}.{$field->name} field type must be Input Type but got: %s.",
|
||||||
|
Utils::printSafe($field->type)
|
||||||
|
);
|
||||||
|
Utils::invariant(
|
||||||
|
!isset($field->config['resolve']),
|
||||||
|
"{$this->name}.{$field->name} field type has a resolve property, but Input Types cannot define resolvers."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Type\Definition;
|
namespace GraphQL\Type\Definition;
|
||||||
|
|
||||||
|
use GraphQL\Error\InvariantViolation;
|
||||||
use GraphQL\Utils\Utils;
|
use GraphQL\Utils\Utils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,10 +58,8 @@ class InterfaceType extends Type implements AbstractType, OutputType, CompositeT
|
|||||||
public function getFields()
|
public function getFields()
|
||||||
{
|
{
|
||||||
if (null === $this->fields) {
|
if (null === $this->fields) {
|
||||||
$this->fields = [];
|
|
||||||
$fields = isset($this->config['fields']) ? $this->config['fields'] : [];
|
$fields = isset($this->config['fields']) ? $this->config['fields'] : [];
|
||||||
$fields = is_callable($fields) ? call_user_func($fields) : $fields;
|
$this->fields = FieldDefinition::defineFieldMap($this, $fields);
|
||||||
$this->fields = FieldDefinition::createMap($fields, $this->name);
|
|
||||||
}
|
}
|
||||||
return $this->fields;
|
return $this->fields;
|
||||||
}
|
}
|
||||||
@ -95,4 +94,31 @@ class InterfaceType extends Type implements AbstractType, OutputType, CompositeT
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws InvariantViolation
|
||||||
|
*/
|
||||||
|
public function assertValid()
|
||||||
|
{
|
||||||
|
parent::assertValid();
|
||||||
|
|
||||||
|
$fields = $this->getFields();
|
||||||
|
|
||||||
|
Utils::invariant(
|
||||||
|
!isset($this->config['resolveType']) || is_callable($this->config['resolveType']),
|
||||||
|
"{$this->name} must provide \"resolveType\" as a function."
|
||||||
|
);
|
||||||
|
|
||||||
|
Utils::invariant(
|
||||||
|
!empty($fields),
|
||||||
|
"{$this->name} fields must not be empty"
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($fields as $field) {
|
||||||
|
$field->assertValid($this);
|
||||||
|
foreach ($field->args as $arg) {
|
||||||
|
$arg->assertValid($field, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Type\Definition;
|
namespace GraphQL\Type\Definition;
|
||||||
|
|
||||||
|
use GraphQL\Error\InvariantViolation;
|
||||||
use GraphQL\Utils\Utils;
|
use GraphQL\Utils\Utils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -19,11 +20,11 @@ class ListOfType extends Type implements WrappingType, OutputType, InputType
|
|||||||
*/
|
*/
|
||||||
public function __construct($type)
|
public function __construct($type)
|
||||||
{
|
{
|
||||||
Utils::invariant(
|
if (!$type instanceof Type && !is_callable($type)) {
|
||||||
$type instanceof Type || is_callable($type),
|
throw new InvariantViolation(
|
||||||
'Expecting instance of GraphQL\Type\Definition\Type or callable returning instance of that class'
|
'Can only create List of a GraphQLType but got: ' . Utils::printSafe($type)
|
||||||
);
|
);
|
||||||
|
}
|
||||||
$this->ofType = $type;
|
$this->ofType = $type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Type\Definition;
|
namespace GraphQL\Type\Definition;
|
||||||
|
|
||||||
|
use GraphQL\Error\InvariantViolation;
|
||||||
use GraphQL\Utils\Utils;
|
use GraphQL\Utils\Utils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -20,10 +21,16 @@ class NonNull extends Type implements WrappingType, OutputType, InputType
|
|||||||
*/
|
*/
|
||||||
public function __construct($type)
|
public function __construct($type)
|
||||||
{
|
{
|
||||||
Utils::invariant(
|
if (!$type instanceof Type && !is_callable($type)) {
|
||||||
$type instanceof Type || is_callable($type),
|
throw new InvariantViolation(
|
||||||
'Expecting instance of GraphQL\Type\Definition\Type or callable returning instance of that class'
|
'Can only create NonNull of a Nullable GraphQLType but got: ' . Utils::printSafe($type)
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
if ($type instanceof NonNull) {
|
||||||
|
throw new InvariantViolation(
|
||||||
|
'Can only create NonNull of a Nullable GraphQLType but got: ' . Utils::printSafe($type)
|
||||||
|
);
|
||||||
|
}
|
||||||
Utils::invariant(
|
Utils::invariant(
|
||||||
!($type instanceof NonNull),
|
!($type instanceof NonNull),
|
||||||
'Cannot nest NonNull inside NonNull'
|
'Cannot nest NonNull inside NonNull'
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Type\Definition;
|
namespace GraphQL\Type\Definition;
|
||||||
use GraphQL\Error\Error;
|
|
||||||
use GraphQL\Error\InvariantViolation;
|
use GraphQL\Error\InvariantViolation;
|
||||||
use GraphQL\Utils\Utils;
|
use GraphQL\Utils\Utils;
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ class ObjectType extends Type implements OutputType, CompositeType
|
|||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private $interfaceMap = [];
|
private $interfaceMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keeping reference of config for late bindings and custom app-level metadata
|
* Keeping reference of config for late bindings and custom app-level metadata
|
||||||
@ -111,13 +111,13 @@ class ObjectType extends Type implements OutputType, CompositeType
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @return FieldDefinition[]
|
* @return FieldDefinition[]
|
||||||
|
* @throws InvariantViolation
|
||||||
*/
|
*/
|
||||||
public function getFields()
|
public function getFields()
|
||||||
{
|
{
|
||||||
if (null === $this->fields) {
|
if (null === $this->fields) {
|
||||||
$fields = isset($this->config['fields']) ? $this->config['fields'] : [];
|
$fields = isset($this->config['fields']) ? $this->config['fields'] : [];
|
||||||
$fields = is_callable($fields) ? call_user_func($fields) : $fields;
|
$this->fields = FieldDefinition::defineFieldMap($this, $fields);
|
||||||
$this->fields = FieldDefinition::createMap($fields, $this->name);
|
|
||||||
}
|
}
|
||||||
return $this->fields;
|
return $this->fields;
|
||||||
}
|
}
|
||||||
@ -132,9 +132,7 @@ class ObjectType extends Type implements OutputType, CompositeType
|
|||||||
if (null === $this->fields) {
|
if (null === $this->fields) {
|
||||||
$this->getFields();
|
$this->getFields();
|
||||||
}
|
}
|
||||||
if (!isset($this->fields[$name])) {
|
Utils::invariant(isset($this->fields[$name]), 'Field "%s" is not defined for type "%s"', $name, $this->name);
|
||||||
throw new Error(sprintf("Field '%s' is not defined for type '%s'", $name, $this->name));
|
|
||||||
}
|
|
||||||
return $this->fields[$name];
|
return $this->fields[$name];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,11 +145,21 @@ class ObjectType extends Type implements OutputType, CompositeType
|
|||||||
$interfaces = isset($this->config['interfaces']) ? $this->config['interfaces'] : [];
|
$interfaces = isset($this->config['interfaces']) ? $this->config['interfaces'] : [];
|
||||||
$interfaces = is_callable($interfaces) ? call_user_func($interfaces) : $interfaces;
|
$interfaces = is_callable($interfaces) ? call_user_func($interfaces) : $interfaces;
|
||||||
|
|
||||||
|
if (!is_array($interfaces)) {
|
||||||
|
throw new InvariantViolation(
|
||||||
|
"{$this->name} interfaces must be an Array or a callable which returns an Array."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
$this->interfaces = [];
|
$this->interfaces = [];
|
||||||
foreach ($interfaces as $iface) {
|
foreach ($interfaces as $iface) {
|
||||||
$iface = Type::resolve($iface);
|
$iface = Type::resolve($iface);
|
||||||
if (!$iface instanceof InterfaceType) {
|
if (!$iface instanceof InterfaceType) {
|
||||||
throw new InvariantViolation(sprintf('Expecting interface type, got %s', Utils::printSafe($iface)));
|
throw new InvariantViolation(sprintf(
|
||||||
|
'%s may only implement Interface types, it cannot implement %s',
|
||||||
|
$this->name,
|
||||||
|
Utils::printSafe($iface)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
// TODO: return interfaceMap vs interfaces. Possibly breaking change?
|
// TODO: return interfaceMap vs interfaces. Possibly breaking change?
|
||||||
$this->interfaces[] = $iface;
|
$this->interfaces[] = $iface;
|
||||||
@ -161,6 +169,17 @@ class ObjectType extends Type implements OutputType, CompositeType
|
|||||||
return $this->interfaces;
|
return $this->interfaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getInterfaceMap()
|
||||||
|
{
|
||||||
|
if (!$this->interfaceMap) {
|
||||||
|
$this->interfaceMap = [];
|
||||||
|
foreach ($this->getInterfaces() as $interface) {
|
||||||
|
$this->interfaceMap[$interface->name] = $interface;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $this->interfaceMap;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param InterfaceType $iface
|
* @param InterfaceType $iface
|
||||||
* @return bool
|
* @return bool
|
||||||
@ -182,4 +201,61 @@ class ObjectType extends Type implements OutputType, CompositeType
|
|||||||
{
|
{
|
||||||
return isset($this->config['isTypeOf']) ? call_user_func($this->config['isTypeOf'], $value, $context, $info) : null;
|
return isset($this->config['isTypeOf']) ? call_user_func($this->config['isTypeOf'], $value, $context, $info) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates type config and throws if one of type options is invalid.
|
||||||
|
* Note: this method is shallow, it won't validate object fields and their arguments.
|
||||||
|
*
|
||||||
|
* @throws InvariantViolation
|
||||||
|
*/
|
||||||
|
public function assertValid()
|
||||||
|
{
|
||||||
|
parent::assertValid();
|
||||||
|
|
||||||
|
Utils::invariant(
|
||||||
|
null === $this->description || is_string($this->description),
|
||||||
|
"{$this->name} description must be string if set, but it is: " . Utils::printSafe($this->description)
|
||||||
|
);
|
||||||
|
|
||||||
|
Utils::invariant(
|
||||||
|
!isset($this->config['isTypeOf']) || is_callable($this->config['isTypeOf']),
|
||||||
|
"{$this->name} must provide 'isTypeOf' as a function"
|
||||||
|
);
|
||||||
|
|
||||||
|
// getFields() and getInterfaceMap() will do structural validation
|
||||||
|
$fields = $this->getFields();
|
||||||
|
Utils::invariant(
|
||||||
|
!empty($fields),
|
||||||
|
"{$this->name} fields must not be empty"
|
||||||
|
);
|
||||||
|
foreach ($fields as $field) {
|
||||||
|
$field->assertValid($this);
|
||||||
|
foreach ($field->args as $arg) {
|
||||||
|
$arg->assertValid($field, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$implemented = [];
|
||||||
|
foreach ($this->getInterfaces() as $iface) {
|
||||||
|
Utils::invariant(
|
||||||
|
$iface instanceof InterfaceType,
|
||||||
|
"{$this->name} may only implement Interface types, it cannot implement: %s.",
|
||||||
|
Utils::printSafe($iface)
|
||||||
|
);
|
||||||
|
Utils::invariant(
|
||||||
|
!isset($implemented[$iface->name]),
|
||||||
|
"{$this->name} may declare it implements {$iface->name} only once."
|
||||||
|
);
|
||||||
|
$implemented[$iface->name] = true;
|
||||||
|
if (!isset($iface->config['resolveType'])) {
|
||||||
|
Utils::invariant(
|
||||||
|
isset($this->config['isTypeOf']),
|
||||||
|
"Interface Type {$iface->name} does not provide a \"resolveType\" " .
|
||||||
|
"function and implementing Type {$this->name} does not provide a " .
|
||||||
|
'"isTypeOf" function. There is no way to resolve this implementing ' .
|
||||||
|
'type during execution.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,6 +237,13 @@ abstract class Type implements \JsonSerializable
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws InvariantViolation
|
||||||
|
*/
|
||||||
|
public function assertValid()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Type\Definition;
|
namespace GraphQL\Type\Definition;
|
||||||
|
|
||||||
|
use GraphQL\Error\InvariantViolation;
|
||||||
use GraphQL\Utils\Utils;
|
use GraphQL\Utils\Utils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,17 +69,19 @@ class UnionType extends Type implements AbstractType, OutputType, CompositeType
|
|||||||
public function getTypes()
|
public function getTypes()
|
||||||
{
|
{
|
||||||
if (null === $this->types) {
|
if (null === $this->types) {
|
||||||
if ($this->config['types'] instanceof \Closure) {
|
if (!isset($this->config['types'])) {
|
||||||
|
$types = null;
|
||||||
|
} else if (is_callable($this->config['types'])) {
|
||||||
$types = call_user_func($this->config['types']);
|
$types = call_user_func($this->config['types']);
|
||||||
} else {
|
} else {
|
||||||
$types = $this->config['types'];
|
$types = $this->config['types'];
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::invariant(
|
if (!is_array($types)) {
|
||||||
is_array($types),
|
throw new InvariantViolation(
|
||||||
'Option "types" of union "%s" is expected to return array of types (or closure returning array of types)',
|
"{$this->name} types must be an Array or a callable which returns an Array."
|
||||||
$this->name
|
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
$this->types = [];
|
$this->types = [];
|
||||||
foreach ($types as $type) {
|
foreach ($types as $type) {
|
||||||
@ -123,4 +126,48 @@ class UnionType extends Type implements AbstractType, OutputType, CompositeType
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws InvariantViolation
|
||||||
|
*/
|
||||||
|
public function assertValid()
|
||||||
|
{
|
||||||
|
parent::assertValid();
|
||||||
|
|
||||||
|
$types = $this->getTypes();
|
||||||
|
Utils::invariant(
|
||||||
|
!empty($types),
|
||||||
|
"{$this->name} types must not be empty"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isset($this->config['resolveType'])) {
|
||||||
|
Utils::invariant(
|
||||||
|
is_callable($this->config['resolveType']),
|
||||||
|
"{$this->name} must provide \"resolveType\" as a function."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$includedTypeNames = [];
|
||||||
|
foreach ($types as $objType) {
|
||||||
|
Utils::invariant(
|
||||||
|
$objType instanceof ObjectType,
|
||||||
|
"{$this->name} may only contain Object types, it cannot contain: %s.",
|
||||||
|
Utils::printSafe($objType)
|
||||||
|
);
|
||||||
|
Utils::invariant(
|
||||||
|
!isset($includedTypeNames[$objType->name]),
|
||||||
|
"{$this->name} can include {$objType->name} type only once."
|
||||||
|
);
|
||||||
|
$includedTypeNames[$objType->name] = true;
|
||||||
|
if (!isset($this->config['resolveType'])) {
|
||||||
|
Utils::invariant(
|
||||||
|
isset($objType->config['isTypeOf']) && is_callable($objType->config['isTypeOf']),
|
||||||
|
"Union type \"{$this->name}\" does not provide a \"resolveType\" " .
|
||||||
|
"function and possible type \"{$objType->name}\" does not provide an " .
|
||||||
|
'"isTypeOf" function. There is no way to resolve this possible type ' .
|
||||||
|
'during execution.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -390,4 +390,111 @@ class Schema
|
|||||||
}
|
}
|
||||||
return $this->resolvedTypes[$typeName];
|
return $this->resolvedTypes[$typeName];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws InvariantViolation
|
||||||
|
*/
|
||||||
|
public function assertValid()
|
||||||
|
{
|
||||||
|
foreach ($this->config->getDirectives() as $index => $directive) {
|
||||||
|
Utils::invariant(
|
||||||
|
$directive instanceof Directive,
|
||||||
|
"Each entry of \"directives\" option of Schema config must be an instance of %s but entry at position %d is %s.",
|
||||||
|
Directive::class,
|
||||||
|
$index,
|
||||||
|
Utils::printSafe($directive)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->getTypeMap() as $name => $type) {
|
||||||
|
$type->assertValid();
|
||||||
|
|
||||||
|
if ($type instanceof AbstractType) {
|
||||||
|
$possibleTypes = $this->getPossibleTypes($type);
|
||||||
|
|
||||||
|
Utils::invariant(
|
||||||
|
!empty($possibleTypes),
|
||||||
|
"Could not find possible implementing types for {$type->name} " .
|
||||||
|
'in schema. Check that schema.types is defined and is an array of ' .
|
||||||
|
'all possible types in the schema.'
|
||||||
|
);
|
||||||
|
|
||||||
|
} else if ($type instanceof ObjectType) {
|
||||||
|
foreach ($type->getInterfaces() as $iface) {
|
||||||
|
$this->assertImplementsIntarface($type, $iface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function assertImplementsIntarface(ObjectType $object, InterfaceType $iface)
|
||||||
|
{
|
||||||
|
$objectFieldMap = $object->getFields();
|
||||||
|
$ifaceFieldMap = $iface->getFields();
|
||||||
|
|
||||||
|
// Assert each interface field is implemented.
|
||||||
|
foreach ($ifaceFieldMap as $fieldName => $ifaceField) {
|
||||||
|
|
||||||
|
// Assert interface field exists on object.
|
||||||
|
Utils::invariant(
|
||||||
|
isset($objectFieldMap[$fieldName]),
|
||||||
|
"{$iface->name} expects field \"{$fieldName}\" but {$object->name} does not provide it"
|
||||||
|
);
|
||||||
|
|
||||||
|
$objectField = $objectFieldMap[$fieldName];
|
||||||
|
|
||||||
|
// Assert interface field type is satisfied by object field type, by being
|
||||||
|
// a valid subtype. (covariant)
|
||||||
|
Utils::invariant(
|
||||||
|
TypeComparators::isTypeSubTypeOf($this, $objectField->getType(), $ifaceField->getType()),
|
||||||
|
"{$iface->name}.{$fieldName} expects type \"{$ifaceField->getType()}\" " .
|
||||||
|
"but " .
|
||||||
|
"{$object->name}.${fieldName} provides type \"{$objectField->getType()}\""
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert each interface field arg is implemented.
|
||||||
|
foreach ($ifaceField->args as $ifaceArg) {
|
||||||
|
$argName = $ifaceArg->name;
|
||||||
|
|
||||||
|
/** @var FieldArgument $objectArg */
|
||||||
|
$objectArg = Utils::find($objectField->args, function(FieldArgument $arg) use ($argName) {
|
||||||
|
return $arg->name === $argName;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert interface field arg exists on object field.
|
||||||
|
Utils::invariant(
|
||||||
|
$objectArg,
|
||||||
|
"{$iface->name}.{$fieldName} expects argument \"{$argName}\" but ".
|
||||||
|
"{$object->name}.{$fieldName} does not provide it."
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert interface field arg type matches object field arg type.
|
||||||
|
// (invariant)
|
||||||
|
Utils::invariant(
|
||||||
|
TypeComparators::isEqualType($ifaceArg->getType(), $objectArg->getType()),
|
||||||
|
"{$iface->name}.{$fieldName}({$argName}:) expects type " .
|
||||||
|
"\"{$ifaceArg->getType()->name}\" but " .
|
||||||
|
"{$object->name}.{$fieldName}({$argName}:) provides type " .
|
||||||
|
"\"{$objectArg->getType()->name}\"."
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert additional arguments must not be required.
|
||||||
|
foreach ($objectField->args as $objectArg) {
|
||||||
|
$argName = $objectArg->name;
|
||||||
|
$ifaceArg = Utils::find($ifaceField->args, function(FieldArgument $arg) use ($argName) {
|
||||||
|
return $arg->name === $argName;
|
||||||
|
});
|
||||||
|
if (!$ifaceArg) {
|
||||||
|
Utils::invariant(
|
||||||
|
!($objectArg->getType() instanceof NonNull),
|
||||||
|
"{$object->name}.{$fieldName}({$argName}:) is of required type " .
|
||||||
|
"\"{$objectArg->getType()}\" but is not also provided by the " .
|
||||||
|
"interface {$iface->name}.{$fieldName}."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Type;
|
namespace GraphQL\Type;
|
||||||
|
|
||||||
|
use GraphQL\Error\InvariantViolation;
|
||||||
use GraphQL\Type\Descriptor;
|
use GraphQL\Type\Descriptor;
|
||||||
use GraphQL\Type\Definition\Directive;
|
use GraphQL\Type\Definition\Directive;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
@ -203,7 +204,7 @@ class SchemaConfig
|
|||||||
*/
|
*/
|
||||||
public function getDirectives()
|
public function getDirectives()
|
||||||
{
|
{
|
||||||
return $this->directives;
|
return $this->directives ?: [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
137
src/Utils/TypeComparators.php
Normal file
137
src/Utils/TypeComparators.php
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
<?php
|
||||||
|
namespace GraphQL\Utils;
|
||||||
|
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
|
use GraphQL\Type\Definition\AbstractType;
|
||||||
|
use GraphQL\Type\Definition\CompositeType;
|
||||||
|
use GraphQL\Type\Definition\ListOfType;
|
||||||
|
use GraphQL\Type\Definition\NonNull;
|
||||||
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
|
use GraphQL\Type\Definition\Type;
|
||||||
|
|
||||||
|
class TypeComparators
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Provided two types, return true if the types are equal (invariant).
|
||||||
|
*
|
||||||
|
* @param Type $typeA
|
||||||
|
* @param Type $typeB
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function isEqualType(Type $typeA, Type $typeB)
|
||||||
|
{
|
||||||
|
// Equivalent types are equal.
|
||||||
|
if ($typeA === $typeB) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If either type is non-null, the other must also be non-null.
|
||||||
|
if ($typeA instanceof NonNull && $typeB instanceof NonNull) {
|
||||||
|
return self::isEqualType($typeA->getWrappedType(), $typeB->getWrappedType());
|
||||||
|
}
|
||||||
|
|
||||||
|
// If either type is a list, the other must also be a list.
|
||||||
|
if ($typeA instanceof ListOfType && $typeB instanceof ListOfType) {
|
||||||
|
return self::isEqualType($typeA->getWrappedType(), $typeB->getWrappedType());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise the types are not equal.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provided a type and a super type, return true if the first type is either
|
||||||
|
* equal or a subset of the second super type (covariant).
|
||||||
|
*
|
||||||
|
* @param Schema $schema
|
||||||
|
* @param Type $maybeSubType
|
||||||
|
* @param Type $superType
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
static function isTypeSubTypeOf(Schema $schema, Type $maybeSubType, Type $superType)
|
||||||
|
{
|
||||||
|
// Equivalent type is a valid subtype
|
||||||
|
if ($maybeSubType === $superType) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If superType is non-null, maybeSubType must also be nullable.
|
||||||
|
if ($superType instanceof NonNull) {
|
||||||
|
if ($maybeSubType instanceof NonNull) {
|
||||||
|
return self::isTypeSubTypeOf($schema, $maybeSubType->getWrappedType(), $superType->getWrappedType());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else if ($maybeSubType instanceof NonNull) {
|
||||||
|
// If superType is nullable, maybeSubType may be non-null.
|
||||||
|
return self::isTypeSubTypeOf($schema, $maybeSubType->getWrappedType(), $superType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If superType type is a list, maybeSubType type must also be a list.
|
||||||
|
if ($superType instanceof ListOfType) {
|
||||||
|
if ($maybeSubType instanceof ListOfType) {
|
||||||
|
return self::isTypeSubTypeOf($schema, $maybeSubType->getWrappedType(), $superType->getWrappedType());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else if ($maybeSubType instanceof ListOfType) {
|
||||||
|
// If superType is not a list, maybeSubType must also be not a list.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If superType type is an abstract type, maybeSubType type may be a currently
|
||||||
|
// possible object type.
|
||||||
|
if (Type::isAbstractType($superType) && $maybeSubType instanceof ObjectType && $schema->isPossibleType($superType, $maybeSubType)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, the child type is not a valid subtype of the parent type.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provided two composite types, determine if they "overlap". Two composite
|
||||||
|
* types overlap when the Sets of possible concrete types for each intersect.
|
||||||
|
*
|
||||||
|
* This is often used to determine if a fragment of a given type could possibly
|
||||||
|
* be visited in a context of another type.
|
||||||
|
*
|
||||||
|
* This function is commutative.
|
||||||
|
*
|
||||||
|
* @param Schema $schema
|
||||||
|
* @param CompositeType $typeA
|
||||||
|
* @param CompositeType $typeB
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
static function doTypesOverlap(Schema $schema, CompositeType $typeA, CompositeType $typeB)
|
||||||
|
{
|
||||||
|
// Equivalent types overlap
|
||||||
|
if ($typeA === $typeB) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($typeA instanceof AbstractType) {
|
||||||
|
if ($typeB instanceof AbstractType) {
|
||||||
|
// If both types are abstract, then determine if there is any intersection
|
||||||
|
// between possible concrete types of each.
|
||||||
|
foreach ($schema->getPossibleTypes($typeA) as $type) {
|
||||||
|
if ($schema->isPossibleType($typeB, $type)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var $typeB ObjectType */
|
||||||
|
// Determine if the latter type is a possible concrete type of the former.
|
||||||
|
return $schema->isPossibleType($typeA, $typeB);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($typeB instanceof AbstractType) {
|
||||||
|
/** @var $typeA ObjectType */
|
||||||
|
// Determine if the former type is a possible concrete type of the latter.
|
||||||
|
return $schema->isPossibleType($typeB, $typeA);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise the types do not overlap.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -7,8 +7,7 @@ use GraphQL\Language\AST\NamedTypeNode;
|
|||||||
use GraphQL\Language\AST\Node;
|
use GraphQL\Language\AST\Node;
|
||||||
use GraphQL\Language\AST\NodeKind;
|
use GraphQL\Language\AST\NodeKind;
|
||||||
use GraphQL\Language\AST\NonNullTypeNode;
|
use GraphQL\Language\AST\NonNullTypeNode;
|
||||||
use GraphQL\Schema;
|
use GraphQL\Type\Schema;
|
||||||
use GraphQL\Type\Definition\AbstractType;
|
|
||||||
use GraphQL\Type\Definition\CompositeType;
|
use GraphQL\Type\Definition\CompositeType;
|
||||||
use GraphQL\Type\Definition\Directive;
|
use GraphQL\Type\Definition\Directive;
|
||||||
use GraphQL\Type\Definition\EnumType;
|
use GraphQL\Type\Definition\EnumType;
|
||||||
@ -32,114 +31,27 @@ use GraphQL\Type\Introspection;
|
|||||||
class TypeInfo
|
class TypeInfo
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Provided two types, return true if the types are equal (invariant).
|
* @deprecated moved to GraphQL\Utils\TypeComparators
|
||||||
*/
|
*/
|
||||||
public static function isEqualType(Type $typeA, Type $typeB)
|
public static function isEqualType(Type $typeA, Type $typeB)
|
||||||
{
|
{
|
||||||
// Equivalent types are equal.
|
return TypeComparators::isEqualType($typeA, $typeB);
|
||||||
if ($typeA === $typeB) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If either type is non-null, the other must also be non-null.
|
|
||||||
if ($typeA instanceof NonNull && $typeB instanceof NonNull) {
|
|
||||||
return self::isEqualType($typeA->getWrappedType(), $typeB->getWrappedType());
|
|
||||||
}
|
|
||||||
|
|
||||||
// If either type is a list, the other must also be a list.
|
|
||||||
if ($typeA instanceof ListOfType && $typeB instanceof ListOfType) {
|
|
||||||
return self::isEqualType($typeA->getWrappedType(), $typeB->getWrappedType());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise the types are not equal.
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provided a type and a super type, return true if the first type is either
|
* @deprecated moved to GraphQL\Utils\TypeComparators
|
||||||
* equal or a subset of the second super type (covariant).
|
|
||||||
*/
|
*/
|
||||||
static function isTypeSubTypeOf(Schema $schema, Type $maybeSubType, Type $superType)
|
static function isTypeSubTypeOf(Schema $schema, Type $maybeSubType, Type $superType)
|
||||||
{
|
{
|
||||||
// Equivalent type is a valid subtype
|
return TypeComparators::isTypeSubTypeOf($schema, $maybeSubType, $superType);
|
||||||
if ($maybeSubType === $superType) {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If superType is non-null, maybeSubType must also be nullable.
|
|
||||||
if ($superType instanceof NonNull) {
|
|
||||||
if ($maybeSubType instanceof NonNull) {
|
|
||||||
return self::isTypeSubTypeOf($schema, $maybeSubType->getWrappedType(), $superType->getWrappedType());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} else if ($maybeSubType instanceof NonNull) {
|
|
||||||
// If superType is nullable, maybeSubType may be non-null.
|
|
||||||
return self::isTypeSubTypeOf($schema, $maybeSubType->getWrappedType(), $superType);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If superType type is a list, maybeSubType type must also be a list.
|
|
||||||
if ($superType instanceof ListOfType) {
|
|
||||||
if ($maybeSubType instanceof ListOfType) {
|
|
||||||
return self::isTypeSubTypeOf($schema, $maybeSubType->getWrappedType(), $superType->getWrappedType());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} else if ($maybeSubType instanceof ListOfType) {
|
|
||||||
// If superType is not a list, maybeSubType must also be not a list.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If superType type is an abstract type, maybeSubType type may be a currently
|
|
||||||
// possible object type.
|
|
||||||
if (Type::isAbstractType($superType) && $maybeSubType instanceof ObjectType && $schema->isPossibleType($superType, $maybeSubType)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, the child type is not a valid subtype of the parent type.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provided two composite types, determine if they "overlap". Two composite
|
* @deprecated moved to GraphQL\Utils\TypeComparators
|
||||||
* types overlap when the Sets of possible concrete types for each intersect.
|
|
||||||
*
|
|
||||||
* This is often used to determine if a fragment of a given type could possibly
|
|
||||||
* be visited in a context of another type.
|
|
||||||
*
|
|
||||||
* This function is commutative.
|
|
||||||
*/
|
*/
|
||||||
static function doTypesOverlap(Schema $schema, CompositeType $typeA, CompositeType $typeB)
|
static function doTypesOverlap(Schema $schema, CompositeType $typeA, CompositeType $typeB)
|
||||||
{
|
{
|
||||||
// Equivalent types overlap
|
return TypeComparators::doTypesOverlap($schema, $typeA, $typeB);
|
||||||
if ($typeA === $typeB) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($typeA instanceof AbstractType) {
|
|
||||||
if ($typeB instanceof AbstractType) {
|
|
||||||
// If both types are abstract, then determine if there is any intersection
|
|
||||||
// between possible concrete types of each.
|
|
||||||
foreach ($schema->getPossibleTypes($typeA) as $type) {
|
|
||||||
if ($schema->isPossibleType($typeB, $type)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @var $typeB ObjectType */
|
|
||||||
// Determine if the latter type is a possible concrete type of the former.
|
|
||||||
return $schema->isPossibleType($typeA, $typeB);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($typeB instanceof AbstractType) {
|
|
||||||
/** @var $typeA ObjectType */
|
|
||||||
// Determine if the former type is a possible concrete type of the latter.
|
|
||||||
return $schema->isPossibleType($typeB, $typeA);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise the types do not overlap.
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -218,7 +218,7 @@ class Utils
|
|||||||
* @param string $message
|
* @param string $message
|
||||||
* @param mixed $sprintfParam1
|
* @param mixed $sprintfParam1
|
||||||
* @param mixed $sprintfParam2 ...
|
* @param mixed $sprintfParam2 ...
|
||||||
* @throws \Exception
|
* @throws InvariantViolation
|
||||||
*/
|
*/
|
||||||
public static function invariant($test, $message = '')
|
public static function invariant($test, $message = '')
|
||||||
{
|
{
|
||||||
@ -420,7 +420,7 @@ class Utils
|
|||||||
/**
|
/**
|
||||||
* @param $name
|
* @param $name
|
||||||
* @param bool $isIntrospection
|
* @param bool $isIntrospection
|
||||||
* @throws Error
|
* @throws InvariantViolation
|
||||||
*/
|
*/
|
||||||
public static function assertValidName($name, $isIntrospection = false)
|
public static function assertValidName($name, $isIntrospection = false)
|
||||||
{
|
{
|
||||||
|
@ -7,6 +7,7 @@ use GraphQL\Language\AST\OperationDefinitionNode;
|
|||||||
use GraphQL\Language\AST\VariableDefinitionNode;
|
use GraphQL\Language\AST\VariableDefinitionNode;
|
||||||
use GraphQL\Type\Definition\ListOfType;
|
use GraphQL\Type\Definition\ListOfType;
|
||||||
use GraphQL\Type\Definition\NonNull;
|
use GraphQL\Type\Definition\NonNull;
|
||||||
|
use GraphQL\Utils\TypeComparators;
|
||||||
use GraphQL\Utils\TypeInfo;
|
use GraphQL\Utils\TypeInfo;
|
||||||
use GraphQL\Validator\ValidationContext;
|
use GraphQL\Validator\ValidationContext;
|
||||||
|
|
||||||
@ -45,7 +46,7 @@ class VariablesInAllowedPosition
|
|||||||
$schema = $context->getSchema();
|
$schema = $context->getSchema();
|
||||||
$varType = TypeInfo::typeFromAST($schema, $varDef->type);
|
$varType = TypeInfo::typeFromAST($schema, $varDef->type);
|
||||||
|
|
||||||
if ($varType && !TypeInfo::isTypeSubTypeOf($schema, $this->effectiveType($varType, $varDef), $type)) {
|
if ($varType && !TypeComparators::isTypeSubTypeOf($schema, $this->effectiveType($varType, $varDef), $type)) {
|
||||||
$context->reportError(new Error(
|
$context->reportError(new Error(
|
||||||
self::badVarPosMessage($varName, $varType, $type),
|
self::badVarPosMessage($varName, $varType, $type),
|
||||||
[$varDef, $node]
|
[$varDef, $node]
|
||||||
|
@ -62,12 +62,12 @@ class LazyInterfaceTest extends \PHPUnit_Framework_TestCase
|
|||||||
if (!$this->lazyInterface) {
|
if (!$this->lazyInterface) {
|
||||||
$this->lazyInterface = new InterfaceType([
|
$this->lazyInterface = new InterfaceType([
|
||||||
'name' => 'LazyInterface',
|
'name' => 'LazyInterface',
|
||||||
|
'fields' => [
|
||||||
|
'a' => Type::string()
|
||||||
|
],
|
||||||
'resolveType' => function() {
|
'resolveType' => function() {
|
||||||
return $this->getTestObjectType();
|
return $this->getTestObjectType();
|
||||||
},
|
},
|
||||||
'resolve' => function() {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ class ServerTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
public function testSchemaDefinition()
|
public function testSchemaDefinition()
|
||||||
{
|
{
|
||||||
$mutationType = $queryType = $subscriptionType = new ObjectType(['name' => 'A', 'fields' => []]);
|
$mutationType = $queryType = $subscriptionType = new ObjectType(['name' => 'A', 'fields' => ['a' => Type::string()]]);
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
'query' => $queryType
|
'query' => $queryType
|
||||||
@ -283,7 +283,7 @@ class ServerTest extends \PHPUnit_Framework_TestCase
|
|||||||
public function testValidate()
|
public function testValidate()
|
||||||
{
|
{
|
||||||
$server = Server::create()
|
$server = Server::create()
|
||||||
->setQueryType(new ObjectType(['name' => 'Q', 'fields' => []]));
|
->setQueryType(new ObjectType(['name' => 'Q', 'fields' => ['a' => Type::string()]]));
|
||||||
|
|
||||||
$ast = $server->parse('{q}');
|
$ast = $server->parse('{q}');
|
||||||
$errors = $server->validate($ast);
|
$errors = $server->validate($ast);
|
||||||
|
@ -243,11 +243,11 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
$value = $enumTypeWithDeprecatedValue->getValues()[0];
|
$value = $enumTypeWithDeprecatedValue->getValues()[0];
|
||||||
|
|
||||||
$this->assertEquals([
|
$this->assertArraySubset([
|
||||||
'name' => 'foo',
|
'name' => 'foo',
|
||||||
'description' => null,
|
'description' => null,
|
||||||
'deprecationReason' => 'Just because',
|
'deprecationReason' => 'Just because',
|
||||||
'value' => 'foo'
|
'value' => 'foo',
|
||||||
], (array) $value);
|
], (array) $value);
|
||||||
|
|
||||||
$this->assertEquals(true, $value->isDeprecated());
|
$this->assertEquals(true, $value->isDeprecated());
|
||||||
@ -284,8 +284,8 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase
|
|||||||
$actual = $EnumTypeWithNullishValue->getValues();
|
$actual = $EnumTypeWithNullishValue->getValues();
|
||||||
|
|
||||||
$this->assertEquals(count($expected), count($actual));
|
$this->assertEquals(count($expected), count($actual));
|
||||||
$this->assertEquals($expected[0], (array)$actual[0]);
|
$this->assertArraySubset($expected[0], (array)$actual[0]);
|
||||||
$this->assertEquals($expected[1], (array)$actual[1]);
|
$this->assertArraySubset($expected[1], (array)$actual[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,7 +24,7 @@ class IntrospectionTest extends \PHPUnit_Framework_TestCase
|
|||||||
$emptySchema = new Schema([
|
$emptySchema = new Schema([
|
||||||
'query' => new ObjectType([
|
'query' => new ObjectType([
|
||||||
'name' => 'QueryRoot',
|
'name' => 'QueryRoot',
|
||||||
'fields' => []
|
'fields' => ['a' => Type::string()]
|
||||||
])
|
])
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -42,7 +42,6 @@ class IntrospectionTest extends \PHPUnit_Framework_TestCase
|
|||||||
),
|
),
|
||||||
'types' =>
|
'types' =>
|
||||||
array (
|
array (
|
||||||
0 =>
|
|
||||||
array (
|
array (
|
||||||
'kind' => 'OBJECT',
|
'kind' => 'OBJECT',
|
||||||
'name' => 'QueryRoot',
|
'name' => 'QueryRoot',
|
||||||
@ -52,9 +51,29 @@ class IntrospectionTest extends \PHPUnit_Framework_TestCase
|
|||||||
),
|
),
|
||||||
'enumValues' => NULL,
|
'enumValues' => NULL,
|
||||||
'possibleTypes' => NULL,
|
'possibleTypes' => NULL,
|
||||||
'fields' => Array ()
|
'fields' => array (
|
||||||
|
array (
|
||||||
|
'name' => 'a',
|
||||||
|
'args' => array(),
|
||||||
|
'type' => array(
|
||||||
|
'kind' => 'SCALAR',
|
||||||
|
'name' => 'String',
|
||||||
|
'ofType' => null
|
||||||
|
),
|
||||||
|
'isDeprecated' => false,
|
||||||
|
'deprecationReason' => null,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
array (
|
||||||
|
'kind' => 'SCALAR',
|
||||||
|
'name' => 'String',
|
||||||
|
'fields' => NULL,
|
||||||
|
'inputFields' => NULL,
|
||||||
|
'interfaces' => NULL,
|
||||||
|
'enumValues' => NULL,
|
||||||
|
'possibleTypes' => NULL,
|
||||||
),
|
),
|
||||||
1 =>
|
|
||||||
array (
|
array (
|
||||||
'kind' => 'OBJECT',
|
'kind' => 'OBJECT',
|
||||||
'name' => '__Schema',
|
'name' => '__Schema',
|
||||||
@ -108,7 +127,6 @@ class IntrospectionTest extends \PHPUnit_Framework_TestCase
|
|||||||
'isDeprecated' => false,
|
'isDeprecated' => false,
|
||||||
'deprecationReason' => NULL,
|
'deprecationReason' => NULL,
|
||||||
),
|
),
|
||||||
2 =>
|
|
||||||
array (
|
array (
|
||||||
'name' => 'mutationType',
|
'name' => 'mutationType',
|
||||||
'args' =>
|
'args' =>
|
||||||
@ -122,7 +140,6 @@ class IntrospectionTest extends \PHPUnit_Framework_TestCase
|
|||||||
'isDeprecated' => false,
|
'isDeprecated' => false,
|
||||||
'deprecationReason' => NULL,
|
'deprecationReason' => NULL,
|
||||||
),
|
),
|
||||||
3 =>
|
|
||||||
array (
|
array (
|
||||||
'name' => 'subscriptionType',
|
'name' => 'subscriptionType',
|
||||||
'args' =>
|
'args' =>
|
||||||
@ -136,7 +153,6 @@ class IntrospectionTest extends \PHPUnit_Framework_TestCase
|
|||||||
'isDeprecated' => false,
|
'isDeprecated' => false,
|
||||||
'deprecationReason' => NULL,
|
'deprecationReason' => NULL,
|
||||||
),
|
),
|
||||||
4 =>
|
|
||||||
array (
|
array (
|
||||||
'name' => 'directives',
|
'name' => 'directives',
|
||||||
'args' =>
|
'args' =>
|
||||||
@ -173,7 +189,6 @@ class IntrospectionTest extends \PHPUnit_Framework_TestCase
|
|||||||
'enumValues' => NULL,
|
'enumValues' => NULL,
|
||||||
'possibleTypes' => NULL,
|
'possibleTypes' => NULL,
|
||||||
),
|
),
|
||||||
2 =>
|
|
||||||
array (
|
array (
|
||||||
'kind' => 'OBJECT',
|
'kind' => 'OBJECT',
|
||||||
'name' => '__Type',
|
'name' => '__Type',
|
||||||
@ -388,7 +403,6 @@ class IntrospectionTest extends \PHPUnit_Framework_TestCase
|
|||||||
'enumValues' => NULL,
|
'enumValues' => NULL,
|
||||||
'possibleTypes' => NULL,
|
'possibleTypes' => NULL,
|
||||||
),
|
),
|
||||||
3 =>
|
|
||||||
array (
|
array (
|
||||||
'kind' => 'ENUM',
|
'kind' => 'ENUM',
|
||||||
'name' => '__TypeKind',
|
'name' => '__TypeKind',
|
||||||
@ -448,17 +462,6 @@ class IntrospectionTest extends \PHPUnit_Framework_TestCase
|
|||||||
),
|
),
|
||||||
'possibleTypes' => NULL,
|
'possibleTypes' => NULL,
|
||||||
),
|
),
|
||||||
4 =>
|
|
||||||
array (
|
|
||||||
'kind' => 'SCALAR',
|
|
||||||
'name' => 'String',
|
|
||||||
'fields' => NULL,
|
|
||||||
'inputFields' => NULL,
|
|
||||||
'interfaces' => NULL,
|
|
||||||
'enumValues' => NULL,
|
|
||||||
'possibleTypes' => NULL,
|
|
||||||
),
|
|
||||||
5 =>
|
|
||||||
array (
|
array (
|
||||||
'kind' => 'SCALAR',
|
'kind' => 'SCALAR',
|
||||||
'name' => 'Boolean',
|
'name' => 'Boolean',
|
||||||
@ -468,7 +471,6 @@ class IntrospectionTest extends \PHPUnit_Framework_TestCase
|
|||||||
'enumValues' => NULL,
|
'enumValues' => NULL,
|
||||||
'possibleTypes' => NULL,
|
'possibleTypes' => NULL,
|
||||||
),
|
),
|
||||||
6 =>
|
|
||||||
array (
|
array (
|
||||||
'kind' => 'OBJECT',
|
'kind' => 'OBJECT',
|
||||||
'name' => '__Field',
|
'name' => '__Field',
|
||||||
@ -596,7 +598,6 @@ class IntrospectionTest extends \PHPUnit_Framework_TestCase
|
|||||||
'enumValues' => NULL,
|
'enumValues' => NULL,
|
||||||
'possibleTypes' => NULL,
|
'possibleTypes' => NULL,
|
||||||
),
|
),
|
||||||
7 =>
|
|
||||||
array (
|
array (
|
||||||
'kind' => 'OBJECT',
|
'kind' => 'OBJECT',
|
||||||
'name' => '__InputValue',
|
'name' => '__InputValue',
|
||||||
@ -676,7 +677,6 @@ class IntrospectionTest extends \PHPUnit_Framework_TestCase
|
|||||||
'enumValues' => NULL,
|
'enumValues' => NULL,
|
||||||
'possibleTypes' => NULL,
|
'possibleTypes' => NULL,
|
||||||
),
|
),
|
||||||
8 =>
|
|
||||||
array (
|
array (
|
||||||
'kind' => 'OBJECT',
|
'kind' => 'OBJECT',
|
||||||
'name' => '__EnumValue',
|
'name' => '__EnumValue',
|
||||||
@ -756,7 +756,6 @@ class IntrospectionTest extends \PHPUnit_Framework_TestCase
|
|||||||
'enumValues' => NULL,
|
'enumValues' => NULL,
|
||||||
'possibleTypes' => NULL,
|
'possibleTypes' => NULL,
|
||||||
),
|
),
|
||||||
9 =>
|
|
||||||
array (
|
array (
|
||||||
'kind' => 'OBJECT',
|
'kind' => 'OBJECT',
|
||||||
'name' => '__Directive',
|
'name' => '__Directive',
|
||||||
@ -919,7 +918,6 @@ class IntrospectionTest extends \PHPUnit_Framework_TestCase
|
|||||||
'enumValues' => NULL,
|
'enumValues' => NULL,
|
||||||
'possibleTypes' => NULL,
|
'possibleTypes' => NULL,
|
||||||
),
|
),
|
||||||
10 =>
|
|
||||||
array (
|
array (
|
||||||
'kind' => 'ENUM',
|
'kind' => 'ENUM',
|
||||||
'name' => '__DirectiveLocation',
|
'name' => '__DirectiveLocation',
|
||||||
@ -973,7 +971,7 @@ class IntrospectionTest extends \PHPUnit_Framework_TestCase
|
|||||||
),
|
),
|
||||||
'possibleTypes' => NULL,
|
'possibleTypes' => NULL,
|
||||||
),
|
),
|
||||||
11 => array (
|
array (
|
||||||
'kind' => 'SCALAR',
|
'kind' => 'SCALAR',
|
||||||
'name' => 'ID',
|
'name' => 'ID',
|
||||||
'fields' => NULL,
|
'fields' => NULL,
|
||||||
@ -982,7 +980,7 @@ class IntrospectionTest extends \PHPUnit_Framework_TestCase
|
|||||||
'enumValues' => NULL,
|
'enumValues' => NULL,
|
||||||
'possibleTypes' => NULL,
|
'possibleTypes' => NULL,
|
||||||
),
|
),
|
||||||
12 => array (
|
array (
|
||||||
'kind' => 'SCALAR',
|
'kind' => 'SCALAR',
|
||||||
'name' => 'Float',
|
'name' => 'Float',
|
||||||
'fields' => NULL,
|
'fields' => NULL,
|
||||||
@ -991,7 +989,7 @@ class IntrospectionTest extends \PHPUnit_Framework_TestCase
|
|||||||
'enumValues' => NULL,
|
'enumValues' => NULL,
|
||||||
'possibleTypes' => NULL,
|
'possibleTypes' => NULL,
|
||||||
),
|
),
|
||||||
13 => array (
|
array (
|
||||||
'kind' => 'SCALAR',
|
'kind' => 'SCALAR',
|
||||||
'name' => 'Int',
|
'name' => 'Int',
|
||||||
'fields' => NULL,
|
'fields' => NULL,
|
||||||
@ -1491,7 +1489,7 @@ class IntrospectionTest extends \PHPUnit_Framework_TestCase
|
|||||||
{
|
{
|
||||||
$QueryRoot = new ObjectType([
|
$QueryRoot = new ObjectType([
|
||||||
'name' => 'QueryRoot',
|
'name' => 'QueryRoot',
|
||||||
'fields' => []
|
'fields' => ['a' => Type::string()]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema(['query' => $QueryRoot]);
|
$schema = new Schema(['query' => $QueryRoot]);
|
||||||
@ -1551,7 +1549,7 @@ class IntrospectionTest extends \PHPUnit_Framework_TestCase
|
|||||||
{
|
{
|
||||||
$QueryRoot = new ObjectType([
|
$QueryRoot = new ObjectType([
|
||||||
'name' => 'QueryRoot',
|
'name' => 'QueryRoot',
|
||||||
'fields' => []
|
'fields' => ['a' => Type::string()]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$schema = new Schema(['query' => $QueryRoot]);
|
$schema = new Schema(['query' => $QueryRoot]);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -318,7 +318,7 @@ class ExtractTypesTest extends \PHPUnit_Framework_TestCase
|
|||||||
{
|
{
|
||||||
$otherUserType = new ObjectType([
|
$otherUserType = new ObjectType([
|
||||||
'name' => 'User',
|
'name' => 'User',
|
||||||
'fields' => []
|
'fields' => ['a' => Type::string()]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$queryType = new ObjectType([
|
$queryType = new ObjectType([
|
||||||
|
Loading…
Reference in New Issue
Block a user