Passed
Pull Request — master (#29)
by Christoffer
02:26
created

coerceBoolean()   A

Complexity

Conditions 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
c 0
b 0
f 0
dl 0
loc 7
rs 9.4285
1
<?php
2
3
namespace Digia\GraphQL\Provider;
4
5
use Digia\GraphQL\GraphQL;
6
use Digia\GraphQL\Language\AST\Node\BooleanValueNode;
7
use Digia\GraphQL\Language\AST\Node\FloatValueNode;
8
use Digia\GraphQL\Language\AST\Node\IntValueNode;
9
use Digia\GraphQL\Language\AST\Node\NodeInterface;
10
use Digia\GraphQL\Language\AST\Node\StringValueNode;
11
use Digia\GraphQL\Language\AST\NodeKindEnum;
12
use Digia\GraphQL\Type\Definition\TypeNameEnum;
13
use const Digia\GraphQL\Type\MAX_INT;
0 ignored issues
show
Bug introduced by
The constant Digia\GraphQL\Type\MAX_INT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
14
use const Digia\GraphQL\Type\MIN_INT;
0 ignored issues
show
Bug introduced by
The constant Digia\GraphQL\Type\MIN_INT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
15
use League\Container\ServiceProvider\AbstractServiceProvider;
16
use function Digia\GraphQL\Type\GraphQLScalarType;
17
18
class ScalarTypesProvider extends AbstractServiceProvider
19
{
20
21
    /**
22
     * @var array
23
     */
24
    protected $provides = [
25
        GraphQL::BOOLEAN,
26
        GraphQL::FLOAT,
27
        GraphQL::INT,
28
        GraphQL::ID,
29
        GraphQL::STRING,
30
    ];
31
32
    /**
33
     * @inheritdoc
34
     */
35
    public function register()
36
    {
37
        /**
38
         * @param $value
39
         * @return bool
40
         * @throws \TypeError
41
         */
42
        function coerceBoolean($value): bool
43
        {
44
            if (!is_scalar($value)) {
45
                throw new \TypeError(sprintf('Boolean cannot represent a non-scalar value: %s', $value));
46
            }
47
48
            return (bool)$value;
49
        }
50
51
        $this->container->add(GraphQL::BOOLEAN, function () {
52
            return GraphQLScalarType([
53
                'name'        => TypeNameEnum::BOOLEAN,
54
                'description' => 'The `Boolean` scalar type represents `true` or `false`.',
55
                'serialize'   => function ($value) {
56
                    return coerceBoolean($value);
57
                },
58
                'parseValue'  => function ($value) {
59
                    return coerceBoolean($value);
60
                },
61
62
                'parseLiteral' => function (NodeInterface $astNode) {
63
                    /** @var BooleanValueNode $astNode */
64
                    return $astNode->getKind() === NodeKindEnum::BOOLEAN ? $astNode->getValue() : null;
65
                },
66
            ]);
67
        }, true/* $shared */);
68
69
        /**
70
         * @param $value
71
         * @return float
72
         * @throws \TypeError
73
         */
74
        function coerceFloat($value): float
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
75
        {
76
            if ($value === '') {
77
                throw new \TypeError('Float cannot represent non numeric value: (empty string)');
78
            }
79
80
            if (is_numeric($value) || \is_bool($value)) {
81
                return (float)$value;
82
            }
83
84
            throw new \TypeError(sprintf('Float cannot represent non numeric value: %s', $value));
85
        }
86
87
        $this->container->add(GraphQL::FLOAT, function () {
88
            return GraphQLScalarType([
89
                'name'         => TypeNameEnum::FLOAT,
90
                'description'  =>
91
                    'The `Float` scalar type represents signed double-precision fractional ' .
92
                    'values as specified by ' .
93
                    '[IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).',
94
                'serialize'    => function ($value) {
95
                    return coerceFloat($value);
96
                },
97
                'parseValue'   => function ($value) {
98
                    return coerceFloat($value);
99
                },
100
                'parseLiteral' => function (NodeInterface $astNode) {
101
                    /** @var FloatValueNode $astNode */
102
                    return $astNode->getKind() === NodeKindEnum::FLOAT || $astNode->getKind() === NodeKindEnum::INT
103
                        ? $astNode->getValue()
104
                        : null;
105
                },
106
            ]);
107
        }, true/* $shared */);
108
109
        /**
110
         * @param $value
111
         * @return int
112
         * @throws \TypeError
113
         */
114
        function coerceInt($value)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
115
        {
116
            if ($value === '') {
117
                throw new \TypeError('Int cannot represent non 32-bit signed integer value: (empty string)');
118
            }
119
120
            if (\is_bool($value)) {
121
                $value = (int)$value;
122
            }
123
124
            if (!\is_int($value) || $value > MAX_INT || $value < MIN_INT) {
125
                throw new \TypeError(sprintf('Int cannot represent non 32-bit signed integer value: %s', $value));
126
            }
127
128
            $intValue   = (int)$value;
129
            $floatValue = (float)$value;
130
131
            if ($floatValue != $intValue || floor($floatValue) !== $floatValue) {
132
                throw new \TypeError(sprintf('Int cannot represent non-integer value: %s', $value));
133
            }
134
135
            return $intValue;
136
        }
137
138
        $this->container->add(GraphQL::INT, function () {
139
            return GraphQLScalarType([
140
                'name'         => TypeNameEnum::INT,
141
                'description'  =>
142
                    'The `Int` scalar type represents non-fractional signed whole numeric ' .
143
                    'values. Int can represent values between -(2^31) and 2^31 - 1.',
144
                'serialize'    => function ($value) {
145
                    return coerceInt($value);
146
                },
147
                'parseValue'   => function ($value) {
148
                    return coerceInt($value);
149
                },
150
                'parseLiteral' => function (NodeInterface $astNode) {
151
                    /** @var IntValueNode $astNode */
152
                    return $astNode->getKind() === NodeKindEnum::INT ? $astNode->getValue() : null;
153
                },
154
            ]);
155
        }, true/* $shared */);
156
157
        /**
158
         * @param $value
159
         * @return string
160
         * @throws \TypeError
161
         */
162
        function coerceString($value): string
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
163
        {
164
            if ($value === null) {
165
                return 'null';
166
            }
167
168
            if ($value === true) {
169
                return 'true';
170
            }
171
172
            if ($value === false) {
173
                return 'false';
174
            }
175
176
            if (!is_scalar($value)) {
177
                throw new \TypeError('String cannot represent a non-scalar value');
178
            }
179
180
            return (string)$value;
181
        }
182
183
        $this->container->add(GraphQL::ID, function () {
184
            return GraphQLScalarType([
185
                'name'         => TypeNameEnum::ID,
186
                'description'  =>
187
                    'The `ID` scalar type represents a unique identifier, often used to ' .
188
                    'refetch an object or as key for a cache. The ID type appears in a JSON ' .
189
                    'response as a String; however, it is not intended to be human-readable. ' .
190
                    'When expected as an input type, any string (such as `"4"`) or integer ' .
191
                    '(such as `4`) input value will be accepted as an ID.',
192
                'serialize'    => function ($value) {
193
                    return coerceString($value);
194
                },
195
                'parseValue'   => function ($value) {
196
                    return coerceString($value);
197
                },
198
                'parseLiteral' => function (NodeInterface $astNode) {
199
                    /** @var StringValueNode $astNode */
200
                    return $astNode->getKind() === NodeKindEnum::STRING || $astNode->getKind() === NodeKindEnum::INT
201
                        ? $astNode->getValue()
202
                        : null;
203
                },
204
            ]);
205
        }, true/* $shared */);
206
207
        $this->container->add(GraphQL::STRING, function () {
208
            return GraphQLScalarType([
209
                'name'         => TypeNameEnum::STRING,
210
                'description'  =>
211
                    'The `String` scalar type represents textual data, represented as UTF-8 ' .
212
                    'character sequences. The String type is most often used by GraphQL to ' .
213
                    'represent free-form human-readable text.',
214
                'serialize'    => function ($value) {
215
                    return coerceString($value);
216
                },
217
                'parseValue'   => function ($value) {
218
                    return coerceString($value);
219
                },
220
                'parseLiteral' => function (NodeInterface $astNode) {
221
                    /** @var StringValueNode $astNode */
222
                    return $astNode->getKind() === NodeKindEnum::STRING ? $astNode->getValue() : null;
223
                },
224
            ]);
225
        }, true/* $shared */);
226
    }
227
}
228