Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ dist: trusty
sudo: false

git:
depth: 1
depth: 50

branches:
only:
Expand Down
21 changes: 9 additions & 12 deletions Definition/Builder/SchemaBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
namespace Overblog\GraphQLBundle\Definition\Builder;

use GraphQL\Type\Definition\Type;
use GraphQL\Type\Schema;
use Overblog\GraphQLBundle\Definition\Type\SchemaDecorator;
use Overblog\GraphQLBundle\Definition\Type\ExtensibleSchema;
use Overblog\GraphQLBundle\Definition\Type\SchemaExtension\DecoratorExtension;
use Overblog\GraphQLBundle\Definition\Type\SchemaExtension\ValidatorExtension;
use Overblog\GraphQLBundle\Resolver\ResolverMapInterface;
use Overblog\GraphQLBundle\Resolver\ResolverMaps;
use Overblog\GraphQLBundle\Resolver\TypeResolver;
Expand All @@ -14,16 +15,12 @@ class SchemaBuilder
/** @var TypeResolver */
private $typeResolver;

/** @var SchemaDecorator */
private $decorator;

/** @var bool */
private $enableValidation;

public function __construct(TypeResolver $typeResolver, SchemaDecorator $decorator, $enableValidation = false)
public function __construct(TypeResolver $typeResolver, $enableValidation = false)
{
$this->typeResolver = $typeResolver;
$this->decorator = $decorator;
$this->enableValidation = $enableValidation;
}

