Passed
Pull Request — master (#256)
by Sam
02:41
created

EnumType::parseValue()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 5
nc 3
nop 1
dl 0
loc 11
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\EnumTypeDefinitionNode;
9
use Digia\GraphQL\Language\Node\EnumValueNode;
10
use Digia\GraphQL\Language\Node\NodeInterface;
11
use function Digia\GraphQL\Type\isAssocArray;
12
use function Digia\GraphQL\Type\newEnumValue;
13
use function Digia\GraphQL\Util\toString;
14
15
/**
16
 * Enum Type Definition
17
 *
18
 * Some leaf values of requests and input values are Enums. GraphQL serializes
19
 * Enum values as strings, however internally Enums can be represented by any
20
 * kind of type, often integers.
21
 *
22
 * Example:
23
 *
24
 *     $RGBType = newEnumType([
25
 *       'name'   => 'RGB',
26
 *       'values' => [
27
 *         'RED'   => ['value' => 0],
28
 *         'GREEN' => ['value' => 1],
29
 *         'BLUE'  => ['value' => 2]
30
 *       ]
31
 *     ]);
32
 *
33
 * Note: If a value is not provided in a definition, the name of the enum value
34
 * will be used as its internal value.
35
 */
36
class EnumType implements NamedTypeInterface, InputTypeInterface, LeafTypeInterface,
37
    OutputTypeInterface, SerializableTypeInterface, DescriptionAwareInterface, ASTNodeAwareInterface
38
{
39
    use NameTrait;
40
    use DescriptionTrait;
41
    use ASTNodeTrait;
42
43
    /**
44
     * @var array
45
     */
46
    protected $rawValues;
47
48
    /**
49
     * A list of enum value instances.
50
     *
51
     * @var EnumValue[]
52
     */
53
    protected $values;
54
55
    /**
56
     * EnumType constructor.
57
     *
58
     * @param string                      $name
59
     * @param null|string                 $description
60
     * @param EnumValue[]                 $rawValues
61
     * @param EnumTypeDefinitionNode|null $astNode
62
     */
63
    public function __construct(string $name, ?string $description, array $rawValues, ?EnumTypeDefinitionNode $astNode)
64
    {
65
        $this->name        = $name;
66
        $this->description = $description;
67
        $this->astNode     = $astNode;
68
        $this->rawValues   = $rawValues;
69
    }
70
71
    /**
72
     * @param mixed $value
73
     * @return null|string
74
     * @throws InvariantException
75
     */
76
    public function serialize($value)
77
    {
78
        $enumValue = $this->getValueByValue($value);
79
80
        if ($enumValue) {
81
            return $enumValue->getName();
82
        }
83
84
        return null;
85
    }
86
87
    /**
88
     * @param mixed $value
89
     * @return mixed|null
90
     * @throws InvariantException
91
     */
92
    public function parseValue($value)
93
    {
94
        if (\is_string($value)) {
95
            $enumValue = $this->getValueByName($value);
96
97
            if ($enumValue !== null) {
98
                return $enumValue->getValue();
99
            }
100
        }
101
102
        return null;
103
    }
104
105
    /**
106
     * @param NodeInterface $node
107
     * @return mixed|null
108
     * @throws InvariantException
109
     */
110
    public function parseLiteral(NodeInterface $node)
111
    {
112
        if ($node instanceof EnumValueNode) {
113
            $enumValue = $this->getValueByName($node->getValue());
114
115
            if ($enumValue !== null) {
116
                return $enumValue->getValue();
117
            }
118
        }
119
120
        return null;
121
    }
122
123
    /**
124
     * @param string $name
125
     * @return EnumValue|null
126
     * @throws InvariantException
127
     */
128
    public function getValue(string $name): ?EnumValue
129
    {
130
        return $this->getValueByName($name);
131
    }
132
133
    /**
134
     * @return EnumValue[]
135
     * @throws InvariantException
136
     */
137
    public function getValues(): array
138
    {
139
        if (!isset($this->values)) {
140
            $this->values = $this->buildValues($this->rawValues);
141
        }
142
        return $this->values;
143
    }
144
145
    /**
146
     * @param string $name
147
     * @return EnumValue|null
148
     * @throws InvariantException
149
     */
150
    protected function getValueByName(string $name): ?EnumValue
151
    {
152
        foreach ($this->getValues() as $enumValue) {
153
            if ($enumValue->getName() === $name) {
154
                return $enumValue;
155
            }
156
        }
157
158
        return null;
159
    }
160
161
    /**
162
     * @param mixed $value
163
     * @return EnumValue|null
164
     * @throws InvariantException
165
     */
166
    protected function getValueByValue($value): ?EnumValue
167
    {
168
        foreach ($this->getValues() as $enumValue) {
169
            if ($enumValue->getValue() === $value) {
170
                return $enumValue;
171
            }
172
        }
173
174
        return null;
175
    }
176
177
    /**
178
     * @param array $rawValues
179
     * @return array
180
     * @throws InvariantException
181
     */
182
    protected function buildValues(array $rawValues): array
183
    {
184
        if (!isAssocArray($rawValues)) {
185
            throw new InvariantException(\sprintf('%s values must be an associative array with value names as keys.',
186
                $this->name));
187
        }
188
189
        $values = [];
190
191
        foreach ($rawValues as $valueName => $valueConfig) {
192
            if (!isAssocArray($valueConfig)) {
193
                throw new InvariantException(\sprintf(
194
                    '%s.%s must refer to an object with a "value" key representing an internal value but got: %s.',
195
                    $this->name,
196
                    $valueName,
197
                    toString($valueConfig)
198
                ));
199
            }
200
201
            if (isset($valueConfig['isDeprecated'])) {
202
                throw new InvariantException(\sprintf(
203
                    '%s.%s should provide "deprecationReason" instead of "isDeprecated".',
204
                    $this->name,
205
                    $valueName
206
                ));
207
            }
208
209
            $valueConfig['name']  = $valueName;
210
            $valueConfig['value'] = \array_key_exists('value', $valueConfig)
211
                ? $valueConfig['value']
212
                : $valueName;
213
214
            $values[] = newEnumValue($valueConfig);
215
        }
216
217
        return $values;
218
    }
219
}
220