Passed
Push — master ( e86c97...dfc587 )
by Christoffer
02:07
created

InputObjectType::getField()   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 1
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\InputObjectTypeDefinitionNode;
9
use function Digia\GraphQL\Type\isAssocArray;
10
use function Digia\GraphQL\Type\newInputField;
11
use function Digia\GraphQL\Type\resolveThunk;
12
use function Digia\GraphQL\Util\invariant;
13
14
/**
15
 * Input Object Type Definition
16
 *
17
 * An input object defines a structured collection of fields which may be
18
 * supplied to a field argument.
19
 *
20
 * Using `NonNull` will ensure that a value must be provided by the query
21
 *
22
 * Example:
23
 *
24
 *     $GeoPoint = newInputObjectType([
25
 *       'name': 'GeoPoint',
26
 *       'fields': [
27
 *         'lat': ['type' => newNonNull(Float())],
28
 *         'lon': ['type' => newNonNull(Float())],
29
 *         'alt': ['type' => Float(), 'defaultValue' => 0],
30
 *       ]
31
 *     ]);
32
 */
33
class InputObjectType implements TypeInterface, NamedTypeInterface, InputTypeInterface, ASTNodeAwareInterface
34
{
35
    use NameTrait;
36
    use DescriptionTrait;
37
    use ASTNodeTrait;
38
39
    /**
40
     * Fields can be defined either as an array or as a thunk.
41
     * Using thunks allows for cross-referencing of fields.
42
     *
43
     * @var array|callable
44
     */
45
    protected $rawFieldsOrThunk;
46
47
    /**
48
     * A key-value map over field names and their corresponding field instances.
49
     *
50
     * @var null|InputField[]
51
     */
52
    protected $fieldMap;
53
54
    /**
55
     * InputObjectType constructor.
56
     *
57
     * @param string                             $name
58
     * @param null|string                        $description
59
     * @param array|callable                     $rawFieldsOrThunk
60
     * @param InputObjectTypeDefinitionNode|null $astNode
61
     * @throws InvariantException
62
     */
63
    public function __construct(
64
        string $name,
65
        ?string $description,
66
        $rawFieldsOrThunk,
67
        ?InputObjectTypeDefinitionNode $astNode
68
    ) {
69
        $this->name             = $name;
70
        $this->description      = $description;
71
        $this->rawFieldsOrThunk = $rawFieldsOrThunk;
72
        $this->astNode          = $astNode;
73
    }
74
75
    /**
76
     * @param string $fieldName
77
     * @return InputField|null
78
     * @throws InvariantException
79
     */
80
    public function getField(string $fieldName): ?InputField
81
    {
82
        return $this->getFields()[$fieldName] ?? null;
83
    }
84
85
    /**
86
     * @return InputField[]
87
     * @throws InvariantException
88
     */
89
    public function getFields(): array
90
    {
91
        if (!isset($this->fieldMap)) {
92
            $this->fieldMap = $this->buildFieldMap($this->rawFieldsOrThunk);
93
        }
94
95
        return $this->fieldMap;
96
    }
97
98
    /**
99
     * @param array|callable $rawFieldsOrThunk
100
     * @return array
101
     * @throws InvariantException
102
     */
103
    protected function buildFieldMap($rawFieldsOrThunk): array
104
    {
105
        $rawFields = resolveThunk($rawFieldsOrThunk);
106
107
        invariant(
108
            isAssocArray($rawFields),
109
            \sprintf(
110
                '%s fields must be an associative array with field names as keys or a function which returns such an array.',
111
                $this->name
112
            )
113
        );
114
115
        $fieldMap = [];
116
117
        foreach ($rawFields as $fieldName => $fieldConfig) {
118
            invariant(
119
                !isset($fieldConfig['resolve']),
120
                \sprintf(
121
                    '%s.%s field type has a resolve property, but Input Types cannot define resolvers.',
122
                    $this->name,
123
                    $fieldName
124
                )
125
            );
126
127
            $fieldConfig['name'] = $fieldName;
128
129
            $fieldMap[$fieldName] = newInputField($fieldConfig);
130
        }
131
132
        return $fieldMap;
133
    }
134
}
135