Expand All @@ -34,21 +31,21 @@ public function __construct(TypeResolver $typeResolver, SchemaDecorator $decorat
* @param ResolverMapInterface[] $resolverMaps
* @param string[] $types
*
* @return Schema
* @return ExtensibleSchema
*/
public function create($queryAlias = null, $mutationAlias = null, $subscriptionAlias = null, array $resolverMaps = [], array $types = [])
{
$query = $this->typeResolver->resolve($queryAlias);
$mutation = $this->typeResolver->resolve($mutationAlias);
$subscription = $this->typeResolver->resolve($subscriptionAlias);

$schema = new Schema($this->buildSchemaArguments($query, $mutation, $subscription, $types));
reset($resolverMaps);
$this->decorator->decorate($schema, 1 === count($resolverMaps) ? current($resolverMaps) : new ResolverMaps($resolverMaps));
$schema = new ExtensibleSchema($this->buildSchemaArguments($query, $mutation, $subscription, $types));
$extensions = [new DecoratorExtension(1 === count($resolverMaps) ? current($resolverMaps) : new ResolverMaps($resolverMaps))];

if ($this->enableValidation) {
$schema->assertValid();
$extensions[] = new ValidatorExtension();
}
$schema->setExtensions($extensions);

return $schema;
}
Expand Down
47 changes: 47 additions & 0 deletions Definition/Type/ExtensibleSchema.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace Overblog\GraphQLBundle\Definition\Type;

use GraphQL\Type\Schema;
use Overblog\GraphQLBundle\Definition\Type\SchemaExtension\SchemaExtensionInterface;

class ExtensibleSchema extends Schema
{
/** @var SchemaExtensionInterface[] */
private $extensions = [];

/**
* @param SchemaExtensionInterface[] $extensions
*
* @return $this
*/
public function setExtensions(array $extensions)
{
$this->extensions = [];
foreach ($extensions as $extension) {
$this->addExtension($extension);
}

return $this;
}

/**
* @param SchemaExtensionInterface $extension
*/
public function addExtension(SchemaExtensionInterface $extension)
{
$this->extensions[] = $extension;
}

/**
* @return $this
*/
public function processExtensions()
{
foreach ($this->extensions as $extension) {
$extension->process($this);
}

return $this;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<?php

namespace Overblog\GraphQLBundle\Definition\Type;
namespace Overblog\GraphQLBundle\Definition\Type\SchemaExtension;

use GraphQL\Type\Definition\CustomScalarType;
use GraphQL\Type\Definition\EnumType;
use GraphQL\Type\Definition\InterfaceType;
use GraphQL\Type\Definition\ObjectType;
Expand All @@ -11,23 +12,30 @@
use Overblog\GraphQLBundle\Resolver\Resolver;
use Overblog\GraphQLBundle\Resolver\ResolverMapInterface;

class SchemaDecorator
final class DecoratorExtension implements SchemaExtensionInterface
{
public function decorate(Schema $schema, ResolverMapInterface $resolverMap)
private $resolverMap;

public function __construct(ResolverMapInterface $resolverMap)
{
$this->resolverMap = $resolverMap;
}

public function process(Schema $schema)
{
foreach ($resolverMap->covered() as $typeName) {
foreach ($this->resolverMap->covered() as $typeName) {
$type = $schema->getType($typeName);

if ($type instanceof ObjectType) {
$this->decorateObjectType($type, $resolverMap);
$this->decorateObjectType($type);
} elseif ($type instanceof InterfaceType || $type instanceof UnionType) {
$this->decorateInterfaceOrUnionType($type, $resolverMap);
$this->decorateInterfaceOrUnionType($type);
} elseif ($type instanceof EnumType) {
$this->decorateEnumType($type, $resolverMap);
$this->decorateEnumType($type);
} elseif ($type instanceof CustomScalarType) {
$this->decorateCustomScalarType($type, $resolverMap);
$this->decorateCustomScalarType($type);
} else {
$covered = $resolverMap->covered($type->name);
$covered = $this->resolverMap->covered($type->name);
if (!empty($covered)) {
throw new \InvalidArgumentException(
sprintf(
Expand All @@ -41,47 +49,46 @@ public function decorate(Schema $schema, ResolverMapInterface $resolverMap)
}
}

private function decorateObjectType(ObjectType $type, ResolverMapInterface $resolverMap)
private function decorateObjectType(ObjectType $type)
{
$fieldsResolved = [];
foreach ($resolverMap->covered($type->name) as $fieldName) {
foreach ($this->resolverMap->covered($type->name) as $fieldName) {
if (ResolverMapInterface::IS_TYPEOF === $fieldName) {
$this->configTypeMapping($type, $resolverMap, ResolverMapInterface::IS_TYPEOF);
$this->configTypeMapping($type, ResolverMapInterface::IS_TYPEOF);
} elseif (ResolverMapInterface::RESOLVE_FIELD === $fieldName) {
$resolveFieldFn = Resolver::wrapArgs($resolverMap->resolve($type->name, ResolverMapInterface::RESOLVE_FIELD));
$resolveFieldFn = Resolver::wrapArgs($this->resolverMap->resolve($type->name, ResolverMapInterface::RESOLVE_FIELD));
$type->config[substr(ResolverMapInterface::RESOLVE_FIELD, 2)] = $resolveFieldFn;
$type->resolveFieldFn = $resolveFieldFn;
} else {
$fieldsResolved[] = $fieldName;
}
}
$this->decorateObjectTypeFields($type, $resolverMap, $fieldsResolved);
$this->decorateObjectTypeFields($type, $fieldsResolved);
}

/**
* @param InterfaceType|UnionType $type
* @param ResolverMapInterface $resolverMap
*/
private function decorateInterfaceOrUnionType($type, ResolverMapInterface $resolverMap)
private function decorateInterfaceOrUnionType($type)
{
$this->configTypeMapping($type, $resolverMap, ResolverMapInterface::RESOLVE_TYPE);
$covered = $resolverMap->covered($type->name);
$this->configTypeMapping($type, ResolverMapInterface::RESOLVE_TYPE);
$covered = $this->resolverMap->covered($type->name);
if (!empty($covered)) {
$unknownFields = array_diff($covered, [ResolverMapInterface::RESOLVE_TYPE]);
if (!empty($unknownFields)) {
throw new \InvalidArgumentException(
sprintf(
'"%s".{"%s"} defined in resolverMap, but only "%s" is allowed.',
'"%s".{"%s"} defined in resolverMap, but only "%s::RESOLVE_TYPE" is allowed.',
$type->name,
implode('", "', $unknownFields),
ResolverMapInterface::RESOLVE_TYPE
ResolverMapInterface::class
)
);
}
}
}

private function decorateCustomScalarType(CustomScalarType $type, ResolverMapInterface $resolverMap)
private function decorateCustomScalarType(CustomScalarType $type)
{
static $allowedFields = [
ResolverMapInterface::SCALAR_TYPE,
Expand All @@ -91,33 +98,34 @@ private function decorateCustomScalarType(CustomScalarType $type, ResolverMapInt
];

foreach ($allowedFields as $fieldName) {
$this->configTypeMapping($type, $resolverMap, $fieldName);
$this->configTypeMapping($type, $fieldName);
}

$unknownFields = array_diff($resolverMap->covered($type->name), $allowedFields);
$unknownFields = array_diff($this->resolverMap->covered($type->name), $allowedFields);
if (!empty($unknownFields)) {
throw new \InvalidArgumentException(
sprintf(
'"%s".{"%s"} defined in resolverMap, but only "%s" is allowed.',
'"%s".{"%s"} defined in resolverMap, but only "%s::{%s}" is allowed.',
$type->name,
implode('", "', $unknownFields),
implode('", "', $allowedFields)
ResolverMapInterface::class,
implode(', ', ['SCALAR_TYPE', 'SERIALIZE', 'PARSE_VALUE', 'PARSE_LITERAL'])
)
);
}
}

private function decorateEnumType(EnumType $type, ResolverMapInterface $resolverMaps)
private function decorateEnumType(EnumType $type)
{
$fieldNames = [];
foreach ($type->config['values'] as $key => &$value) {
$fieldName = isset($value['name']) ? $value['name'] : $key;
if ($resolverMaps->isResolvable($type->name, $fieldName)) {
$value['value'] = $resolverMaps->resolve($type->name, $fieldName);
if ($this->resolverMap->isResolvable($type->name, $fieldName)) {
$value['value'] = $this->resolverMap->resolve($type->name, $fieldName);
}
$fieldNames[] = $fieldName;
}
$unknownFields = array_diff($resolverMaps->covered($type->name), $fieldNames);
$unknownFields = array_diff($this->resolverMap->covered($type->name), $fieldNames);
if (!empty($unknownFields)) {
throw new \InvalidArgumentException(
sprintf(
Expand All @@ -129,11 +137,11 @@ private function decorateEnumType(EnumType $type, ResolverMapInterface $resolver
}
}

private function decorateObjectTypeFields(ObjectType $type, ResolverMapInterface $resolverMap, array $fieldsResolved)
private function decorateObjectTypeFields(ObjectType $type, array $fieldsResolved)
{
$fields = $type->config['fields'];

$decoratedFields = function () use ($fields, $type, $resolverMap, $fieldsResolved) {
$decoratedFields = function () use ($fields, $type, $fieldsResolved) {
if (is_callable($fields)) {
$fields = $fields();
}
Expand All @@ -142,8 +150,8 @@ private function decorateObjectTypeFields(ObjectType $type, ResolverMapInterface
foreach ($fields as $key => &$field) {
$fieldName = isset($field['name']) ? $field['name'] : $key;

if ($resolverMap->isResolvable($type->name, $fieldName)) {
$field['resolve'] = Resolver::wrapArgs($resolverMap->resolve($type->name, $fieldName));
if ($this->resolverMap->isResolvable($type->name, $fieldName)) {
$field['resolve'] = Resolver::wrapArgs($this->resolverMap->resolve($type->name, $fieldName));
}

$fieldNames[] = $fieldName;
Expand All @@ -162,10 +170,10 @@ private function decorateObjectTypeFields(ObjectType $type, ResolverMapInterface
$type->config['fields'] = is_callable($fields) ? $decoratedFields : $decoratedFields();
}

private function configTypeMapping(Type $type, ResolverMapInterface $resolverMap, $fieldName)
private function configTypeMapping(Type $type, $fieldName)
{
if ($resolverMap->isResolvable($type->name, $fieldName)) {
$type->config[substr($fieldName, 2)] = $resolverMap->resolve($type->name, $fieldName);
if ($this->resolverMap->isResolvable($type->name, $fieldName)) {
$type->config[substr($fieldName, 2)] = $this->resolverMap->resolve($type->name, $fieldName);
}
}
}
10 changes: 10 additions & 0 deletions Definition/Type/SchemaExtension/SchemaExtensionInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Overblog\GraphQLBundle\Definition\Type\SchemaExtension;

use GraphQL\Type\Schema;

interface SchemaExtensionInterface
{
public function process(Schema $schema);
}
13 changes: 13 additions & 0 deletions Definition/Type/SchemaExtension/ValidatorExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Overblog\GraphQLBundle\Definition\Type\SchemaExtension;

use GraphQL\Type\Schema;

final class ValidatorExtension implements SchemaExtensionInterface
{
public function process(Schema $schema)
{
$schema->assertValid();
}
}
2 changes: 1 addition & 1 deletion DependencyInjection/OverblogGraphQLExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ private function setErrorHandler(array $config, ContainerBuilder $container)
private function setSchemaBuilderArguments(array $config, ContainerBuilder $container)
{
$container->getDefinition($this->getAlias().'.schema_builder')
->replaceArgument(2, $config['definitions']['config_validation']);
->replaceArgument(1, $config['definitions']['config_validation']);
}

private function setSchemaArguments(array $config, ContainerBuilder $container)
Expand Down
10 changes: 5 additions & 5 deletions Event/ExecutorArgumentsEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

namespace Overblog\GraphQLBundle\Event;

use GraphQL\Type\Schema;
use Overblog\GraphQLBundle\Definition\Type\ExtensibleSchema;
use Symfony\Component\EventDispatcher\Event;

final class ExecutorArgumentsEvent extends Event
{
/** @var Schema */
/** @var ExtensibleSchema */
private $schema;

/** @var string */
Expand All @@ -26,7 +26,7 @@ final class ExecutorArgumentsEvent extends Event
private $operationName;

public static function create(
Schema $schema,
ExtensibleSchema $schema,
$requestString,
\ArrayObject $contextValue,
$rootValue = null,
Expand Down Expand Up @@ -78,13 +78,13 @@ public function setVariableValue(array $variableValue = null)
$this->variableValue = $variableValue;
}

public function setSchema(Schema $schema)
public function setSchema(ExtensibleSchema $schema)
{
$this->schema = $schema;
}

/**
* @return Schema
* @return ExtensibleSchema
*/
public function getSchema()
{
Expand Down
2 changes: 2 additions & 0 deletions Request/Executor.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ public function execute($schemaName, array $request, $rootValue = null)
isset($request[ParserInterface::PARAM_OPERATION_NAME]) ? $request[ParserInterface::PARAM_OPERATION_NAME] : null
);

$executorArgumentsEvent->getSchema()->processExtensions();

$result = $this->executor->execute(
$executorArgumentsEvent->getSchema(),
$executorArgumentsEvent->getRequestString(),
Expand Down
Loading