Passed
Push — master ( 41f82c...2e19c8 )
by Christoffer
02:41
created

FieldsTrait::buildFieldMap()   B

Complexity

Conditions 4
Paths 3

Size

Total Lines 48
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 29
nc 3
nop 1
dl 0
loc 48
rs 8.7396
c 0
b 0
f 0
1
<?php
2
3
namespace Digia\GraphQL\Type\Definition;
4
5
use Digia\GraphQL\Error\InvariantException;
6
use function Digia\GraphQL\Type\isAssocArray;
7
use function Digia\GraphQL\Type\newField;
8
use function Digia\GraphQL\Type\resolveThunk;
9
use function Digia\GraphQL\Util\invariant;
10
use function Digia\GraphQL\Util\toString;
11
12
trait FieldsTrait
13
{
14
    /**
15
     * Fields can be defined either as an array or as a thunk.
16
     * Using thunks allows for cross-referencing of fields.
17
     *
18
     * @var array|callable
19
     */
20
    protected $rawFieldsOrThunk;
21
22
    /**
23
     * A key-value map over field names and their corresponding field instances.
24
     *
25
     * @var Field[]
26
     */
27
    protected $fieldMap;
28
29
    /**
30
     * @return null|string
31
     */
32
    abstract public function getName(): ?string;
33
34
    /**
35
     * @param string $fieldName
36
     * @return Field|null
37
     * @throws InvariantException
38
     */
39
    public function getField(string $fieldName): ?Field
40
    {
41
        return $this->getFields()[$fieldName] ?? null;
42
    }
43
44
    /**
45
     * @return Field[]
46
     * @throws InvariantException
47
     */
48
    public function getFields(): array
49
    {
50
        // Fields are built lazily to avoid concurrency issues.
51
        if (!isset($this->fieldMap)) {
52
            $this->fieldMap = $this->buildFieldMap($this->rawFieldsOrThunk);
53
        }
54
55
        return $this->fieldMap;
56
    }
57
58
    /**
59
     * @param array|callable $rawFieldsOrThunk
60
     * @return Field[]
61
     * @throws InvariantException
62
     */
63
    protected function buildFieldMap($rawFieldsOrThunk): array
64
    {
65
        $rawFields = resolveThunk($rawFieldsOrThunk);
66
67
        invariant(
68
            isAssocArray($rawFields),
69
            \sprintf(
70
                '%s fields must be an associative array with field names as key or a callable which returns such an array.',
71
                $this->getName()
72
            )
73
        );
74
75
        $fieldMap = [];
76
77
        foreach ($rawFields as $fieldName => $fieldConfig) {
78
            invariant(
79
                \is_array($fieldConfig),
80
                \sprintf('%s.%s field config must be an array', $this->getName(), $fieldName)
81
            );
82
83
            invariant(
84
                !isset($fieldConfig['isDeprecated']),
85
                \sprintf(
86
                    '%s.%s should provide "deprecationReason" instead of "isDeprecated".',
87
                    $this->getName(),
88
                    $fieldName
89
                )
90
            );
91
92
            if (isset($fieldConfig['resolve'])) {
93
                invariant(
94
                    null === $fieldConfig['resolve'] || \is_callable($fieldConfig['resolve']),
95
                    \sprintf(
96
                        '%s.%s field resolver must be a function if provided, but got: %s',
97
                        $this->getName(),
98
                        $fieldName,
99
                        toString($fieldConfig['resolve'])
100
                    )
101
                );
102
            }
103
104
            $fieldConfig['name']     = $fieldName;
105
            $fieldConfig['typeName'] = $this->getName();
106
107
            $fieldMap[$fieldName] = newField($fieldConfig);
108
        }
109
110
        return $fieldMap;
111
    }
112
}
113