Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added IsPublic support to InputObject #1108

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
8 changes: 8 additions & 0 deletions src/Config/InputObjectTypeDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Overblog\GraphQLBundle\Config;

use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\VariableNodeDefinition;

use function is_string;

Expand All @@ -31,6 +32,7 @@ public function getDefinition(): ArrayNodeDefinition
->append($this->typeSection(true))
->append($this->descriptionSection())
->append($this->defaultValueSection())
->append($this->publicSection())
->append($this->validationSection(self::VALIDATION_LEVEL_PROPERTY))
->append($this->deprecationReasonSection())
->end()
Expand All @@ -42,4 +44,10 @@ public function getDefinition(): ArrayNodeDefinition

return $node;
}

protected function publicSection(): VariableNodeDefinition
{
return self::createNode('public', 'variable')
->info('Visibility control to field (expression language can be used here)');
}
}
9 changes: 9 additions & 0 deletions src/Config/Parser/MetadataParser/MetadataParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -645,9 +645,14 @@ private static function getGraphQLInputFieldsFromMetadatas(ReflectionClass $refl

/** @var Metadata\Field|null $fieldMetadata */
$fieldMetadata = self::getFirstMetadataMatching($metadatas, Metadata\Field::class);
$publicMetadata = self::getFirstMetadataMatching($metadatas, Metadata\IsPublic::class);

// No field metadata found
if (null === $fieldMetadata) {
if (null !== $publicMetadata) {
throw new InvalidArgumentException(sprintf('The metadatas %s defined on "%s" are only usable in addition of metadata %s', self::formatMetadata('Visible'), $reflector->getName(), self::formatMetadata('Field')));
}

continue;
}

Expand Down Expand Up @@ -678,6 +683,10 @@ private static function getGraphQLInputFieldsFromMetadatas(ReflectionClass $refl
$fieldConfiguration['type'] = $fieldType;
}

if ($publicMetadata) {
$fieldConfiguration['public'] = self::formatExpression($publicMetadata->value);
}

$fieldConfiguration = array_merge(self::getDescriptionConfiguration($metadatas, true), $fieldConfiguration);
$fields[$fieldName] = $fieldConfiguration;
}
Expand Down
26 changes: 18 additions & 8 deletions src/Definition/Builder/SchemaBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,42 +10,44 @@
use Overblog\GraphQLBundle\Definition\Type\SchemaExtension\ValidatorExtension;
use Overblog\GraphQLBundle\Resolver\TypeResolver;

use Symfony\Contracts\Service\ResetInterface;
use function array_map;

