Skip to content

Commit 972047f

Browse files
authored
Merge pull request #724 from jasonvarga/class-based-schema-routes
Fix class based schemas within routes
2 parents a6887ef + 474626a commit 972047f

File tree

8 files changed

+190
-6
lines changed

8 files changed

+190
-6
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ CHANGELOG
44
[Next release](https://github.com/rebing/graphql-laravel/compare/6.4.0...master)
55
--------------
66

7+
### Fixed
8+
- Middleware and methods can be used in class based schemas. [\#724 / jasonvarga](https://github.com/rebing/graphql-laravel/pull/724)\
9+
This is a follow-up fix for [Support for class based schemas](https://github.com/rebing/graphql-laravel/pull/706)
10+
711
2021-03-31, 6.4.0
812
-----------------
913
### Added

phpstan.neon.dist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ parameters:
5858
- '/Parameter #1 \$name of method Rebing\\GraphQL\\Support\\Type\:\:getFieldResolver\(\) expects string, int\|string given/'
5959
# tests/Unit/EndpointTest.php
6060
- '/Parameter #1 \$wrappedType of static method GraphQL\\Type\\Definition\\Type::nonNull\(\) expects \(callable\(\): mixed\)\|GraphQL\\Type\\Definition\\NullableType, GraphQL\\Type\\Definition\\Type given/'
61+
- '/Parameter #1 \$array of static method Illuminate\\Support\\Arr::get\(\) expects array\|ArrayAccess/'
6162
# Mass ignore the raw array property access used in many tests for now
6263
# See also https://github.com/nunomaduro/larastan/issues/611
6364
-

src/GraphQL.php

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -503,10 +503,41 @@ protected function getSchemaConfiguration($schema)
503503

504504
$schema = is_array($schema) ? $schema : $this->schemas[$schemaName];
505505

506-
if (! is_string($schema)) {
506+
return static::getNormalizedSchemaConfiguration($schema);
507+
}
508+
509+
/**
510+
* @return array<string, array|Schema>
511+
*/
512+
public static function getNormalizedSchemasConfiguration(): array
513+
{
514+
return array_filter(array_map(function ($schema) {
515+
try {
516+
return static::getNormalizedSchemaConfiguration($schema);
517+
} catch (SchemaNotFound $e) {
518+
return null;
519+
}
520+
}, config('graphql.schemas')));
521+
}
522+
523+
/**
524+
* @param Schema|array<array>|string|null $schema
525+
* @return Schema|array<array>
526+
*/
527+
public static function getNormalizedSchemaConfiguration($schema)
528+
{
529+
if (is_array($schema) || $schema instanceof Schema) {
507530
return $schema;
508531
}
509532

533+
if (is_null($schema)) {
534+
return [];
535+
}
536+
537+
if (! class_exists($schema)) {
538+
throw new SchemaNotFound('Schema class '.$schema.' not found.');
539+
}
540+
510541
/** @var ConfigConvertible $instance */
511542
$instance = app()->make($schema);
512543

src/routes.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,11 @@
4646
}, ARRAY_FILTER_USE_BOTH);
4747

4848
if ($queryTypesMapWithRoutes) {
49-
$defaultMiddleware = config('graphql.schemas.'.config('graphql.default_schema').'.middleware', []);
50-
$defaultMethod = config('graphql.schemas.'.config('graphql.default_schema').'.method', ['get', 'post']);
49+
$schemaConfig = Rebing\GraphQL\GraphQL::getNormalizedSchemasConfiguration();
50+
51+
$defaultConfig = Arr::get($schemaConfig, config('graphql.default_schema'), []);
52+
$defaultMiddleware = $defaultConfig['middleware'] ?? [];
53+
$defaultMethod = $defaultConfig['method'] ?? ['get', 'post'];
5154

5255
foreach ($queryTypesMapWithRoutes as $type => $info) {
5356
if (preg_match($schemaParameterPattern, $info['route'])) {
@@ -66,7 +69,7 @@
6669
);
6770
}
6871

69-
foreach (config('graphql.schemas') as $name => $schema) {
72+
foreach ($schemaConfig as $name => $schema) {
7073
foreach (Arr::get($schema, 'method', ['get', 'post']) as $method) {
7174
$routeName = "graphql.$name";
7275
if ($method !== 'get') {

tests/Support/Objects/ExampleSchema.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ public function toConfig(): array
1717
'mutation' => [
1818
'updateExampleCustom' => UpdateExampleMutation::class,
1919
],
20+
'middleware' => [
21+
ExampleMiddleware::class,
22+
]
2023
];
2124
}
2225
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rebing\GraphQL\Tests\Support\Objects;
6+
7+
class ExampleSchemaWithMethod extends ExampleSchema
8+
{
9+
public function toConfig(): array
10+
{
11+
return array_merge(parent::toConfig(), ['method' => ['post']]);
12+
}
13+
}

tests/Unit/GraphQLTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,8 @@ public function testSchemaWithWrongName(): void
120120
*/
121121
public function testSchemaWithInvalidClassName(): void
122122
{
123-
$this->expectException(BindingResolutionException::class);
124-
$this->expectExceptionMessage('Target class [ThisClassDoesntExist] does not exist.');
123+
$this->expectException(SchemaNotFound::class);
124+
$this->expectExceptionMessage('Schema class ThisClassDoesntExist not found.');
125125
GraphQL::schema('invalid_class_based');
126126
}
127127

tests/Unit/RoutesTest.php

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rebing\GraphQL\Tests\Unit;
6+
7+
use GraphQL\Utils\BuildSchema;
8+
use Illuminate\Routing\Route;
9+
use Illuminate\Support\Collection;
10+
use Rebing\GraphQL\Tests\Support\Objects\ExampleMiddleware;
11+
use Rebing\GraphQL\Tests\Support\Objects\ExampleSchema;
12+
use Rebing\GraphQL\Tests\Support\Objects\ExampleSchemaWithMethod;
13+
use Rebing\GraphQL\Tests\TestCase;
14+
15+
class RoutesTest extends TestCase
16+
{
17+
protected function getEnvironmentSetUp($app)
18+
{
19+
$app['config']->set('graphql', [
20+
21+
'prefix' => 'graphql_test',
22+
23+
'graphiql' => [
24+
'display' => false,
25+
],
26+
27+
'schemas' => [
28+
'default' => [
29+
'middleware' => [ExampleMiddleware::class]
30+
],
31+
'custom' => [
32+
'middleware' => [ExampleMiddleware::class]
33+
],
34+
'with_methods' => [
35+
'method' => ['post'],
36+
'middleware' => [ExampleMiddleware::class]
37+
],
38+
'class_based' => ExampleSchema::class,
39+
'class_based_with_methods' => ExampleSchemaWithMethod::class,
40+
'shorthand' => BuildSchema::build('
41+
schema {
42+
query: ShorthandExample
43+
}
44+
45+
type ShorthandExample {
46+
echo(message: String!): String!
47+
}
48+
'),
49+
]
50+
51+
]);
52+
}
53+
54+
public function testRoutes(): void
55+
{
56+
$expected = [
57+
'graphql.query' => [
58+
'methods' => ['GET', 'HEAD'],
59+
'uri' => 'graphql_test',
60+
'middleware' => [ExampleMiddleware::class],
61+
],
62+
'graphql.query.post' => [
63+
'methods' => ['POST'],
64+
'uri' => 'graphql_test',
65+
'middleware' => [ExampleMiddleware::class],
66+
],
67+
'graphql.default' => [
68+
'methods' => ['GET', 'HEAD'],
69+
'uri' => 'graphql_test/{default}',
70+
'middleware' => [ExampleMiddleware::class],
71+
],
72+
'graphql.default.post' => [
73+
'methods' => ['POST'],
74+
'uri' => 'graphql_test/{default}',
75+
'middleware' => [ExampleMiddleware::class],
76+
],
77+
'graphql.custom' => [
78+
'methods' => ['GET', 'HEAD'],
79+
'uri' => 'graphql_test/{custom}',
80+
'middleware' => [ExampleMiddleware::class],
81+
],
82+
'graphql.custom.post' => [
83+
'methods' => ['POST'],
84+
'uri' => 'graphql_test/{custom}',
85+
'middleware' => [ExampleMiddleware::class],
86+
],
87+
'graphql.with_methods.post' => [
88+
'methods' => ['POST'],
89+
'uri' => 'graphql_test/{with_methods}',
90+
'middleware' => [ExampleMiddleware::class],
91+
],
92+
'graphql.class_based' => [
93+
'methods' => ['GET', 'HEAD'],
94+
'uri' => 'graphql_test/{class_based}',
95+
'middleware' => [ExampleMiddleware::class],
96+
],
97+
'graphql.class_based.post' => [
98+
'methods' => ['POST'],
99+
'uri' => 'graphql_test/{class_based}',
100+
'middleware' => [ExampleMiddleware::class],
101+
],
102+
'graphql.class_based_with_methods.post' => [
103+
'methods' => ['POST'],
104+
'uri' => 'graphql_test/{class_based_with_methods}',
105+
'middleware' => [ExampleMiddleware::class],
106+
],
107+
'graphql.shorthand' => [
108+
'methods' => ['GET', 'HEAD'],
109+
'uri' => 'graphql_test/{shorthand}',
110+
'middleware' => [],
111+
],
112+
'graphql.shorthand.post' => [
113+
'methods' => ['POST'],
114+
'uri' => 'graphql_test/{shorthand}',
115+
'middleware' => [],
116+
],
117+
];
118+
119+
$this->assertEquals($expected, Collection::make(
120+
app('router')->getRoutes()->getRoutesByName()
121+
)->map(function (Route $route) {
122+
return [
123+
'methods' => $route->methods(),
124+
'uri' => $route->uri(),
125+
'middleware' => $route->middleware(),
126+
];
127+
})->all());
128+
}
129+
}

0 commit comments

Comments
 (0)