Skip to content

Commit d525145

Browse files
committed
Validate interface implemented ancestors
Part of the work done to implement interfaces implementing interfaces. This was caught by test and improves on the previously done changes for the SchemaValidationContext by implementing `validateTypeImplementsAncestors` which was missing.
1 parent 951d882 commit d525145

File tree

1 file changed

+38
-6
lines changed

1 file changed

+38
-6
lines changed

src/Type/SchemaValidationContext.php

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ public function validateTypes() : void
307307
$this->validateFields($type);
308308

309309
// Ensure objects implement the interfaces they claim to.
310-
$this->validateTypeInterfaces($type);
310+
$this->validateInterfaces($type);
311311

312312
// Ensure directives are valid
313313
$this->validateDirectivesAtLocation(
@@ -319,7 +319,7 @@ public function validateTypes() : void
319319
$this->validateFields($type);
320320

321321
// Ensure interfaces implement the interfaces they claim to.
322-
$this->validateTypeInterfaces($type);
322+
$this->validateInterfaces($type);
323323

324324
// Ensure directives are valid
325325
$this->validateDirectivesAtLocation(
@@ -661,9 +661,9 @@ private function getFieldArgNode($type, $fieldName, $argName)
661661
/**
662662
* @param ObjectType|InterfaceType $type
663663
*/
664-
private function validateTypeInterfaces(ImplementingType $type)
664+
private function validateInterfaces(ImplementingType $type)
665665
{
666-
$implementedTypeNames = [];
666+
$ifaceTypeNames = [];
667667
foreach ($type->getInterfaces() as $iface) {
668668
if (! $iface instanceof InterfaceType) {
669669
$this->reportError(
@@ -676,14 +676,16 @@ private function validateTypeInterfaces(ImplementingType $type)
676676
);
677677
continue;
678678
}
679-
if (isset($implementedTypeNames[$iface->name])) {
679+
if (isset($ifaceTypeNames[$iface->name])) {
680680
$this->reportError(
681681
sprintf('Type %s can only implement %s once.', $type->name, $iface->name),
682682
$this->getAllImplementsInterfaceNodes($type, $iface)
683683
);
684684
continue;
685685
}
686-
$implementedTypeNames[$iface->name] = true;
686+
$ifaceTypeNames[$iface->name] = true;
687+
688+
$this->validateTypeImplementsAncestors($type, $iface);
687689
$this->validateTypeImplementsInterface($type, $iface);
688690
}
689691
}
@@ -877,6 +879,36 @@ private function validateTypeImplementsInterface($type, $iface)
877879
}
878880
}
879881

882+
/**
883+
* @param ObjectType|InterfaceType $type
884+
* @param InterfaceType $iface
885+
*/
886+
private function validateTypeImplementsAncestors(ImplementingType $type, $iface) {
887+
$typeInterfaces = $type->getInterfaces();
888+
foreach ($iface->getInterfaces() as $transitive) {
889+
if (!in_array($transitive, $typeInterfaces)) {
890+
$this->reportError(
891+
$transitive === $type ?
892+
sprintf(
893+
"Type %s cannot implement %s because it would create a circular reference.",
894+
$type->name,
895+
$iface->name
896+
) :
897+
sprintf(
898+
"Type %s must implement %s because it is implemented by %s.",
899+
$type->name,
900+
$transitive->name,
901+
$iface->name
902+
),
903+
array_merge(
904+
$this->getAllImplementsInterfaceNodes($iface, $transitive),
905+
$this->getAllImplementsInterfaceNodes($type, $iface)
906+
)
907+
);
908+
}
909+
}
910+
}
911+
880912
private function validateUnionMembers(UnionType $union)
881913
{
882914
$memberTypes = $union->getTypes();

0 commit comments

Comments
 (0)