Reverted DefinitionContainer (YAGNI)

This commit is contained in:
vladar 2016-11-25 16:54:57 +07:00
parent 7c0aa4ceec
commit 0969073b8a
24 changed files with 49 additions and 185 deletions

View File

@ -26,7 +26,7 @@ $myType = new ObjectType([
]);
```
Class per type, using inheritance:
Class per type:
```php
<?php
namespace MyApp;
@ -50,31 +50,6 @@ class MyType extends ObjectType
}
```
Class per type, using composition:
```php
<?php
namespace MyApp;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\DefinitionContainer;
class MyType implements DefinitionContainer
{
private $definition;
public function getDefinition()
{
return $this->definition ?: ($this->definition = new ObjectType([
'name' => 'MyType',
'fields' => [
'id' => Type::id()
]
]));
}
}
```
You can also mix-and-match styles for convenience. For example:
```php
<?php

View File

@ -35,7 +35,7 @@ or hardcoded in source code) to **serialized** representation included in respon
Those cases are covered by methods `serialize`, `parseValue` and `parseLiteral` of abstract `ScalarType`
class respectively.
Here is an example of simple `Email` type (using inheritance):
Here is an example of simple `Email` type:
```php
<?php
@ -109,30 +109,6 @@ class EmailType extends ScalarType
}
```
Same example, using composition over inheritance:
```php
<?php
namespace MyApp;
use GraphQL\Type\DefinitionContainer;
use GraphQL\Type\Definition\CustomScalarType;
class EmailType implements DefinitionContainer
{
private $definition;
public function getDefinition()
{
return $this->definition ?: ($this->definition = new CustomScalarType([
'name' => 'Email',
'serialize' => function($value) {/* See function body above */},
'parseValue' => function($value) {/* See function body above */},
'parseLiteral' => function($valueNode) {/* See function body above */},
]));
}
}
```
Or with inline style:
```php

View File

@ -1,24 +0,0 @@
<?php
namespace GraphQL\Examples\Blog\Type;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\DefinitionContainer;
abstract class BaseType implements DefinitionContainer
{
// Base class to reduce boilerplate for those who prefer own clean hierarchy of classes
// (and avoids extending GraphQL classes directly)
/**
* @var Type
*/
protected $definition;
/**
* @return Type
*/
public function getDefinition()
{
return $this->definition;
}
}

View File

@ -8,12 +8,11 @@ use GraphQL\Examples\Blog\Types;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\ResolveInfo;
class CommentType extends BaseType
class CommentType extends ObjectType
{
public function __construct()
{
// Option #1: using composition over inheritance to define type, see ImageType for inheritance example
$this->definition = new ObjectType([
$config = [
'name' => 'Comment',
'fields' => function() {
return [
@ -43,7 +42,8 @@ class CommentType extends BaseType
return $value->{$info->fieldName};
}
}
]);
];
parent::__construct($config);
}
public function author(Comment $comment)

View File

@ -1,20 +1,19 @@
<?php
namespace GraphQL\Examples\Blog\Type\Enum;
use GraphQL\Examples\Blog\Type\BaseType;
use GraphQL\Type\Definition\EnumType;
class ContentFormatEnum extends BaseType
class ContentFormatEnum extends EnumType
{
const FORMAT_TEXT = 'TEXT';
const FORMAT_HTML = 'HTML';
public function __construct()
{
// Option #1: Define type using composition over inheritance, see ImageSizeEnumType for inheritance option
$this->definition = new EnumType([
$config = [
'name' => 'ContentFormatEnum',
'values' => [self::FORMAT_TEXT, self::FORMAT_HTML]
]);
];
parent::__construct($config);
}
}

View File

@ -8,7 +8,6 @@ class ImageSizeEnumType extends EnumType
{
public function __construct()
{
// Option #2: Define enum type using inheritance
$config = [
// Note: 'name' option is not needed in this form - it will be inferred from className
'values' => [

View File

@ -11,7 +11,6 @@ class ImageType extends ObjectType
{
public function __construct()
{
// Option #2: define type using inheritance, see any other object type for compositional example
$config = [
'name' => 'ImageType',
'fields' => [

View File

@ -7,21 +7,21 @@ use GraphQL\Examples\Blog\Data\Image;
use GraphQL\Examples\Blog\Types;
use GraphQL\Type\Definition\InterfaceType;
class NodeType extends BaseType
class NodeType extends InterfaceType
{
public function __construct()
{
// Option #1: using composition over inheritance to define type, see ImageType for inheritance example
$this->definition = new InterfaceType([
$config = [
'name' => 'Node',
'fields' => [
'id' => Types::id()
],
'resolveType' => [$this, 'resolveType']
]);
'resolveType' => [$this, 'resolveNodeType']
];
parent::__construct($config);
}
public function resolveType($object, Types $types)
public function resolveNodeType($object)
{
if ($object instanceof User) {
return Types::user();

View File

@ -8,12 +8,11 @@ use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\ResolveInfo;
use GraphQL\Type\Definition\Type;
class QueryType extends BaseType
class QueryType extends ObjectType
{
public function __construct()
{
// Option #1: using composition over inheritance to define type, see ImageType for inheritance example
$this->definition = new ObjectType([
$config = [
'name' => 'Query',
'fields' => [
'user' => [
@ -61,7 +60,8 @@ class QueryType extends BaseType
'resolveField' => function($val, $args, $context, ResolveInfo $info) {
return $this->{$info->fieldName}($val, $args, $context, $info);
}
]);
];
parent::__construct($config);
}
public function user($rootValue, $args)

View File

@ -2,21 +2,19 @@
namespace GraphQL\Examples\Blog\Type\Scalar;
use GraphQL\Error\Error;
use GraphQL\Examples\Blog\Type\BaseType;
use GraphQL\Language\AST\StringValueNode;
use GraphQL\Type\Definition\CustomScalarType;
use GraphQL\Utils;
class EmailType extends BaseType
class EmailType
{
public function __construct()
public static function create()
{
// Option #1: define scalar types using composition (see UrlType fo option #2 using inheritance)
$this->definition = new CustomScalarType([
return new CustomScalarType([
'name' => 'Email',
'serialize' => [$this, 'serialize'],
'parseValue' => [$this, 'parseValue'],
'parseLiteral' => [$this, 'parseLiteral'],
'serialize' => [__CLASS__, 'serialize'],
'parseValue' => [__CLASS__, 'parseValue'],
'parseLiteral' => [__CLASS__, 'parseLiteral'],
]);
}
@ -26,7 +24,7 @@ class EmailType extends BaseType
* @param string $value
* @return string
*/
public function serialize($value)
public static function serialize($value)
{
// Assuming internal representation of email is always correct:
return $value;
@ -42,7 +40,7 @@ class EmailType extends BaseType
* @param mixed $value
* @return mixed
*/
public function parseValue($value)
public static function parseValue($value)
{
if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
throw new \UnexpectedValueException("Cannot represent value as email: " . Utils::printSafe($value));
@ -57,7 +55,7 @@ class EmailType extends BaseType
* @return string
* @throws Error
*/
public function parseLiteral($valueNode)
public static function parseLiteral($valueNode)
{
// Note: throwing GraphQL\Error\Error vs \UnexpectedValueException to benefit from GraphQL
// error location in query:

View File

@ -9,8 +9,6 @@ use GraphQL\Utils;
class UrlType extends ScalarType
{
// Option #2: Displays scalar type defined using inheritance. See EmailType for definition via composition
/**
* Serializes an internal value to include in a response.
*

View File

@ -6,12 +6,11 @@ use GraphQL\Examples\Blog\Data\User;
use GraphQL\Examples\Blog\Types;
use GraphQL\Type\Definition\UnionType;
class SearchResultType extends BaseType
class SearchResultType extends UnionType
{
public function __construct()
{
// Option #1: using composition over inheritance to define type, see ImageType for inheritance example
$this->definition = new UnionType([
$config = [
'name' => 'SearchResultType',
'types' => function() {
return [
@ -26,6 +25,7 @@ class SearchResultType extends BaseType
return Types::user();
}
}
]);
];
parent::__construct($config);
}
}

View File

@ -13,7 +13,7 @@ use GraphQL\Type\Definition\ResolveInfo;
* Class StoryType
* @package GraphQL\Examples\Social\Type
*/
class StoryType extends BaseType
class StoryType extends ObjectType
{
const EDIT = 'EDIT';
const DELETE = 'DELETE';
@ -23,8 +23,7 @@ class StoryType extends BaseType
public function __construct()
{
// Option #1: using composition over inheritance to define type, see ImageType for inheritance example
$this->definition = new ObjectType([
$config = [
'name' => 'Story',
'fields' => function() {
return [
@ -83,7 +82,8 @@ class StoryType extends BaseType
return $value->{$info->fieldName};
}
}
]);
];
parent::__construct($config);
}
public function author(Story $story)

View File

@ -8,12 +8,11 @@ use GraphQL\Examples\Blog\Types;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\ResolveInfo;
class UserType extends BaseType
class UserType extends ObjectType
{
public function __construct()
{
// Option #1: using composition over inheritance to define type, see ImageType for inheritance example
$this->definition = new ObjectType([
$config = [
'name' => 'User',
'description' => 'Our blog authors',
'fields' => function() {
@ -52,7 +51,8 @@ class UserType extends BaseType
return $value->{$info->fieldName};
}
}
]);
];
parent::__construct($config);
}
public function photo(User $user, $args)

View File

@ -16,7 +16,6 @@ use GraphQL\Examples\Blog\Type\ImageType;
use GraphQL\Type\Definition\ListOfType;
use GraphQL\Type\Definition\NonNull;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\DefinitionContainer;
/**
* Class Types
@ -128,7 +127,7 @@ class Types
public static function email()
{
return self::$emailType ?: (self::$emailType = new EmailType());
return self::$emailType ?: (self::$emailType = EmailType::create());
}
/**
@ -191,7 +190,7 @@ class Types
}
/**
* @param Type|DefinitionContainer $type
* @param Type $type
* @return ListOfType
*/
public static function listOf($type)
@ -200,7 +199,7 @@ class Types
}
/**
* @param Type|DefinitionContainer $type
* @param Type $type
* @return NonNull
*/
public static function nonNull($type)

View File

@ -20,7 +20,6 @@ use GraphQL\Type\Definition\NonNull;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\ResolveInfo;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\DefinitionContainer;
use GraphQL\Type\Introspection;
use GraphQL\Utils;
@ -754,11 +753,6 @@ class Executor
$runtimeType = $exeContext->schema->getType($runtimeType);
}
// FIXME: Executor should never face with DefinitionContainer - it should be unwrapped in Schema
if ($runtimeType instanceof DefinitionContainer) {
$runtimeType = $runtimeType->getDefinition();
}
if (!($runtimeType instanceof ObjectType)) {
throw new Error(
"Abstract type {$returnType} must resolve to an Object type at runtime " .

View File

@ -9,7 +9,6 @@ use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\UnionType;
use GraphQL\Type\Definition\WrappingType;
use GraphQL\Type\DefinitionContainer;
use GraphQL\Type\Introspection;
/**
@ -114,18 +113,6 @@ class Schema
'validate' => true
];
if ($config['query'] instanceof DefinitionContainer) {
$config['query'] = $config['query']->getDefinition();
}
if ($config['mutation'] instanceof DefinitionContainer) {
$config['mutation'] = $config['mutation']->getDefinition();
}
if ($config['subscription'] instanceof DefinitionContainer) {
$config['subscription'] = $config['subscription']->getDefinition();
}
Utils::invariant(
$config['query'] instanceof ObjectType,
"Schema query must be Object Type but got: " . Utils::getVariableType($config['query'])
@ -301,9 +288,6 @@ class Schema
if (!$type) {
return $this->typeMap;
}
if ($type instanceof DefinitionContainer) {
$type = $type->getDefinition();
}
if ($type instanceof WrappingType) {
return $this->extractTypes($type->getWrappedType(true));

View File

@ -2,7 +2,6 @@
namespace GraphQL\Type\Definition;
use GraphQL\Error\InvariantViolation;
use GraphQL\Type\DefinitionContainer;
use GraphQL\Utils;
/**
@ -190,10 +189,6 @@ class Config
$err = 'Error in "'.$typeName.'" type definition: ' . "Each entry at '$pathStr' must be an array, but '%s' is '%s'";
foreach ($value as $arrKey => $arrValue) {
if ($arrValue instanceof DefinitionContainer) {
$arrValue = $arrValue->getDefinition();
}
if (is_array($def->definition)) {
if ($def->flags & self::MAYBE_TYPE && $arrValue instanceof Type) {
$arrValue = ['type' => $arrValue];
@ -226,10 +221,6 @@ class Config
return ; // Allow nulls for non-required fields
}
if ($value instanceof DefinitionContainer) {
$value = $value->getDefinition();
}
switch (true) {
case $def & self::ANY:
break;

View File

@ -1,7 +1,6 @@
<?php
namespace GraphQL\Type\Definition;
use GraphQL\Type\DefinitionContainer;
use GraphQL\Utils;
/**
@ -16,12 +15,12 @@ class ListOfType extends Type implements WrappingType, OutputType, InputType
public $ofType;
/**
* @param callable|Type|DefinitionContainer $type
* @param callable|Type $type
*/
public function __construct($type)
{
Utils::invariant(
$type instanceof Type || $type instanceof DefinitionContainer || is_callable($type),
$type instanceof Type || is_callable($type),
'Expecting instance of GraphQL\Type\Definition\Type or callable returning instance of that class'
);

View File

@ -1,8 +1,6 @@
<?php
namespace GraphQL\Type\Definition;
use GraphQL\Type\DefinitionContainer;
use GraphQL\Type\TypeKind;
use GraphQL\Utils;
/**
@ -17,13 +15,13 @@ class NonNull extends Type implements WrappingType, OutputType, InputType
private $ofType;
/**
* @param callable|Type|DefinitionContainer $type
* @param callable|Type $type
* @throws \Exception
*/
public function __construct($type)
{
Utils::invariant(
$type instanceof Type || $type instanceof DefinitionContainer || is_callable($type),
$type instanceof Type || is_callable($type),
'Expecting instance of GraphQL\Type\Definition\Type or callable returning instance of that class'
);
Utils::invariant(

View File

@ -1,7 +1,6 @@
<?php
namespace GraphQL\Type\Definition;
use GraphQL\Error\InvariantViolation;
use GraphQL\Type\DefinitionContainer;
use GraphQL\Utils;
@ -155,7 +154,7 @@ class ObjectType extends Type implements OutputType, CompositeType
}
/**
* @param InterfaceType|DefinitionContainer $iface
* @param InterfaceType $iface
* @return bool
*/
public function implementsInterface($iface)

View File

@ -2,7 +2,6 @@
namespace GraphQL\Type\Definition;
use GraphQL\Error\InvariantViolation;
use GraphQL\Type\DefinitionContainer;
use GraphQL\Utils;
/*
@ -198,9 +197,6 @@ abstract class Type implements \JsonSerializable
);
$type = $type();
}
if ($type instanceof DefinitionContainer) {
$type = $type->getDefinition();
}
if (!$type instanceof Type) {
throw new InvariantViolation(sprintf(

View File

@ -1,7 +1,6 @@
<?php
namespace GraphQL\Type\Definition;
use GraphQL\Type\DefinitionContainer;
use GraphQL\Utils;
/**

View File

@ -1,15 +0,0 @@
<?php
namespace GraphQL\Type;
use GraphQL\Type\Definition\Type;
/**
* Interface DefinitionContainer
* @package GraphQL\Type
*/
interface DefinitionContainer
{
/**
* @return Type
*/
public function getDefinition();
}