Completed
Pull Request — master (#103)
by Christoffer
02:14
created

PossibleFragmentSpreadsRule   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 75
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 13
dl 0
loc 75
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A getFragmentType() 0 11 3
A __construct() 0 3 1
D enterNode() 0 38 9
1
<?php
2
3
namespace Digia\GraphQL\Validation\Rule;
4
5
use Digia\GraphQL\Error\InvalidTypeException;
6
use Digia\GraphQL\Error\ValidationException;
7
use Digia\GraphQL\Language\Node\FragmentSpreadNode;
8
use Digia\GraphQL\Language\Node\InlineFragmentNode;
9
use Digia\GraphQL\Language\Node\NodeInterface;
10
use Digia\GraphQL\Type\Definition\CompositeTypeInterface;
11
use Digia\GraphQL\Type\Definition\TypeInterface;
12
use Digia\GraphQL\Util\TypeComparator;
13
use function Digia\GraphQL\Util\typeFromAST;
14
use function Digia\GraphQL\Validation\typeIncompatibleAnonymousSpreadMessage;
15
use function Digia\GraphQL\Validation\typeIncompatibleSpreadMessage;
16
17
/**
18
 * Possible fragment spread
19
 *
20
 * A fragment spread is only valid if the type condition could ever possibly
21
 * be true: if there is a non-empty intersection of the possible parent types,
22
 * and possible types which pass the type condition.
23
 */
24
class PossibleFragmentSpreadsRule extends AbstractRule
25
{
26
    /**
27
     * @var TypeComparator
28
     */
29
    protected $typeComparator;
30
31
    /**
32
     * PossibleFragmentSpreadsRule constructor.
33
     */
34
    public function __construct()
35
    {
36
        $this->typeComparator = new TypeComparator();
37
    }
38
39
40
    /**
41
     * @inheritdoc
42
     */
43
    public function enterNode(NodeInterface $node): ?NodeInterface
44
    {
45
        if ($node instanceof InlineFragmentNode) {
46
            $fragmentType = $this->validationContext->getType();
47
            $parentType   = $this->validationContext->getParentType();
48
49
            if ($fragmentType instanceof CompositeTypeInterface &&
50
                $parentType instanceof CompositeTypeInterface &&
51
                !$this->typeComparator->doTypesOverlap($this->validationContext->getSchema(),
52
                    $fragmentType, $parentType)) {
53
                $this->validationContext->reportError(
54
                    new ValidationException(
55
                        typeIncompatibleAnonymousSpreadMessage($parentType, $fragmentType),
0 ignored issues
show
Bug introduced by
$fragmentType of type Digia\GraphQL\Type\Defin...\CompositeTypeInterface is incompatible with the type string expected by parameter $fragmentType of Digia\GraphQL\Validation...nonymousSpreadMessage(). ( Ignorable by Annotation )

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

55
                        typeIncompatibleAnonymousSpreadMessage($parentType, /** @scrutinizer ignore-type */ $fragmentType),
Loading history...
Bug introduced by
$parentType of type Digia\GraphQL\Type\Defin...\CompositeTypeInterface is incompatible with the type string expected by parameter $parentType of Digia\GraphQL\Validation...nonymousSpreadMessage(). ( Ignorable by Annotation )

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

55
                        typeIncompatibleAnonymousSpreadMessage(/** @scrutinizer ignore-type */ $parentType, $fragmentType),
Loading history...
56
                        [$node]
57
                    )
58
                );
59
            }
60
        }
61
62
        if ($node instanceof FragmentSpreadNode) {
63
            $fragmentName = $node->getNameValue();
64
            $fragmentType = $this->getFragmentType($fragmentName);
65
            $parentType   = $this->validationContext->getParentType();
66
67
            if (null !== $fragmentType &&
68
                null !== $parentType &&
69
                !$this->typeComparator->doTypesOverlap($this->validationContext->getSchema(),
70
                    $fragmentType, $parentType)) {
71
                $this->validationContext->reportError(
72
                    new ValidationException(
73
                        typeIncompatibleSpreadMessage($fragmentName, $parentType, $fragmentType),
0 ignored issues
show
Bug introduced by
$fragmentType of type Digia\GraphQL\Type\Definition\TypeInterface is incompatible with the type string expected by parameter $fragmentType of Digia\GraphQL\Validation...mpatibleSpreadMessage(). ( Ignorable by Annotation )

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

73
                        typeIncompatibleSpreadMessage($fragmentName, $parentType, /** @scrutinizer ignore-type */ $fragmentType),
Loading history...
Bug introduced by
$parentType of type Digia\GraphQL\Type\Definition\TypeInterface is incompatible with the type string expected by parameter $parentType of Digia\GraphQL\Validation...mpatibleSpreadMessage(). ( Ignorable by Annotation )

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

73
                        typeIncompatibleSpreadMessage($fragmentName, /** @scrutinizer ignore-type */ $parentType, $fragmentType),
Loading history...
74
                        [$node]
75
                    )
76
                );
77
            }
78
        }
79
80
        return $node;
81
    }
82
83
    /**
84
     * @param string $name
85
     * @return TypeInterface|null
86
     * @throws InvalidTypeException
87
     */
88
    protected function getFragmentType(string $name): ?TypeInterface
89
    {
90
        $fragment = $this->validationContext->getFragment($name);
91
92
        if (null === $fragment) {
93
            return null;
94
        }
95
96
        $type = typeFromAST($this->validationContext->getSchema(), $fragment->getTypeCondition());
97
98
        return $type instanceof CompositeTypeInterface ? $type : null;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $type instanceof ...nterface ? $type : null could return the type Digia\GraphQL\Type\Defin...\CompositeTypeInterface which is incompatible with the type-hinted return null|Digia\GraphQL\Type\Definition\TypeInterface. Consider adding an additional type-check to rule them out.
Loading history...
99
    }
100
}
101