1818 * name?: string|null,
1919 * description?: string|null,
2020 * fields: iterable<FieldConfig>|callable(): iterable<FieldConfig>,
21+ * isOneOf?: bool|null,
2122 * parseValue?: callable(array<string, mixed>): mixed,
2223 * astNode?: InputObjectTypeDefinitionNode|null,
2324 * extensionASTNodes?: array<InputObjectTypeExtensionNode>|null
@@ -35,6 +36,8 @@ class InputObjectType extends Type implements InputType, NullableType, NamedType
3536 /** @phpstan-var InputObjectConfig */
3637 public array $ config ;
3738
39+ public bool $ isOneOf ;
40+
3841 /**
3942 * Lazily initialized.
4043 *
@@ -55,6 +58,7 @@ public function __construct(array $config)
5558 $ this ->description = $ config ['description ' ] ?? null ;
5659 $ this ->astNode = $ config ['astNode ' ] ?? null ;
5760 $ this ->extensionASTNodes = $ config ['extensionASTNodes ' ] ?? [];
61+ $ this ->isOneOf = $ config ['isOneOf ' ] ?? false ;
5862
5963 $ this ->config = $ config ;
6064 }
@@ -91,6 +95,12 @@ public function hasField(string $name): bool
9195 return isset ($ this ->fields [$ name ]);
9296 }
9397
98+ /** Returns true if this is a oneOf input object type. */
99+ public function isOneOf (): bool
100+ {
101+ return $ this ->isOneOf ;
102+ }
103+
94104 /**
95105 * @throws InvariantViolation
96106 *
@@ -196,6 +206,44 @@ public function assertValid(): void
196206 foreach ($ resolvedFields as $ field ) {
197207 $ field ->assertValid ($ this );
198208 }
209+
210+ // Additional validation for oneOf input objects
211+ if ($ this ->isOneOf ()) {
212+ $ this ->validateOneOfConstraints ($ resolvedFields );
213+ }
214+ }
215+
216+ /**
217+ * Validates that oneOf input object constraints are met.
218+ *
219+ * @param array<string, InputObjectField> $fields
220+ *
221+ * @throws InvariantViolation
222+ */
223+ private function validateOneOfConstraints (array $ fields ): void
224+ {
225+ if (count ($ fields ) === 0 ) {
226+ throw new InvariantViolation ("OneOf input object type {$ this ->name } must define one or more fields. " );
227+ }
228+
229+ foreach ($ fields as $ fieldName => $ field ) {
230+ $ fieldType = $ field ->getType ();
231+
232+ // OneOf fields must be nullable (not wrapped in NonNull)
233+ if ($ fieldType instanceof NonNull) {
234+ throw new InvariantViolation ("OneOf input object type {$ this ->name } field {$ fieldName } must be nullable. " );
235+ }
236+
237+ // OneOf fields cannot have default values
238+ if ($ field ->defaultValueExists ()) {
239+ throw new InvariantViolation ("OneOf input object type {$ this ->name } field {$ fieldName } cannot have a default value. " );
240+ }
241+
242+ // OneOf fields cannot be deprecated (optional constraint for now)
243+ if ($ field ->isDeprecated ()) {
244+ throw new InvariantViolation ("OneOf input object type {$ this ->name } field {$ fieldName } cannot be deprecated. " );
245+ }
246+ }
199247 }
200248
201249 public function astNode (): ?InputObjectTypeDefinitionNode
0 commit comments