Passed
Pull Request — master (#351)
by Kirill
02:29
created

UnionType::buildTypeMap()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 1
dl 0
loc 12
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Digia\GraphQL\Type\Definition;
4
5
use Digia\GraphQL\Error\InvariantException;
6
use Digia\GraphQL\Language\Node\ASTNodeAwareInterface;
7
use Digia\GraphQL\Language\Node\ASTNodeTrait;
8
use Digia\GraphQL\Language\Node\UnionTypeDefinitionNode;
9
use Digia\GraphQL\Schema\Definition;
10
use GraphQL\Contracts\TypeSystem\Type\NamedTypeInterface;
11
use GraphQL\Contracts\TypeSystem\Type\ObjectTypeInterface;
12
use GraphQL\Contracts\TypeSystem\Type\TypeInterface;
13
use GraphQL\Contracts\TypeSystem\Type\UnionTypeInterface;
14
use function Digia\GraphQL\Type\resolveThunk;
15
16
/**
17
 * Union Type Definition
18
 *
19
 * When a field can return one of a heterogeneous set of types, a Union type
20
 * is used to describe what types are possible as well as providing a function
21
 * to determine which type is actually used when the field is resolved.
22
 *
23
 * Example:
24
 *
25
 *     $PetType = newUnionType([
26
 *       'name' => 'Pet',
27
 *       'types' => [$DogType, $CatType],
28
 *       'resolveType' => function ($value) {
29
 *         if ($value instanceof Dog) {
30
 *           return $DogType;
31
 *         }
32
 *         if ($value instanceof Cat) {
33
 *           return $CatType;
34
 *         }
35
 *       }
36
 *     ]);
37
 */
38
class UnionType extends Definition implements UnionTypeInterface, AbstractTypeInterface, ASTNodeAwareInterface
39
{
40
    use NameTrait;
41
    use DescriptionTrait;
42
    use ResolveTypeTrait;
43
    use ASTNodeTrait;
44
45
    /**
46
     * Types can be defined either as an array or as a thunk.
47
     * Using thunks allows for cross-referencing of types.
48
     *
49
     * @var array|callable
50
     */
51
    protected $typesOrThunk;
52
53
    /**
54
     * A key-value map over type names and their corresponding type instances.
55
     *
56
     * @var TypeInterface[]
57
     */
58
    protected $typeMap;
59
60
    /**
61
     * UnionType constructor.
62
     *
63
     * @param string                       $name
64
     * @param null|string                  $description
65
     * @param array|callable               $typesOrThunk
66
     * @param callable|null                $resolveTypeCallback
67
     * @param UnionTypeDefinitionNode|null $astNode
68
     */
69
    public function __construct(
70
        string $name,
71
        ?string $description,
72
        $typesOrThunk,
73
        ?callable $resolveTypeCallback,
74
        ?UnionTypeDefinitionNode $astNode
75
    ) {
76
        $this->name                = $name;
77
        $this->description         = $description;
78
        $this->typesOrThunk        = $typesOrThunk;
79
        $this->resolveTypeCallback = $resolveTypeCallback;
80
        $this->astNode             = $astNode;
81
    }
82
83
    /**
84
     * @return ObjectTypeInterface[]
85
     * @throws InvariantException
86
     */
87
    public function getTypes(): array
88
    {
89
        // Types are built lazily to avoid concurrency issues.
90
        if (!isset($this->typeMap)) {
91
            $this->typeMap = $this->buildTypeMap($this->typesOrThunk);
92
        }
93
94
        return $this->typeMap;
95
    }
96
97
    /**
98
     * @param string $name
99
     * @return ObjectTypeInterface|null
100
     * @throws InvariantException
101
     */
102
    public function getType(string $name): ?ObjectTypeInterface
103
    {
104
        return $this->getTypes()[$name] ?? null;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getTypes()[$name] ?? null could return the type GraphQL\Contracts\TypeSystem\Type\TypeInterface which includes types incompatible with the type-hinted return GraphQL\Contracts\TypeSy...bjectTypeInterface|null. Consider adding an additional type-check to rule them out.
Loading history...
105
    }
106
107
    /**
108
     * @param string $name
109
     * @return bool
110
     * @throws InvariantException
111
     */
112
    public function hasType(string $name): bool
113
    {
114
        return $this->getType($name) !== null;
115
    }
116
117
    /**
118
     * @param array|callable $typesOrThunk
119
     * @return array
120
     * @throws InvariantException
121
     */
122
    protected function buildTypeMap($typesOrThunk): array
123
    {
124
        $typeMap = resolveThunk($typesOrThunk);
125
126
        if (!\is_array($typeMap)) {
127
            throw new InvariantException(\sprintf(
128
                'Must provide array of types or a function which returns such an array for Union %s.',
129
                $this->name
130
            ));
131
        }
132
133
        return $typeMap;
134
    }
135
}
136