15
15
16
16
use ApiPlatform \Core \Api \IdentifiersExtractorInterface ;
17
17
use ApiPlatform \Core \Bridge \Graphql \Resolver \CollectionResolverFactoryInterface ;
18
+ use ApiPlatform \Core \Bridge \Graphql \Resolver \ItemMutationResolverFactoryInterface ;
18
19
use ApiPlatform \Core \Bridge \Graphql \Resolver \ItemResolverFactoryInterface ;
19
20
use ApiPlatform \Core \Exception \ResourceClassNotFoundException ;
20
21
use ApiPlatform \Core \Metadata \Property \Factory \PropertyMetadataFactoryInterface ;
@@ -48,35 +49,43 @@ final class SchemaBuilder implements SchemaBuilderInterface
48
49
private $ resourceMetadataFactory ;
49
50
private $ collectionResolverFactory ;
50
51
private $ itemResolverFactory ;
52
+ private $ itemMutationResolverFactory ;
51
53
private $ identifiersExtractor ;
52
54
private $ paginationEnabled ;
53
55
private $ resourceTypesCache = [];
54
56
55
- public function __construct (PropertyNameCollectionFactoryInterface $ propertyNameCollectionFactory , PropertyMetadataFactoryInterface $ propertyMetadataFactory , ResourceNameCollectionFactoryInterface $ resourceNameCollectionFactory , ResourceMetadataFactoryInterface $ resourceMetadataFactory , CollectionResolverFactoryInterface $ collectionResolverFactory , ItemResolverFactoryInterface $ itemResolverFactory , IdentifiersExtractorInterface $ identifiersExtractor , bool $ paginationEnabled )
57
+ public function __construct (PropertyNameCollectionFactoryInterface $ propertyNameCollectionFactory , PropertyMetadataFactoryInterface $ propertyMetadataFactory , ResourceNameCollectionFactoryInterface $ resourceNameCollectionFactory , ResourceMetadataFactoryInterface $ resourceMetadataFactory , CollectionResolverFactoryInterface $ collectionResolverFactory , ItemResolverFactoryInterface $ itemResolverFactory , ItemMutationResolverFactoryInterface $ itemMutationResolverFactory , IdentifiersExtractorInterface $ identifiersExtractor , bool $ paginationEnabled )
56
58
{
57
59
$ this ->propertyNameCollectionFactory = $ propertyNameCollectionFactory ;
58
60
$ this ->propertyMetadataFactory = $ propertyMetadataFactory ;
59
61
$ this ->resourceNameCollectionFactory = $ resourceNameCollectionFactory ;
60
62
$ this ->resourceMetadataFactory = $ resourceMetadataFactory ;
61
63
$ this ->collectionResolverFactory = $ collectionResolverFactory ;
62
64
$ this ->itemResolverFactory = $ itemResolverFactory ;
65
+ $ this ->itemMutationResolverFactory = $ itemMutationResolverFactory ;
63
66
$ this ->identifiersExtractor = $ identifiersExtractor ;
64
67
$ this ->paginationEnabled = $ paginationEnabled ;
65
68
}
66
69
67
70
public function getSchema (): Schema
68
71
{
69
72
$ queryFields = [];
73
+ $ mutationFields = [];
70
74
71
75
foreach ($ this ->resourceNameCollectionFactory ->create () as $ resource ) {
72
76
$ queryFields += $ this ->getQueryFields ($ resource );
77
+ $ mutationFields += $ this ->getMutationFields ($ resource );
73
78
}
74
79
75
80
return new Schema ([
76
81
'query ' => new ObjectType ([
77
82
'name ' => 'Query ' ,
78
83
'fields ' => $ queryFields ,
79
84
]),
85
+ 'mutation ' => new ObjectType ([
86
+ 'name ' => 'Mutation ' ,
87
+ 'fields ' => $ mutationFields ,
88
+ ]),
80
89
]);
81
90
}
82
91
@@ -107,14 +116,35 @@ private function getQueryFields(string $resource): array
107
116
return $ queryFields ;
108
117
}
109
118
119
+ /**
120
+ * Gets the mutation fields of the schema.
121
+ */
122
+ private function getMutationFields (string $ resource ): array
123
+ {
124
+ $ mutationFields = [];
125
+ $ resourceMetadata = $ this ->resourceMetadataFactory ->create ($ resource );
126
+ $ shortName = $ resourceMetadata ->getShortName ();
127
+ $ resourceType = new Type (Type::BUILTIN_TYPE_OBJECT , true , $ resource );
128
+
129
+ foreach ($ this ->getOperations ($ resourceMetadata , false , true ) as $ operationName => $ mutationItemOperation ) {
130
+ if ($ fieldConfiguration = $ this ->getResourceFieldConfiguration (ucfirst ("{$ operationName }s one $ shortName. " ), $ resourceType , $ resource )) {
131
+ $ fieldConfiguration ['args ' ] += $ this ->getResourceMutationArgumentsConfiguration ($ resourceType , $ resource );
132
+ $ fieldConfiguration ['resolve ' ] = $ resourceType ->isCollection () ? null : $ this ->itemMutationResolverFactory ->createItemMutationResolver ($ resource , $ operationName , $ mutationItemOperation );
133
+ $ mutationFields [$ operationName .$ shortName ] = $ fieldConfiguration ;
134
+ }
135
+ }
136
+
137
+ return $ mutationFields ;
138
+ }
139
+
110
140
/**
111
141
* Get the field configuration of a resource.
112
142
*
113
143
* @see http://webonyx.github.io/graphql-php/type-system/object-types/
114
144
*
115
145
* @return array|null
116
146
*/
117
- private function getResourceFieldConfiguration (string $ fieldDescription = null , Type $ type , string $ rootResource , bool $ isInput = false )
147
+ private function getResourceFieldConfiguration (string $ fieldDescription = null , Type $ type , string $ rootResource , bool $ isInput = false , bool $ isMutation = false )
118
148
{
119
149
try {
120
150
$ graphqlType = $ this ->convertType ($ type , $ isInput );
@@ -123,7 +153,7 @@ private function getResourceFieldConfiguration(string $fieldDescription = null,
123
153
$ className = $ isInternalGraphqlType ? '' : ($ type ->isCollection () ? $ type ->getCollectionValueType ()->getClassName () : $ type ->getClassName ());
124
154
125
155
$ args = [];
126
- if ($ this ->paginationEnabled && !$ isInternalGraphqlType && $ type ->isCollection () && !$ isInput ) {
156
+ if ($ this ->paginationEnabled && !$ isInternalGraphqlType && $ type ->isCollection () && !$ isInput && ! $ isMutation ) {
127
157
$ args = [
128
158
'first ' => [
129
159
'type ' => GraphQLType::int (),
@@ -136,7 +166,7 @@ private function getResourceFieldConfiguration(string $fieldDescription = null,
136
166
];
137
167
}
138
168
139
- if ($ isInternalGraphqlType || $ isInput ) {
169
+ if ($ isInternalGraphqlType || $ isInput || $ isMutation ) {
140
170
$ resolve = null ;
141
171
} else {
142
172
$ resolve = $ type ->isCollection () ? $ this ->collectionResolverFactory ->createCollectionResolver ($ className , $ rootResource ) : $ this ->itemResolverFactory ->createItemResolver ($ className , $ rootResource );
@@ -153,6 +183,14 @@ private function getResourceFieldConfiguration(string $fieldDescription = null,
153
183
}
154
184
}
155
185
186
+ /**
187
+ * Gets the field arguments of the mutation of a given resource.
188
+ */
189
+ private function getResourceMutationArgumentsConfiguration (Type $ type , string $ resource ): array
190
+ {
191
+ return ['input ' => $ this ->getResourceFieldConfiguration (null , $ type , $ resource , true )];
192
+ }
193
+
156
194
/**
157
195
* Gets the field arguments of the identifier of a given resource.
158
196
*
@@ -335,6 +373,10 @@ private function getOperations(ResourceMetadata $resourceMetadata, bool $isQuery
335
373
continue ;
336
374
}
337
375
376
+ if (Request::METHOD_PATCH === $ operation ['method ' ]) {
377
+ continue ;
378
+ }
379
+
338
380
yield $ operationName => $ operation ;
339
381
}
340
382
}
0 commit comments