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

ObjectType::getIsTypeOfCallback()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
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\ObjectTypeDefinitionNode;
9
use Digia\GraphQL\Language\Node\ObjectTypeExtensionNode;
10
use Digia\GraphQL\Schema\Definition;
11
use GraphQL\Contracts\TypeSystem\Type\InterfaceTypeInterface;
12
use GraphQL\Contracts\TypeSystem\Type\ObjectTypeInterface;
13
use React\Promise\PromiseInterface;
14
use function Digia\GraphQL\Type\resolveThunk;
15
16
/**
17
 * Object Type Definition
18
 *
19
 * Almost all of the GraphQL types you define will be object types. Object types
20
 * have a name, but most importantly describe their fields.
21
 *
22
 * Example:
23
 *
24
 *     $AddressType = newObjectType([
25
 *       'name'   => 'Address',
26
 *       'fields' => [
27
 *         'street'    => ['type' => stringType()],
28
 *         'number'    => ['type' => intType()],
29
 *         'formatted' => [
30
 *           'type'    => stringType(),
31
 *           'resolve' => function ($obj) {
32
 *             return $obj->number . ' ' . $obj->street
33
 *           }
34
 *         ]
35
 *       ]
36
 *     ]);
37
 *
38
 * When two types need to refer to each other, or a type needs to refer to
39
 * itself in a field, you can use a function expression (aka a closure or a
40
 * thunk) to supply the fields lazily.
41
 *
42
 * Example:
43
 *
44
 *     $PersonType = newObjectType([
45
 *       'name' => 'Person',
46
 *       'fields' => function () {
47
 *         return [
48
 *           'name'       => ['type' => stringType()],
49
 *           'bestFriend' => ['type' => $PersonType],
50
 *         ];
51
 *       }
52
 *     ]);
53
 */
54
class ObjectType extends Definition implements ObjectTypeInterface, FieldsAwareInterface, ASTNodeAwareInterface
55
{
56
    use NameTrait;
57
    use DescriptionTrait;
58
    use FieldsTrait;
59
    use ResolveTrait;
60
    use ASTNodeTrait;
61
    use ExtensionASTNodesTrait;
62
63
    /**
64
     * @var callable
65
     */
66
    protected $isTypeOfCallback;
67
68
    /**
69
     * Interfaces can be defined either as an array or as a thunk.
70
     * Using thunks allows for cross-referencing of interfaces.
71
     *
72
     * @var array|callable
73
     */
74
    protected $interfacesOrThunk;
75
76
    /**
77
     * A list of interface instances.
78
     *
79
     * @var InterfaceType[]|null
80
     */
81
    protected $interfaces;
82
83
    /**
84
     * ObjectType constructor.
85
     *
86
     * @param string                        $name
87
     * @param null|string                   $description
88
     * @param array|callable                $fieldsOrThunk
89
     * @param array|callable                $interfacesOrThunk
90
     * @param callable|null                 $isTypeOfCallback
91
     * @param ObjectTypeDefinitionNode|null $astNode
92
     * @param ObjectTypeExtensionNode[]     $extensionASTNodes
93
     */
94
    public function __construct(
95
        string $name,
96
        ?string $description,
97
        $fieldsOrThunk,
98
        $interfacesOrThunk,
99
        ?callable $isTypeOfCallback,
100
        ?ObjectTypeDefinitionNode $astNode,
101
        array $extensionASTNodes
102
    ) {
103
        $this->name              = $name;
104
        $this->description       = $description;
105
        $this->rawFieldsOrThunk  = $fieldsOrThunk;
106
        $this->interfacesOrThunk = $interfacesOrThunk;
107
        $this->isTypeOfCallback  = $isTypeOfCallback;
108
        $this->astNode           = $astNode;
109
        $this->extensionAstNodes = $extensionASTNodes;
110
    }
111
112
    /**
113
     * @param mixed $value
114
     * @param mixed $context
115
     * @param mixed $info
116
     * @return bool|PromiseInterface
117
     */
118
    public function isTypeOf($value, $context, $info)
119
    {
120
        return null !== $this->isTypeOfCallback
121
            ? \call_user_func($this->isTypeOfCallback, $value, $context, $info)
122
            : false;
123
    }
124
125
    /**
126
     * @return bool
127
     * @throws InvariantException
128
     */
129
    public function hasInterfaces(): bool
130
    {
131
        return !empty($this->getInterfaces());
132
    }
133
134
    /**
135
     * @param string $name
136
     * @return InterfaceTypeInterface|null
137
     * @throws InvariantException
138
     */
139
    public function getInterface(string $name): ?InterfaceTypeInterface
140
    {
141
        return $this->getInterfaces()[$name] ?? null;
142
    }
143
144
    /**
145
     * @param string $name
146
     * @return bool
147
     * @throws InvariantException
148
     */
149
    public function hasInterface(string $name): bool
150
    {
151
        return $this->getInterface($name) !== null;
152
    }
153
154
    /**
155
     * @return InterfaceType[]
156
     * @throws InvariantException
157
     */
158
    public function getInterfaces(): array
159
    {
160
        if ($this->interfaces === null) {
161
            $this->interfaces = $this->buildInterfaces($this->interfacesOrThunk);
162
        }
163
        return $this->interfaces;
164
    }
165
166
    /**
167
     * @return bool
168
     */
169
    public function hasIsTypeOfCallback(): bool
170
    {
171
        return null !== $this->isTypeOfCallback;
172
    }
173
174
    /**
175
     * @return null|callable
176
     */
177
    public function getIsTypeOfCallback(): ?callable
178
    {
179
        return $this->isTypeOfCallback;
180
    }
181
182
    /**
183
     * @param array|callable $interfacesOrThunk
184
     * @return array
185
     * @throws InvariantException
186
     */
187
    protected function buildInterfaces($interfacesOrThunk): array
188
    {
189
        $interfaces = resolveThunk($interfacesOrThunk);
190
191
        if (!\is_array($interfaces)) {
192
            throw new InvariantException(
193
                \sprintf('%s interfaces must be an array or a function which returns an array.', $this->name)
194
            );
195
        }
196
197
        return $interfaces;
198
    }
199
}
200