55namespace Apollo \Federation ;
66
77use Apollo \Federation \Types \EntityObjectType ;
8+ use Apollo \Federation \Types \SchemaExtensionType ;
89use Apollo \Federation \Utils \FederatedSchemaPrinter ;
910use GraphQL \Type \Definition \CustomScalarType ;
1011use GraphQL \Type \Definition \Directive ;
@@ -22,6 +23,11 @@ trait FederatedSchemaTrait
2223 */
2324 protected array $ entityTypes = [];
2425
26+ /**
27+ * @var SchemaExtensionType[]
28+ */
29+ protected array $ schemaExtensionTypes = [];
30+
2531 /**
2632 * @var Directive[]
2733 */
@@ -42,7 +48,15 @@ public function getEntityTypes(): array
4248 */
4349 public function hasEntityTypes (): bool
4450 {
45- return !empty ($ this ->getEntityTypes ());
51+ return !empty ($ this ->entityTypes );
52+ }
53+
54+ /**
55+ * @return SchemaExtensionType[]
56+ */
57+ public function getSchemaExtensionTypes (): array
58+ {
59+ return $ this ->schemaExtensionTypes ;
4660 }
4761
4862 /**
@@ -59,22 +73,25 @@ protected function getEntityDirectivesConfig(array $config): array
5973 }
6074
6175 /**
62- * @param array<string,mixed> $config
76+ * @param array{ query: ObjectType } $config
6377 *
6478 * @return array{ query: ObjectType }
6579 */
6680 protected function getQueryTypeConfig (array $ config ): array
6781 {
6882 $ queryTypeConfig = $ config ['query ' ]->config ;
69- if (\is_callable ($ queryTypeConfig ['fields ' ])) {
70- $ queryTypeConfig ['fields ' ] = $ queryTypeConfig ['fields ' ]();
71- }
83+ $ fields = $ queryTypeConfig ['fields ' ];
84+ $ queryTypeConfig ['fields ' ] = function () use ($ config , $ fields ) {
85+ if (\is_callable ($ fields )) {
86+ $ fields = $ fields ();
87+ }
7288
73- $ queryTypeConfig ['fields ' ] = array_merge (
74- $ queryTypeConfig ['fields ' ],
75- $ this ->getQueryTypeServiceFieldConfig (),
76- $ this ->getQueryTypeEntitiesFieldConfig ($ config )
77- );
89+ return array_merge (
90+ $ fields ,
91+ $ this ->getQueryTypeServiceFieldConfig (),
92+ $ this ->getQueryTypeEntitiesFieldConfig ($ config )
93+ );
94+ };
7895
7996 return [
8097 'query ' => new ObjectType ($ queryTypeConfig ),
@@ -87,17 +104,17 @@ protected function getQueryTypeConfig(array $config): array
87104 protected function getQueryTypeServiceFieldConfig (): array
88105 {
89106 $ serviceType = new ObjectType ([
90- 'name ' => self ::RESERVED_TYPE_SERVICE ,
107+ 'name ' => FederatedSchema ::RESERVED_TYPE_SERVICE ,
91108 'fields ' => [
92- self ::RESERVED_FIELD_SDL => [
109+ FederatedSchema ::RESERVED_FIELD_SDL => [
93110 'type ' => Type::string (),
94111 'resolve ' => fn (): string => FederatedSchemaPrinter::doPrint ($ this ),
95112 ],
96113 ],
97114 ]);
98115
99116 return [
100- self ::RESERVED_FIELD_SERVICE => [
117+ FederatedSchema ::RESERVED_FIELD_SERVICE => [
101118 'type ' => Type::nonNull ($ serviceType ),
102119 'resolve ' => static fn (): array => [],
103120 ],
@@ -111,25 +128,25 @@ protected function getQueryTypeServiceFieldConfig(): array
111128 */
112129 protected function getQueryTypeEntitiesFieldConfig (?array $ config ): array
113130 {
114- if (!$ this ->hasEntityTypes () ) {
131+ if (!$ this ->entityTypes ) {
115132 return [];
116133 }
117134
118135 $ entityType = new UnionType ([
119- 'name ' => self ::RESERVED_TYPE_ENTITY ,
136+ 'name ' => FederatedSchema ::RESERVED_TYPE_ENTITY ,
120137 'types ' => array_values ($ this ->getEntityTypes ()),
121138 ]);
122139
123140 $ anyType = new CustomScalarType ([
124- 'name ' => self ::RESERVED_TYPE_ANY ,
141+ 'name ' => FederatedSchema ::RESERVED_TYPE_ANY ,
125142 'serialize ' => static fn ($ value ) => $ value ,
126143 ]);
127144
128145 return [
129- self ::RESERVED_FIELD_ENTITIES => [
146+ FederatedSchema ::RESERVED_FIELD_ENTITIES => [
130147 'type ' => Type::listOf ($ entityType ),
131148 'args ' => [
132- self ::RESERVED_FIELD_REPRESENTATIONS => [
149+ FederatedSchema ::RESERVED_FIELD_REPRESENTATIONS => [
133150 'type ' => Type::nonNull (Type::listOf (Type::nonNull ($ anyType ))),
134151 ],
135152 ],
@@ -147,25 +164,24 @@ protected function getQueryTypeEntitiesFieldConfig(?array $config): array
147164 protected function resolve ($ root , $ args , $ context , $ info ): array
148165 {
149166 return array_map (static function ($ ref ) use ($ context , $ info ) {
150- Utils::invariant (isset ($ ref [self ::RESERVED_FIELD_TYPE_NAME ]), 'Type name must be provided in the reference. ' );
167+ Utils::invariant (isset ($ ref [FederatedSchema ::RESERVED_FIELD_TYPE_NAME ]), 'Type name must be provided in the reference. ' );
151168
152- $ typeName = $ ref [self ::RESERVED_FIELD_TYPE_NAME ];
169+ $ typeName = $ ref [FederatedSchema ::RESERVED_FIELD_TYPE_NAME ];
153170 $ type = $ info ->schema ->getType ($ typeName );
154171
155172 Utils::invariant (
156- $ type && $ type instanceof EntityObjectType,
157- sprintf (
158- 'The _entities resolver tried to load an entity for type "%s", but no object type of that name was found in the schema ' ,
159- $ type ->name
160- )
173+ $ type instanceof EntityObjectType,
174+ 'The _entities resolver tried to load an entity for type "%s", but no object type of that name was found in the schema ' ,
175+ $ type ->name
161176 );
162177
178+ /** @var EntityObjectType $type */
163179 if (!$ type ->hasReferenceResolver ()) {
164180 return $ ref ;
165181 }
166182
167183 return $ type ->resolveReference ($ ref , $ context , $ info );
168- }, $ args [self ::RESERVED_FIELD_REPRESENTATIONS ]);
184+ }, $ args [FederatedSchema ::RESERVED_FIELD_REPRESENTATIONS ]);
169185 }
170186
171187 /**
@@ -186,4 +202,30 @@ protected function extractEntityTypes(array $config): array
186202
187203 return $ entityTypes ;
188204 }
205+
206+ /**
207+ * @param array<string,mixed> $config
208+ *
209+ * @return SchemaExtensionType[]
210+ */
211+ protected function extractSchemaExtensionTypes (array $ config ): array
212+ {
213+ $ typeMap = [];
214+ $ configTypes = $ config ['types ' ] ?? [];
215+ if (\is_array ($ configTypes )) {
216+ $ typeMap = $ configTypes ;
217+ } elseif (\is_callable ($ configTypes )) {
218+ $ typeMap = $ configTypes ();
219+ }
220+
221+ $ types = [];
222+
223+ foreach ($ typeMap as $ type ) {
224+ if ($ type instanceof SchemaExtensionType) {
225+ $ types [$ type ->name ] = $ type ;
226+ }
227+ }
228+
229+ return $ types ;
230+ }
189231}
0 commit comments