mirror of
https://github.com/retailcrm/graphql-php.git
synced 2024-11-21 20:36:05 +03:00
Ability to override internal types (closes #401)
This commit is contained in:
parent
bdbb30c604
commit
e1b4d438db
@ -1,9 +1,13 @@
|
||||
# Changelog
|
||||
## dev-master
|
||||
- Spec compliance: error extensions are displayed under `extensions` key
|
||||
This release brings several breaking changes. Please refer to [UPGRADE](UPGRADE.md) document for details.
|
||||
|
||||
New features and notable changes:
|
||||
- Spec compliance: error category, debug information and extensions are displayed under `extensions` key
|
||||
- `AbstractValidationRule` renamed to `ValidationRule` (NS `GraphQL\Validator\Rules`)
|
||||
- `AbstractQuerySecurity` renamed to `QuerySecurityRule` (NS `GraphQL\Validator\Rules`)
|
||||
- `FindBreakingChanges` renamed to `BreakingChangesFinder` (NS `GraphQL\Utils`)
|
||||
- Added ability to override standard types via `GraphQL::overrideStandardTypes(array $types)`
|
||||
|
||||
#### v0.12.5
|
||||
- Execution performance optimization for lists
|
||||
|
@ -276,7 +276,20 @@ class GraphQL
|
||||
*/
|
||||
public static function getStandardTypes() : array
|
||||
{
|
||||
return array_values(Type::getInternalTypes());
|
||||
return array_values(Type::getStandardTypes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces standard types with types from this list (matching by name)
|
||||
* Standard types not listed here remain untouched.
|
||||
*
|
||||
* @param Type[] $types
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public static function overrideStandardTypes(array $types)
|
||||
{
|
||||
Type::overrideStandardTypes($types);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -291,6 +304,11 @@ class GraphQL
|
||||
return array_values(DocumentValidator::defaultRules());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default resolver implementation
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public static function setDefaultFieldResolver(callable $fn) : void
|
||||
{
|
||||
Executor::setDefaultFieldResolver($fn);
|
||||
|
@ -15,8 +15,11 @@ use ReflectionClass;
|
||||
use Throwable;
|
||||
use function array_keys;
|
||||
use function array_merge;
|
||||
use function implode;
|
||||
use function in_array;
|
||||
use function preg_replace;
|
||||
use function trigger_error;
|
||||
use const E_USER_DEPRECATED;
|
||||
|
||||
/**
|
||||
* Registry of standard GraphQL types
|
||||
@ -31,7 +34,7 @@ abstract class Type implements JsonSerializable
|
||||
public const ID = 'ID';
|
||||
|
||||
/** @var Type[] */
|
||||
private static $internalTypes;
|
||||
private static $standardTypes;
|
||||
|
||||
/** @var Type[] */
|
||||
private static $builtInTypes;
|
||||
@ -58,7 +61,7 @@ abstract class Type implements JsonSerializable
|
||||
*/
|
||||
public static function id()
|
||||
{
|
||||
return self::getInternalType(self::ID);
|
||||
return self::getStandardType(self::ID);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,10 +69,10 @@ abstract class Type implements JsonSerializable
|
||||
*
|
||||
* @return (IDType|StringType|FloatType|IntType|BooleanType)[]|IDType|StringType|FloatType|IntType|BooleanType
|
||||
*/
|
||||
private static function getInternalType($name = null)
|
||||
private static function getStandardType($name = null)
|
||||
{
|
||||
if (self::$internalTypes === null) {
|
||||
self::$internalTypes = [
|
||||
if (self::$standardTypes === null) {
|
||||
self::$standardTypes = [
|
||||
self::ID => new IDType(),
|
||||
self::STRING => new StringType(),
|
||||
self::FLOAT => new FloatType(),
|
||||
@ -78,7 +81,7 @@ abstract class Type implements JsonSerializable
|
||||
];
|
||||
}
|
||||
|
||||
return $name ? self::$internalTypes[$name] : self::$internalTypes;
|
||||
return $name ? self::$standardTypes[$name] : self::$standardTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -88,7 +91,7 @@ abstract class Type implements JsonSerializable
|
||||
*/
|
||||
public static function string()
|
||||
{
|
||||
return self::getInternalType(self::STRING);
|
||||
return self::getStandardType(self::STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -98,7 +101,7 @@ abstract class Type implements JsonSerializable
|
||||
*/
|
||||
public static function boolean()
|
||||
{
|
||||
return self::getInternalType(self::BOOLEAN);
|
||||
return self::getStandardType(self::BOOLEAN);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -108,7 +111,7 @@ abstract class Type implements JsonSerializable
|
||||
*/
|
||||
public static function int()
|
||||
{
|
||||
return self::getInternalType(self::INT);
|
||||
return self::getStandardType(self::INT);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -118,7 +121,7 @@ abstract class Type implements JsonSerializable
|
||||
*/
|
||||
public static function float()
|
||||
{
|
||||
return self::getInternalType(self::FLOAT);
|
||||
return self::getStandardType(self::FLOAT);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -166,7 +169,7 @@ abstract class Type implements JsonSerializable
|
||||
if (self::$builtInTypes === null) {
|
||||
self::$builtInTypes = array_merge(
|
||||
Introspection::getTypes(),
|
||||
self::getInternalTypes()
|
||||
self::getStandardTypes()
|
||||
);
|
||||
}
|
||||
|
||||
@ -178,9 +181,44 @@ abstract class Type implements JsonSerializable
|
||||
*
|
||||
* @return Type[]
|
||||
*/
|
||||
public static function getStandardTypes()
|
||||
{
|
||||
return self::getStandardType();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use method getStandardTypes() instead
|
||||
*
|
||||
* @return Type[]
|
||||
*/
|
||||
public static function getInternalTypes()
|
||||
{
|
||||
return self::getInternalType();
|
||||
trigger_error(__METHOD__ . ' is deprecated. Use Type::getStandardTypes() instead', E_USER_DEPRECATED);
|
||||
return self::getStandardTypes();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Type[] $types
|
||||
*/
|
||||
public static function overrideStandardTypes(array $types)
|
||||
{
|
||||
$standardTypes = self::getStandardTypes();
|
||||
foreach ($types as $type) {
|
||||
Utils::invariant(
|
||||
$type instanceof Type,
|
||||
'Expecting instance of %s, got %s',
|
||||
self::class,
|
||||
Utils::printSafe($type)
|
||||
);
|
||||
Utils::invariant(
|
||||
isset($type->name, $standardTypes[$type->name]),
|
||||
'Expecting one of the following names for a standard type: %s, got %s',
|
||||
implode(', ', array_keys($standardTypes)),
|
||||
Utils::printSafe($type->name ?? null)
|
||||
);
|
||||
$standardTypes[$type->name] = $type;
|
||||
}
|
||||
self::$standardTypes = $standardTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -143,7 +143,7 @@ class Schema
|
||||
$this->resolvedTypes[$type->name] = $type;
|
||||
}
|
||||
}
|
||||
$this->resolvedTypes += Type::getInternalTypes() + Introspection::getTypes();
|
||||
$this->resolvedTypes += Type::getStandardTypes() + Introspection::getTypes();
|
||||
|
||||
if ($this->config->typeLoader) {
|
||||
return;
|
||||
@ -472,7 +472,7 @@ class Schema
|
||||
throw new InvariantViolation(implode("\n\n", $this->validationErrors));
|
||||
}
|
||||
|
||||
$internalTypes = Type::getInternalTypes() + Introspection::getTypes();
|
||||
$internalTypes = Type::getStandardTypes() + Introspection::getTypes();
|
||||
foreach ($this->getTypeMap() as $name => $type) {
|
||||
if (isset($internalTypes[$name])) {
|
||||
continue;
|
||||
|
132
tests/Type/StandardTypesTest.php
Normal file
132
tests/Type/StandardTypesTest.php
Normal file
@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GraphQL\Tests\Type;
|
||||
|
||||
use GraphQL\Error\InvariantViolation;
|
||||
use GraphQL\Type\Definition\CustomScalarType;
|
||||
use GraphQL\Type\Definition\Type;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use stdClass;
|
||||
|
||||
class StandardTypesTest extends TestCase
|
||||
{
|
||||
/** @var Type[] */
|
||||
private static $originalStandardTypes;
|
||||
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
self::$originalStandardTypes = Type::getStandardTypes();
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
parent::tearDown();
|
||||
Type::overrideStandardTypes(self::$originalStandardTypes);
|
||||
}
|
||||
|
||||
public function testAllowsOverridingStandardTypes()
|
||||
{
|
||||
$originalTypes = Type::getStandardTypes();
|
||||
self::assertCount(5, $originalTypes);
|
||||
self::assertSame(self::$originalStandardTypes, $originalTypes);
|
||||
|
||||
$newBooleanType = $this->createCustomScalarType(Type::BOOLEAN);
|
||||
$newFloatType = $this->createCustomScalarType(Type::FLOAT);
|
||||
$newIDType = $this->createCustomScalarType(Type::ID);
|
||||
$newIntType = $this->createCustomScalarType(Type::INT);
|
||||
$newStringType = $this->createCustomScalarType(Type::STRING);
|
||||
|
||||
Type::overrideStandardTypes([
|
||||
$newStringType,
|
||||
$newBooleanType,
|
||||
$newIDType,
|
||||
$newIntType,
|
||||
$newFloatType,
|
||||
]);
|
||||
|
||||
$types = Type::getStandardTypes();
|
||||
self::assertCount(5, $types);
|
||||
|
||||
self::assertSame($newBooleanType, $types[Type::BOOLEAN]);
|
||||
self::assertSame($newFloatType, $types[Type::FLOAT]);
|
||||
self::assertSame($newIDType, $types[Type::ID]);
|
||||
self::assertSame($newIntType, $types[Type::INT]);
|
||||
self::assertSame($newStringType, $types[Type::STRING]);
|
||||
|
||||
self::assertSame($newBooleanType, Type::boolean());
|
||||
self::assertSame($newFloatType, Type::float());
|
||||
self::assertSame($newIDType, Type::id());
|
||||
self::assertSame($newIntType, Type::int());
|
||||
self::assertSame($newStringType, Type::string());
|
||||
}
|
||||
|
||||
public function testPreservesOriginalStandardTypes()
|
||||
{
|
||||
$originalTypes = Type::getStandardTypes();
|
||||
self::assertCount(5, $originalTypes);
|
||||
self::assertSame(self::$originalStandardTypes, $originalTypes);
|
||||
|
||||
$newIDType = $this->createCustomScalarType(Type::ID);
|
||||
$newStringType = $this->createCustomScalarType(Type::STRING);
|
||||
|
||||
Type::overrideStandardTypes([
|
||||
$newStringType,
|
||||
$newIDType,
|
||||
]);
|
||||
|
||||
$types = Type::getStandardTypes();
|
||||
self::assertCount(5, $types);
|
||||
|
||||
self::assertSame($originalTypes[Type::BOOLEAN], $types[Type::BOOLEAN]);
|
||||
self::assertSame($originalTypes[Type::FLOAT], $types[Type::FLOAT]);
|
||||
self::assertSame($originalTypes[Type::INT], $types[Type::INT]);
|
||||
|
||||
self::assertSame($originalTypes[Type::BOOLEAN], Type::boolean());
|
||||
self::assertSame($originalTypes[Type::FLOAT], Type::float());
|
||||
self::assertSame($originalTypes[Type::INT], Type::int());
|
||||
|
||||
self::assertSame($newIDType, $types[Type::ID]);
|
||||
self::assertSame($newStringType, $types[Type::STRING]);
|
||||
|
||||
self::assertSame($newIDType, Type::id());
|
||||
self::assertSame($newStringType, Type::string());
|
||||
}
|
||||
|
||||
public function getInvalidStandardTypes()
|
||||
{
|
||||
return [
|
||||
[null, 'Expecting instance of GraphQL\Type\Definition\Type, got null'],
|
||||
[5, 'Expecting instance of GraphQL\Type\Definition\Type, got 5'],
|
||||
['', 'Expecting instance of GraphQL\Type\Definition\Type, got (empty string)'],
|
||||
[new stdClass(), 'Expecting instance of GraphQL\Type\Definition\Type, got instance of stdClass'],
|
||||
[[], 'Expecting instance of GraphQL\Type\Definition\Type, got []'],
|
||||
[$this->createCustomScalarType('NonStandardName'), 'Expecting one of the following names for a standard type: ID, String, Float, Int, Boolean, got NonStandardName'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getInvalidStandardTypes
|
||||
*/
|
||||
public function testStandardTypesOverrideDoesSanityChecks($type, string $expectedMessage)
|
||||
{
|
||||
$this->expectException(InvariantViolation::class);
|
||||
$this->expectExceptionMessage($expectedMessage);
|
||||
|
||||
Type::overrideStandardTypes([ $type ]);
|
||||
}
|
||||
|
||||
private function createCustomScalarType($name)
|
||||
{
|
||||
return new CustomScalarType([
|
||||
'name' => $name,
|
||||
'serialize' => static function () {
|
||||
},
|
||||
'parseValue' => static function () {
|
||||
},
|
||||
'parseLiteral' => static function () {
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user