final class SchemaBuilder
final class SchemaBuilder implements ResetInterface
{
private TypeResolver $typeResolver;
private bool $enableValidation;
private array $builders = [];

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

public function getBuilder(string $name, ?string $queryAlias, string $mutationAlias = null, string $subscriptionAlias = null, array $types = []): Closure
public function getBuilder(string $name, ?string $queryAlias, string $mutationAlias = null, string $subscriptionAlias = null, array $types = [], bool $resettable = false): Closure
{
return function () use ($name, $queryAlias, $mutationAlias, $subscriptionAlias, $types): ExtensibleSchema {
static $schema = null;
if (null === $schema) {
$schema = $this->create($name, $queryAlias, $mutationAlias, $subscriptionAlias, $types);
return function () use ($name, $queryAlias, $mutationAlias, $subscriptionAlias, $types, $resettable): ExtensibleSchema {
if (!isset($this->builders[$name])) {
$this->builders[$name] = $this->create($name, $queryAlias, $mutationAlias, $subscriptionAlias, $types, $resettable);
}

return $schema;
return $this->builders[$name];
};
}

/**
* @param string[] $types
*/
public function create(string $name, ?string $queryAlias, string $mutationAlias = null, string $subscriptionAlias = null, array $types = []): ExtensibleSchema
public function create(string $name, ?string $queryAlias, string $mutationAlias = null, string $subscriptionAlias = null, array $types = [], bool $resettable = false): ExtensibleSchema
{
$this->typeResolver->setCurrentSchemaName($name);
$query = $this->typeResolver->resolve($queryAlias);
$mutation = $this->typeResolver->resolve($mutationAlias);
$subscription = $this->typeResolver->resolve($subscriptionAlias);

$schema = new ExtensibleSchema($this->buildSchemaArguments($name, $query, $mutation, $subscription, $types));
$schema->setIsResettable($resettable);
$extensions = [];

if ($this->enableValidation) {
Expand Down Expand Up @@ -74,4 +76,12 @@ private function buildSchemaArguments(string $schemaName, Type $query, ?Type $mu
},
];
}

public function reset(): void
{
$this->builders = array_filter(
$this->builders,
fn (ExtensibleSchema $schema) => false === $schema->isResettable()
);
}
}
15 changes: 15 additions & 0 deletions src/Definition/Type/ExtensibleSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@

class ExtensibleSchema extends Schema
{
/**
* Need to reset when container reset called
*/
private bool $isResettable = false;

public function __construct($config)
{
parent::__construct(
Expand Down Expand Up @@ -51,4 +56,14 @@ public function processExtensions()

return $this;
}

public function isResettable(): bool
{
return $this->isResettable;
}

public function setIsResettable(bool $isResettable): void
{
$this->isResettable = $isResettable;
}
}
1 change: 1 addition & 0 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ private function definitionsSchemaSection(): ArrayNodeDefinition
->scalarNode('query')->defaultNull()->end()
->scalarNode('mutation')->defaultNull()->end()
->scalarNode('subscription')->defaultNull()->end()
->scalarNode('resettable')->defaultFalse()->end()
->arrayNode('types')
->defaultValue([])
->prototype('scalar')->end()
Expand Down
1 change: 1 addition & 0 deletions src/DependencyInjection/OverblogGraphQLExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ private function setSchemaArguments(array $config, ContainerBuilder $container):
$schemaConfig['mutation'],
$schemaConfig['subscription'],
$schemaConfig['types'],
$schemaConfig['resettable'],
]);
// schema
$schemaID = sprintf('%s.schema_%s', $this->getAlias(), $schemaName);
Expand Down
42 changes: 31 additions & 11 deletions src/Request/Executor.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use GraphQL\Validator\Rules\DisableIntrospection;
use GraphQL\Validator\Rules\QueryComplexity;
use GraphQL\Validator\Rules\QueryDepth;
use Overblog\GraphQLBundle\Definition\Type\ExtensibleSchema;
use Overblog\GraphQLBundle\Event\Events;
use Overblog\GraphQLBundle\Event\ExecutorArgumentsEvent;
use Overblog\GraphQLBundle\Event\ExecutorContextEvent;
Expand All @@ -21,15 +22,21 @@
use RuntimeException;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

use Symfony\Contracts\Service\ResetInterface;
use function array_keys;
use function is_callable;
use function sprintf;

class Executor
class Executor implements ResetInterface
{
public const PROMISE_ADAPTER_SERVICE_ID = 'overblog_graphql.promise_adapter';

/**
* @var array<Closure>
*/
private array $schemaBuilders = [];
/**
* @var array<Schema>
*/
private array $schemas = [];
private EventDispatcherInterface $dispatcher;
private PromiseAdapter $promiseAdapter;
Expand Down Expand Up @@ -61,7 +68,7 @@ public function setExecutor(ExecutorInterface $executor): self

public function addSchemaBuilder(string $name, Closure $builder): self
{
$this->schemas[$name] = $builder;
$this->schemaBuilders[$name] = $builder;

return $this;
}
Expand All @@ -75,30 +82,43 @@ public function addSchema(string $name, Schema $schema): self

public function getSchema(string $name = null): Schema
{
if (empty($this->schemas)) {
if (empty($this->schemaBuilders) && empty($this->schemas)) {
throw new RuntimeException('At least one schema should be declare.');
}

if (null === $name) {
$name = isset($this->schemas['default']) ? 'default' : array_key_first($this->schemas);
}

if (!isset($this->schemas[$name])) {
throw new NotFoundHttpException(sprintf('Could not find "%s" schema.', $name));
if (null === $name) {
$name = isset($this->schemaBuilders['default']) ? 'default' : array_key_first($this->schemaBuilders);
}

$schema = $this->schemas[$name];
if (is_callable($schema)) {
$schema = $schema();
if (isset($this->schemas[$name])) {
$schema = $this->schemas[$name];
} elseif (isset($this->schemaBuilders[$name])) {
$schema = call_user_func($this->schemaBuilders[$name]);

$this->addSchema((string) $name, $schema);
} else {
throw new NotFoundHttpException(sprintf('Could not find "%s" schema.', $name));
}

return $schema;
}

public function reset(): void
{
// Remove only ExtensibleSchema and isResettable
$this->schemas = array_filter(
$this->schemas,
fn (Schema $schema) => $schema instanceof ExtensibleSchema && !$schema->isResettable()
);
}

public function getSchemasNames(): array
{
return array_keys($this->schemas);
return array_merge(array_keys($this->schemaBuilders), array_keys($this->schemas));
}

public function setMaxQueryDepth(int $maxQueryDepth): void
Expand Down
24 changes: 14 additions & 10 deletions src/Resolver/AbstractResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@

namespace Overblog\GraphQLBundle\Resolver;

use Symfony\Contracts\Service\ResetInterface;
use function array_keys;

abstract class AbstractResolver implements FluentResolverInterface
abstract class AbstractResolver implements FluentResolverInterface, ResetInterface
{
private array $solutionsFactory = [];
private array $solutions = [];
private array $aliases = [];
private array $solutionOptions = [];
private array $fullyLoadedSolutions = [];

public function addSolution(string $id, callable $factory, array $aliases = [], array $options = []): self
{
$this->fullyLoadedSolutions[$id] = false;
$this->addAliases($id, $aliases);

$this->solutions[$id] = $factory;
$this->solutionsFactory[$id] = $factory;
$this->solutionOptions[$id] = $options;

return $this;
Expand All @@ -28,7 +28,7 @@ public function hasSolution(string $id): bool
{
$id = $this->resolveAlias($id);

return isset($this->solutions[$id]);
return isset($this->solutionsFactory[$id]);
}

/**
Expand Down Expand Up @@ -81,13 +81,12 @@ private function loadSolution(string $id)
return null;
}

if ($this->fullyLoadedSolutions[$id]) {
if (isset($this->solutions[$id])) {
return $this->solutions[$id];
} else {
$loader = $this->solutions[$id];
$loader = $this->solutionsFactory[$id];
$this->solutions[$id] = $solution = $loader();
$this->onLoadSolution($solution);
$this->fullyLoadedSolutions[$id] = true;

return $solution;
}
Expand All @@ -110,10 +109,15 @@ private function resolveAlias(string $alias): string
*/
private function loadSolutions(): array
{
foreach ($this->solutions as $name => &$solution) {
$solution = $this->loadSolution($name);
foreach (array_keys($this->solutionsFactory) as $name) {
$this->loadSolution($name);
}

return $this->solutions;
}

public function reset(): void
{
$this->solutions = [];
}
}
12 changes: 12 additions & 0 deletions src/Resolver/TypeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ public function setCurrentSchemaName(?string $currentSchemaName): void
$this->currentSchemaName = $currentSchemaName;
}

public function getCurrentSchemaName(): ?string
{
return $this->currentSchemaName;
}

public function setIgnoreUnresolvableException(bool $ignoreUnresolvableException): void
{
$this->ignoreUnresolvableException = $ignoreUnresolvableException;
Expand Down Expand Up @@ -82,4 +87,11 @@ protected function supportedSolutionClass(): ?string
{
return Type::class;
}

public function reset(): void
{
parent::reset();

$this->cache = [];
}
}
5 changes: 5 additions & 0 deletions src/Resources/config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,15 @@ services:
calls:
- ["setMaxQueryComplexity", ["%overblog_graphql.query_max_complexity%"]]
- ["setMaxQueryDepth", ["%overblog_graphql.query_max_depth%"]]
tags:
- {name: 'kernel.reset', 'method': "reset"}

Overblog\GraphQLBundle\Definition\Builder\SchemaBuilder:
arguments:
- '@Overblog\GraphQLBundle\Resolver\TypeResolver'
- false
tags:
- { name: 'kernel.reset', 'method': "reset" }

Overblog\GraphQLBundle\Definition\Builder\TypeFactory:
arguments:
Expand All @@ -37,6 +41,7 @@ services:
- ['setDispatcher', ['@event_dispatcher']]
tags:
- { name: overblog_graphql.service, alias: typeResolver }
- {name: 'kernel.reset', 'method': "reset"}

Overblog\GraphQLBundle\Transformer\ArgumentsTransformer:
arguments:
Expand Down