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
<?php <?php
namespace MyApp; 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: You can also mix-and-match styles for convenience. For example:
```php ```php
<?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` Those cases are covered by methods `serialize`, `parseValue` and `parseLiteral` of abstract `ScalarType`
class respectively. class respectively.
Here is an example of simple `Email` type (using inheritance): Here is an example of simple `Email` type:
```php ```php
<?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: Or with inline style:
```php ```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\ObjectType;
use GraphQL\Type\Definition\ResolveInfo; use GraphQL\Type\Definition\ResolveInfo;
class CommentType extends BaseType class CommentType extends ObjectType
{ {
public function __construct() public function __construct()
{ {
// Option #1: using composition over inheritance to define type, see ImageType for inheritance example $config = [
$this->definition = new ObjectType([
'name' => 'Comment', 'name' => 'Comment',
'fields' => function() { 'fields' => function() {
return [ return [
@ -43,7 +42,8 @@ class CommentType extends BaseType
return $value->{$info->fieldName}; return $value->{$info->fieldName};
} }
} }
]); ];
parent::__construct($config);
} }
public function author(Comment $comment) public function author(Comment $comment)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -9,8 +9,6 @@ use GraphQL\Utils;
class UrlType extends ScalarType 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. * 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\Examples\Blog\Types;
use GraphQL\Type\Definition\UnionType; use GraphQL\Type\Definition\UnionType;
class SearchResultType extends BaseType class SearchResultType extends UnionType
{ {
public function __construct() public function __construct()
{ {
// Option #1: using composition over inheritance to define type, see ImageType for inheritance example $config = [
$this->definition = new UnionType([
'name' => 'SearchResultType', 'name' => 'SearchResultType',
'types' => function() { 'types' => function() {
return [ return [
@ -26,6 +25,7 @@ class SearchResultType extends BaseType
return Types::user(); return Types::user();
} }
} }
]); ];
parent::__construct($config);
} }
} }

View File

@ -13,7 +13,7 @@ use GraphQL\Type\Definition\ResolveInfo;
* Class StoryType * Class StoryType
* @package GraphQL\Examples\Social\Type * @package GraphQL\Examples\Social\Type
*/ */
class StoryType extends BaseType class StoryType extends ObjectType
{ {
const EDIT = 'EDIT'; const EDIT = 'EDIT';
const DELETE = 'DELETE'; const DELETE = 'DELETE';
@ -23,8 +23,7 @@ class StoryType extends BaseType
public function __construct() public function __construct()
{ {
// Option #1: using composition over inheritance to define type, see ImageType for inheritance example $config = [
$this->definition = new ObjectType([
'name' => 'Story', 'name' => 'Story',
'fields' => function() { 'fields' => function() {
return [ return [
@ -83,7 +82,8 @@ class StoryType extends BaseType
return $value->{$info->fieldName}; return $value->{$info->fieldName};
} }
} }
]); ];
parent::__construct($config);
} }
public function author(Story $story) 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\ObjectType;
use GraphQL\Type\Definition\ResolveInfo; use GraphQL\Type\Definition\ResolveInfo;
class UserType extends BaseType class UserType extends ObjectType
{ {
public function __construct() public function __construct()
{ {
// Option #1: using composition over inheritance to define type, see ImageType for inheritance example $config = [
$this->definition = new ObjectType([
'name' => 'User', 'name' => 'User',
'description' => 'Our blog authors', 'description' => 'Our blog authors',
'fields' => function() { 'fields' => function() {
@ -52,7 +51,8 @@ class UserType extends BaseType
return $value->{$info->fieldName}; return $value->{$info->fieldName};
} }
} }
]); ];
parent::__construct($config);
} }
public function photo(User $user, $args) 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\ListOfType;
use GraphQL\Type\Definition\NonNull; use GraphQL\Type\Definition\NonNull;
use GraphQL\Type\Definition\Type; use GraphQL\Type\Definition\Type;
use GraphQL\Type\DefinitionContainer;
/** /**
* Class Types * Class Types
@ -128,7 +127,7 @@ class Types
public static function email() 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 * @return ListOfType
*/ */
public static function listOf($type) public static function listOf($type)
@ -200,7 +199,7 @@ class Types
} }
/** /**
* @param Type|DefinitionContainer $type * @param Type $type
* @return NonNull * @return NonNull
*/ */
public static function nonNull($type) 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\ObjectType;
use GraphQL\Type\Definition\ResolveInfo; use GraphQL\Type\Definition\ResolveInfo;
use GraphQL\Type\Definition\Type; use GraphQL\Type\Definition\Type;
use GraphQL\Type\DefinitionContainer;
use GraphQL\Type\Introspection; use GraphQL\Type\Introspection;
use GraphQL\Utils; use GraphQL\Utils;
@ -754,11 +753,6 @@ class Executor
$runtimeType = $exeContext->schema->getType($runtimeType); $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)) { if (!($runtimeType instanceof ObjectType)) {
throw new Error( throw new Error(
"Abstract type {$returnType} must resolve to an Object type at runtime " . "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\Type;
use GraphQL\Type\Definition\UnionType; use GraphQL\Type\Definition\UnionType;
use GraphQL\Type\Definition\WrappingType; use GraphQL\Type\Definition\WrappingType;
use GraphQL\Type\DefinitionContainer;
use GraphQL\Type\Introspection; use GraphQL\Type\Introspection;
/** /**
@ -114,18 +113,6 @@ class Schema
'validate' => true '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( Utils::invariant(
$config['query'] instanceof ObjectType, $config['query'] instanceof ObjectType,
"Schema query must be Object Type but got: " . Utils::getVariableType($config['query']) "Schema query must be Object Type but got: " . Utils::getVariableType($config['query'])
@ -301,9 +288,6 @@ class Schema
if (!$type) { if (!$type) {
return $this->typeMap; return $this->typeMap;
} }
if ($type instanceof DefinitionContainer) {
$type = $type->getDefinition();
}
if ($type instanceof WrappingType) { if ($type instanceof WrappingType) {
return $this->extractTypes($type->getWrappedType(true)); return $this->extractTypes($type->getWrappedType(true));

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,6 @@
<?php <?php
namespace GraphQL\Type\Definition; namespace GraphQL\Type\Definition;
use GraphQL\Type\DefinitionContainer;
use GraphQL\Utils; 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();
}