Skip to content

Commit 86a89f3

Browse files
authored
Merge pull request #779 from mfn/mfn-schema
Rewrite and simplify how schemas are handled
2 parents 4e63db8 + f40f07f commit 86a89f3

File tree

22 files changed

+144
-347
lines changed

22 files changed

+144
-347
lines changed

CHANGELOG.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,26 @@ CHANGELOG
55
--------------
66

77
## Breaking changes
8+
- Rewrite and simplify how schemas are handled
9+
- `\Rebing\GraphQL\GraphQL::$schemas` now only holds `Schema`s and not a
10+
mixture of strings or arrays
11+
- `\Rebing\GraphQL\GraphQL::schema()` now only accepts a "schema name", but no
12+
ad hoc `Schema` or "schema configs". To use ad hoc schemas, use
13+
`\Rebing\GraphQL\GraphQL::buildSchemaFromConfig()` and
14+
`\Rebing\GraphQL\GraphQL::addSchema()`
15+
- `\Rebing\GraphQL\GraphQL::queryAndReturnResult()` (and thus also
16+
`\Rebing\GraphQL\GraphQL::query()`) does not accept ad hoc schemas via
17+
`$opts['schema']` anymore; it now only can reference a schema via its name.
18+
- `\Rebing\GraphQL\GraphQL::addSchema()` now only accept `Schema` objects,
19+
where before it would support ad hoc schemas via array configuration.
20+
Use `\Rebing\GraphQL\GraphQL::buildSchemaFromConfig()` for that now.
21+
- `\Rebing\GraphQL\GraphQL::getSchemaConfiguration()` has been removed due to
22+
the simplifications.
23+
- `\Rebing\GraphQL\GraphQL::getNormalizedSchemaConfiguration()` does not
24+
support ad hoc schemas anymore and only accepts the schema name.
25+
- `\Rebing\GraphQL\GraphQLServiceProvider::bootSchemas()` has been removed due
26+
to the simplifications.
27+
828
- The following methods now take a `\Illuminate\Contracts\Config\Repository` as
929
second argument:
1030
- `\Rebing\GraphQL\GraphQL::__construct`
@@ -98,6 +118,7 @@ CHANGELOG
98118
- Laravels `ValidationException` is now formatted the same way as a `ValidationError` [\#748 / mfn](https://github.com/rebing/graphql-laravel/pull/748)
99119

100120
### Changed
121+
- Rewrite and simplify how schemas are handled [\#779 / mfn](https://github.com/rebing/graphql-laravel/pull/779)
101122
- Internally stop using the global `config()` function and preferable use the repository or the Facade otherwise [\#774 / mfn](https://github.com/rebing/graphql-laravel/pull/774)
102123
- Don't silence broken schemas when normalizing them for generating routes [\#766 / mfn](https://github.com/rebing/graphql-laravel/pull/766)
103124
- Lazy loading types has been enabled by default [\#758 / mfn](https://github.com/rebing/graphql-laravel/pull/758)

phpstan-baseline.neon

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
parameters:
22
ignoreErrors:
3-
-
4-
message: "#^Method Rebing\\\\GraphQL\\\\GraphQL\\:\\:addSchema\\(\\) has parameter \\$schema with no value type specified in iterable type array\\.$#"
5-
count: 1
6-
path: src/GraphQL.php
7-
83
-
94
message: "#^Method Rebing\\\\GraphQL\\\\GraphQL\\:\\:addTypes\\(\\) has parameter \\$types with no value type specified in iterable type array\\.$#"
105
count: 1
@@ -30,36 +25,16 @@ parameters:
3025
count: 1
3126
path: src/GraphQL.php
3227

33-
-
34-
message: "#^Method Rebing\\\\GraphQL\\\\GraphQL\\:\\:getSchemaConfiguration\\(\\) has parameter \\$schema with no value type specified in iterable type array\\.$#"
35-
count: 1
36-
path: src/GraphQL.php
37-
38-
-
39-
message: "#^Method Rebing\\\\GraphQL\\\\GraphQL\\:\\:getSchemaConfiguration\\(\\) return type has no value type specified in iterable type array\\.$#"
40-
count: 1
41-
path: src/GraphQL.php
42-
4328
-
4429
message: "#^Method Rebing\\\\GraphQL\\\\GraphQL\\:\\:getSchemas\\(\\) return type has no value type specified in iterable type array\\.$#"
4530
count: 1
4631
path: src/GraphQL.php
4732

48-
-
49-
message: "#^Method Rebing\\\\GraphQL\\\\GraphQL\\:\\:mergeSchemas\\(\\) has parameter \\$schema with no value type specified in iterable type array\\.$#"
50-
count: 1
51-
path: src/GraphQL.php
52-
5333
-
5434
message: "#^Method Rebing\\\\GraphQL\\\\GraphQL\\:\\:objectType\\(\\) has parameter \\$type with no value type specified in iterable type array\\.$#"
5535
count: 1
5636
path: src/GraphQL.php
5737

58-
-
59-
message: "#^Method Rebing\\\\GraphQL\\\\GraphQL\\:\\:schema\\(\\) has parameter \\$schema with no value type specified in iterable type array\\.$#"
60-
count: 1
61-
path: src/GraphQL.php
62-
6338
-
6439
message: "#^Access to an undefined property GraphQL\\\\Type\\\\Definition\\\\InputObjectField\\|stdClass\\:\\:\\$alias\\.$#"
6540
count: 1

src/GraphQL.php

Lines changed: 90 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class GraphQL
3838
/** @var Container */
3939
protected $app;
4040

41-
/** @var array<array|string|Schema> */
41+
/** @var array<Schema> */
4242
protected $schemas = [];
4343

4444
/**
@@ -60,61 +60,23 @@ public function __construct(Container $app, Repository $config)
6060
$this->config = $config;
6161
}
6262

63-
/**
64-
* @param Schema|array|string|null $schema
65-
*/
66-
public function schema($schema = null): Schema
63+
public function schema(?string $schemaName = null): Schema
6764
{
68-
if ($schema instanceof Schema) {
69-
return $schema;
70-
}
71-
72-
$this->clearTypeInstances();
73-
74-
$schema = $this->getSchemaConfiguration($schema);
65+
$schemaName = $schemaName ?? $this->config->get('graphql.default_schema', 'default');
7566

76-
if ($schema instanceof Schema) {
77-
return $schema;
67+
if (isset($this->schemas[$schemaName])) {
68+
return $this->schemas[$schemaName];
7869
}
7970

80-
$schemaQuery = $schema['query'] ?? [];
81-
$schemaMutation = $schema['mutation'] ?? [];
82-
$schemaSubscription = $schema['subscription'] ?? [];
83-
$schemaTypes = $schema['types'] ?? [];
84-
85-
$this->addTypes($schemaTypes);
86-
87-
$query = $this->objectType($schemaQuery, [
88-
'name' => 'Query',
89-
]);
90-
91-
$mutation = $schemaMutation
92-
? $this->objectType($schemaMutation, ['name' => 'Mutation'])
93-
: null;
71+
$this->clearTypeInstances();
9472

95-
$subscription = $schemaSubscription
96-
? $this->objectType($schemaSubscription, ['name' => 'Subscription'])
97-
: null;
73+
$schemaConfig = static::getNormalizedSchemaConfiguration($schemaName);
9874

99-
return new Schema([
100-
'query' => $query,
101-
'mutation' => $mutation,
102-
'subscription' => $subscription,
103-
'types' => function () {
104-
$types = [];
75+
$schema = $this->buildSchemaFromConfig($schemaConfig);
10576

106-
foreach ($this->getTypes() as $name => $type) {
107-
$types[] = $this->type($name);
108-
}
77+
$this->addSchema($schemaName, $schema);
10978

110-
return $types;
111-
},
112-
'typeLoader' => $this->config->get('graphql.lazyload_types', true)
113-
? function ($name) {
114-
return $this->type($name);
115-
}
116-
: null,
117-
]);
79+
return $schema;
11880
}
11981

12082
/**
@@ -136,15 +98,11 @@ public function query(string $query, ?array $variables = null, array $opts = [])
13698
public function queryAndReturnResult(string $query, ?array $variables = null, array $opts = []): ExecutionResult
13799
{
138100
$context = $opts['context'] ?? null;
139-
$schema = $opts['schema'] ?? null;
101+
$schemaName = $opts['schema'] ?? $this->config->get('graphql.default_schema', 'default');
140102
$operationName = $opts['operationName'] ?? null;
141103
$rootValue = $opts['rootValue'] ?? null;
142104

143-
$schemaName = is_string($schema) && !empty($this->config->get("graphql.schemas.$schema"))
144-
? $schema
145-
: $this->config->get('graphql.default_schema', 'default');
146-
147-
$schema = $this->schema($schema);
105+
$schema = $this->schema($schemaName);
148106

149107
$baseParams = new BaseOperationParams();
150108
$baseParams->query = $query;
@@ -384,24 +342,54 @@ protected function buildObjectTypeFromFields(array $fields, array $opts = []): O
384342
], $opts));
385343
}
386344

387-
/**
388-
* @param Schema|array $schema
389-
*/
390-
public function addSchema(string $name, $schema): void
345+
public function addSchema(string $name, Schema $schema): void
391346
{
392-
$this->mergeSchemas($name, $schema);
347+
$this->schemas[$name] = $schema;
393348
}
394349

395350
/**
396-
* @param Schema|array $schema
351+
* @param array<string,mixed> $schemaConfig
397352
*/
398-
public function mergeSchemas(string $name, $schema): void
353+
public function buildSchemaFromConfig(array $schemaConfig): Schema
399354
{
400-
if (isset($this->schemas[$name]) && is_array($this->schemas[$name]) && is_array($schema)) {
401-
$this->schemas[$name] = array_merge_recursive($this->schemas[$name], $schema);
402-
} else {
403-
$this->schemas[$name] = $schema;
404-
}
355+
$schemaQuery = $schemaConfig['query'] ?? [];
356+
$schemaMutation = $schemaConfig['mutation'] ?? [];
357+
$schemaSubscription = $schemaConfig['subscription'] ?? [];
358+
$schemaTypes = $schemaConfig['types'] ?? [];
359+
360+
$this->addTypes($schemaTypes);
361+
362+
$query = $this->objectType($schemaQuery, [
363+
'name' => 'Query',
364+
]);
365+
366+
$mutation = $schemaMutation
367+
? $this->objectType($schemaMutation, ['name' => 'Mutation'])
368+
: null;
369+
370+
$subscription = $schemaSubscription
371+
? $this->objectType($schemaSubscription, ['name' => 'Subscription'])
372+
: null;
373+
374+
return new Schema([
375+
'query' => $query,
376+
'mutation' => $mutation,
377+
'subscription' => $subscription,
378+
'types' => function () {
379+
$types = [];
380+
381+
foreach ($this->getTypes() as $name => $type) {
382+
$types[] = $this->type($name);
383+
}
384+
385+
return $types;
386+
},
387+
'typeLoader' => $this->config->get('graphql.lazyload_types', true)
388+
? function ($name) {
389+
return $this->type($name);
390+
}
391+
: null,
392+
]);
405393
}
406394

407395
public function clearType(string $name): void
@@ -553,57 +541,60 @@ public static function handleErrors(array $errors, callable $formatter): array
553541
}
554542

555543
/**
556-
* @param array|string|null $schema
557-
* @return array|Schema
544+
* @return array<string,array<string,mixed>>
558545
*/
559-
protected function getSchemaConfiguration($schema)
546+
public static function getNormalizedSchemasConfiguration(): array
560547
{
561-
$schemaName = is_string($schema) ? $schema : $this->config->get('graphql.default_schema', 'default');
548+
$schemaConfigs = [];
562549

563-
if (!is_array($schema) && !isset($this->schemas[$schemaName])) {
564-
throw new SchemaNotFound('Type ' . $schemaName . ' not found.');
550+
/** @var string $schemaName */
551+
foreach (array_keys(Config::get('graphql.schemas', [])) as $schemaName) {
552+
$schemaConfigs[$schemaName] = static::getNormalizedSchemaConfiguration($schemaName);
565553
}
566554

567-
$schema = is_array($schema) ? $schema : $this->schemas[$schemaName];
568-
569-
return static::getNormalizedSchemaConfiguration($schema);
555+
return $schemaConfigs;
570556
}
571557

572558
/**
573-
* @return array<string, array|Schema>
559+
* @return array<string,mixed>
574560
*/
575-
public static function getNormalizedSchemasConfiguration(): array
561+
public static function getNormalizedSchemaConfiguration(string $schemaName): array
576562
{
577-
return array_map(
578-
static function ($schema) {
579-
return static::getNormalizedSchemaConfiguration($schema);
580-
},
581-
Config::get('graphql.schemas', [])
582-
);
583-
}
563+
$schemas = Config::get('graphql.schemas');
584564

585-
/**
586-
* @param Schema|array<array>|string|null $schema
587-
* @return Schema|array<array>
588-
*/
589-
public static function getNormalizedSchemaConfiguration($schema)
590-
{
591-
if (is_array($schema) || $schema instanceof Schema) {
592-
return $schema;
565+
if (!array_key_exists($schemaName, $schemas)) {
566+
throw new SchemaNotFound("No configuration for schema '$schemaName' found");
593567
}
594568

595-
if (is_null($schema)) {
596-
return [];
569+
$schemaConfig = $schemas[$schemaName];
570+
571+
if (!is_string($schemaConfig) && !is_array($schemaConfig)) {
572+
throw new SchemaNotFound(
573+
sprintf(
574+
"Configuration for schema '%s' must be either an array or a class implementing %s, found type %s",
575+
$schemaName,
576+
ConfigConvertible::class,
577+
gettype($schemaConfig)
578+
)
579+
);
597580
}
598581

599-
if (!class_exists($schema)) {
600-
throw new SchemaNotFound('Schema class ' . $schema . ' not found.');
582+
if (!$schemaConfig) {
583+
throw new SchemaNotFound("Empty configuration found for schema '$schemaName'");
601584
}
602585

603-
/** @var ConfigConvertible $instance */
604-
$instance = app()->make($schema);
586+
if (is_string($schemaConfig)) {
587+
if (!class_exists($schemaConfig)) {
588+
throw new SchemaNotFound("Cannot find class '$schemaConfig' for schema '$schemaName'");
589+
}
590+
591+
/** @var ConfigConvertible $instance */
592+
$instance = app()->make($schemaConfig);
593+
594+
$schemaConfig = $instance->toConfig();
595+
}
605596

606-
return $instance->toConfig();
597+
return $schemaConfig;
607598
}
608599

609600
public function decorateExecutionResult(ExecutionResult $executionResult): ExecutionResult

src/GraphQLServiceProvider.php

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -67,18 +67,6 @@ protected function bootTypes(GraphQL $graphQL): void
6767
$graphQL->addTypes($configTypes);
6868
}
6969

70-
/**
71-
* Add schemas from config.
72-
*/
73-
protected function bootSchemas(GraphQL $graphQL): void
74-
{
75-
$configSchemas = $graphQL->getConfigRepository()->get('graphql.schemas', []);
76-
77-
foreach ($configSchemas as $name => $schema) {
78-
$graphQL->addSchema($name, $schema);
79-
}
80-
}
81-
8270
/**
8371
* Configure security from config.
8472
*/
@@ -130,8 +118,6 @@ public function registerGraphQL(): void
130118

131119
$this->applySecurityRules($config);
132120

133-
$this->bootSchemas($graphql);
134-
135121
return $graphql;
136122
});
137123
$this->app->alias(GraphQL::class, 'graphql');

src/Support/Facades/GraphQL.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@
2020
* @method static Type paginate(string $typeName, string $customName = null)
2121
* @method static Type simplePaginate(string $typeName, string $customName = null)
2222
* @method static array<string,object|string> getTypes()
23-
* @method static Schema schema(Schema|array|string $schema = null)
23+
* @method static Schema schema(?string $schema = null)
24+
* @method static Schema buildSchemaFromConfig(array $schemaConfig)
2425
* @method static array getSchemas()
25-
* @method static void addSchema(string $name, Schema|array $schema)
26+
* @method static void addSchema(string $name, Schema $schema)
2627
* @method static void addType(object|string $class, string $name = null)
2728
* @method static Type objectType(ObjectType|array|string $type, array $opts = [])
2829
* @method static array formatError(Error $e)

src/routes.php

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,6 @@ function (Router $router) use ($config, $routeConfig): void {
3232
$defaultSchema = $config->get('graphql.default_schema', 'default');
3333

3434
foreach ($schemas as $schemaName => $schemaConfig) {
35-
// A schemaConfig can in fact be a \GraphQL\Type\Schema object
36-
// in which case no further information can be extracted from it
37-
if (is_object($schemaConfig)) {
38-
$schemaConfig = [];
39-
}
40-
4135
$actions = array_filter([
4236
'uses' => $schemaConfig['controller'] ?? $routeConfig['controller'] ?? GraphQLController::class . '@query',
4337
'middleware' => $schemaConfig['middleware'] ?? $routeConfig['middleware'] ?? null,

0 commit comments

Comments
 (0)