TypeComparators::isEqualType()   A
last analyzed

Complexity

Conditions 6
Paths 4

Size

Total Lines 19
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 6.5625

Importance

Changes 0
Metric Value
eloc 7
dl 0
loc 19
c 0
b 0
f 0
rs 9.2222
ccs 6
cts 8
cp 0.75
cc 6
nc 4
nop 2
crap 6.5625
1
<?php
2
3
declare(strict_types=1);
4
5
namespace GraphQL\Utils;
6
7
use GraphQL\Type\Definition\AbstractType;
8
use GraphQL\Type\Definition\CompositeType;
9
use GraphQL\Type\Definition\ListOfType;
10
use GraphQL\Type\Definition\NonNull;
11
use GraphQL\Type\Definition\ObjectType;
12
use GraphQL\Type\Definition\Type;
13
use GraphQL\Type\Schema;
14
15
class TypeComparators
16
{
17
    /**
18
     * Provided two types, return true if the types are equal (invariant).
19
     *
20
     * @return bool
21
     */
22 7
    public static function isEqualType(Type $typeA, Type $typeB)
23
    {
24
        // Equivalent types are equal.
25 7
        if ($typeA === $typeB) {
26 5
            return true;
27
        }
28
29
        // If either type is non-null, the other must also be non-null.
30 2
        if ($typeA instanceof NonNull && $typeB instanceof NonNull) {
31
            return self::isEqualType($typeA->getWrappedType(), $typeB->getWrappedType());
32
        }
33
34
        // If either type is a list, the other must also be a list.
35 2
        if ($typeA instanceof ListOfType && $typeB instanceof ListOfType) {
36
            return self::isEqualType($typeA->getWrappedType(), $typeB->getWrappedType());
37
        }
38
39
        // Otherwise the types are not equal.
40 2
        return false;
41
    }
42
43
    /**
44
     * Provided a type and a super type, return true if the first type is either
45
     * equal or a subset of the second super type (covariant).
46
     *
47
     * @return bool
48
     */
49 63
    public static function isTypeSubTypeOf(Schema $schema, Type $maybeSubType, Type $superType)
50
    {
51
        // Equivalent type is a valid subtype
52 63
        if ($maybeSubType === $superType) {
53 50
            return true;
54
        }
55
56
        // If superType is non-null, maybeSubType must also be nullable.
57 32
        if ($superType instanceof NonNull) {
58 10
            if ($maybeSubType instanceof NonNull) {
59 8
                return self::isTypeSubTypeOf($schema, $maybeSubType->getWrappedType(), $superType->getWrappedType());
60
            }
61
62 2
            return false;
63
        }
64
65 24
        if ($maybeSubType instanceof NonNull) {
66
            // If superType is nullable, maybeSubType may be non-null.
67 11
            return self::isTypeSubTypeOf($schema, $maybeSubType->getWrappedType(), $superType);
68
        }
69
70
        // If superType type is a list, maybeSubType type must also be a list.
71 16
        if ($superType instanceof ListOfType) {
72 6
            if ($maybeSubType instanceof ListOfType) {
73 4
                return self::isTypeSubTypeOf($schema, $maybeSubType->getWrappedType(), $superType->getWrappedType());
74
            }
75
76 2
            return false;
77
        }
78
79 10
        if ($maybeSubType instanceof ListOfType) {
80
            // If superType is not a list, maybeSubType must also be not a list.
81 1
            return false;
82
        }
83
84
        // If superType type is an abstract type, maybeSubType type may be a currently
85
        // possible object type.
86 9
        return Type::isAbstractType($superType) &&
87 9
            $maybeSubType instanceof ObjectType &&
88 2
            $schema->isPossibleType(
89 2
                $superType,
0 ignored issues
show
Bug introduced by
$superType of type GraphQL\Type\Definition\Type is incompatible with the type GraphQL\Type\Definition\AbstractType expected by parameter $abstractType of GraphQL\Type\Schema::isPossibleType(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

89
                /** @scrutinizer ignore-type */ $superType,
Loading history...
90 9
                $maybeSubType
91
            );
92
    }
93
94
    /**
95
     * Provided two composite types, determine if they "overlap". Two composite
96
     * types overlap when the Sets of possible concrete types for each intersect.
97
     *
98
     * This is often used to determine if a fragment of a given type could possibly
99
     * be visited in a context of another type.
100
     *
101
     * This function is commutative.
102
     *
103
     * @return bool
104
     */
105
    public static function doTypesOverlap(Schema $schema, CompositeType $typeA, CompositeType $typeB)
106
    {
107
        // Equivalent types overlap
108
        if ($typeA === $typeB) {
109
            return true;
110
        }
111
112
        if ($typeA instanceof AbstractType) {
113
            if ($typeB instanceof AbstractType) {
114
                // If both types are abstract, then determine if there is any intersection
115
                // between possible concrete types of each.
116
                foreach ($schema->getPossibleTypes($typeA) as $type) {
117
                    if ($schema->isPossibleType($typeB, $type)) {
118
                        return true;
119
                    }
120
                }
121
122
                return false;
123
            }
124
125
            // Determine if the latter type is a possible concrete type of the former.
126
            return $schema->isPossibleType($typeA, $typeB);
127
        }
128
129
        if ($typeB instanceof AbstractType) {
130
            // Determine if the former type is a possible concrete type of the latter.
131
            return $schema->isPossibleType($typeB, $typeA);
132
        }
133
134
        // Otherwise the types do not overlap.
135
        return false;
136
    }
137
}
138