Completed
Pull Request — master (#201)
by Christoffer
02:54
created

InputObjectType   A

Complexity

Total Complexity 6

Size/Duplication

Total Lines 105
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 105
rs 10
c 0
b 0
f 0
wmc 6

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 1
A setFields() 0 4 1
A getFields() 0 6 2
B buildFieldMap() 0 34 2
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\resolveThunk;
11
use function Digia\GraphQL\Util\invariant;
12
13
/**
14
 * Input Object Type Definition
15
 *
16
 * An input object defines a structured collection of fields which may be
17
 * supplied to a field argument.
18
 *
19
 * Using `NonNull` will ensure that a value must be provided by the query
20
 *
21
 * Example:
22
 *
23
 *     $GeoPoint = GraphQLInputObjectType([
24
 *       'name': 'GeoPoint',
25
 *       'fields': [
26
 *         'lat': ['type' => GraphQLNonNull(GraphQLFloat())],
27
 *         'lon': ['type' => GraphQLNonNull(GraphQLFloat())],
28
 *         'alt': ['type' => GraphQLFloat(), 'defaultValue' => 0],
29
 *       ]
30
 *     ]);
31
 */
32
class InputObjectType implements TypeInterface, NamedTypeInterface, InputTypeInterface, ASTNodeAwareInterface
33
{
34
    use NameTrait;
35
    use DescriptionTrait;
36
    use ASTNodeTrait;
37
38
    /**
39
     * Fields can be defined either as an array or as a thunk.
40
     * Using thunks allows for cross-referencing of fields.
41
     *
42
     * @var array|callable
43
     */
44
    protected $fieldsOrThunk;
45
46
    /**
47
     * A key-value map over field names and their corresponding field instances.
48
     *
49
     * @var null|InputField[]
50
     */
51
    protected $fieldMap;
52
53
    /**
54
     * InputObjectType constructor.
55
     *
56
     * @param string                             $name
57
     * @param null|string                        $description
58
     * @param array|callable                     $fieldsOrThunk
59
     * @param InputObjectTypeDefinitionNode|null $astNode
60
     * @throws InvariantException
61
     */
62
    public function __construct(
63
        string $name,
64
        ?string $description,
65
        $fieldsOrThunk,
66
        ?InputObjectTypeDefinitionNode $astNode
67
    ) {
68
        $this->name          = $name;
69
        $this->description   = $description;
70
        $this->fieldsOrThunk = $fieldsOrThunk;
71
        $this->astNode       = $astNode;
72
73
        invariant(null !== $this->getName(), 'Must provide name.');
74
    }
75
76
    /**
77
     * @return InputField[]
78
     * @throws InvariantException
79
     */
80
    public function getFields(): array
81
    {
82
        if (!isset($this->fieldMap)) {
83
            $this->fieldMap = $this->buildFieldMap($this->fieldsOrThunk);
84
        }
85
        return $this->fieldMap;
86
    }
87
88
    /**
89
     * @param array|callable $fieldsOrThunk
90
     * @return $this
91
     */
92
    protected function setFields($fieldsOrThunk)
93
    {
94
        $this->fieldsOrThunk = $fieldsOrThunk;
95
        return $this;
96
    }
97
98
    /**
99
     * @param array|callable $fieldsOrThunk
100
     * @return array
101
     * @throws InvariantException
102
     */
103
    protected function buildFieldMap($fieldsOrThunk): array
104
    {
105
        $fields = resolveThunk($fieldsOrThunk);
106
107
        invariant(
108
            isAssocArray($fields),
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 ($fields 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
            $fieldMap[$fieldName] = new InputField(
128
                $fieldName,
129
                $fieldConfig['type'] ?? null,
130
                $fieldConfig['defaultValue'] ?? null,
131
                $fieldConfig['description'] ?? null,
132
                $fieldConfig['astNode'] ?? null
133
            );
134
        }
135
136
        return $fieldMap;
137
    }
138
}
139