ValueFactory   A
last analyzed

Complexity

Total Complexity 21

Size/Duplication

Total Lines 121
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 21
eloc 44
dl 0
loc 121
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A make() 0 6 2
B create() 0 34 10
A fromIterator() 0 19 5
A addCaster() 0 7 2
A each() 0 4 2
1
<?php
2
3
/**
4
 * This file is part of Railt package.
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
declare(strict_types=1);
11
12
namespace Railt\SDL\Backend\HashTable;
13
14
use Phplrt\Source\Exception\NotAccessibleException;
15
use Railt\Dumper\Facade;
16
use Railt\SDL\Exception\TypeErrorException;
17
use Railt\SDL\Frontend\Ast\Node;
18
use Railt\TypeSystem\Value\BooleanValue;
19
use Railt\TypeSystem\Value\FloatValue;
20
use Railt\TypeSystem\Value\InputObjectValue;
21
use Railt\TypeSystem\Value\IntValue;
22
use Railt\TypeSystem\Value\ListValue;
0 ignored issues
show
Bug introduced by
The type Railt\TypeSystem\Value\ListValue was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
23
use Railt\TypeSystem\Value\NullValue;
24
use Railt\TypeSystem\Value\StringValue;
25
use Railt\TypeSystem\Value\ValueInterface;
26
27
/**
28
 * Class ValueFactory
29
 */
30
class ValueFactory
31
{
32
    /**
33
     * @var array|\Closure[]
34
     */
35
    protected array $casters = [];
36
37
    /**
38
     * @param \Closure $caster
39
     * @param bool $append
40
     * @return $this
41
     */
42
    public function addCaster(\Closure $caster, bool $append = true): self
43
    {
44
        $this->casters = $append
45
            ? [...$this->casters, $caster]
46
            : [$caster, ...$this->casters];
47
48
        return $this;
49
    }
50
51
    /**
52
     * @param iterable|mixed[] $values
53
     * @param Node|null $ctx
54
     * @return iterable|ValueInterface[]
55
     * @throws NotAccessibleException
56
     * @throws TypeErrorException
57
     * @throws \RuntimeException
58
     */
59
    public function each(iterable $values, Node $ctx = null): iterable
60
    {
61
        foreach ($values as $name => $value) {
62
            yield $name => $this->make($value, $ctx);
0 ignored issues
show
Bug Best Practice introduced by
The expression yield $name => $this->make($value, $ctx) returns the type Generator which is incompatible with the documented return type Railt\TypeSystem\Value\ValueInterface[]|iterable.
Loading history...
63
        }
64
    }
65
66
    /**
67
     * @param mixed $value
68
     * @param Node|null $context
69
     * @return ValueInterface
70
     * @throws TypeErrorException
71
     * @throws NotAccessibleException
72
     * @throws \RuntimeException
73
     */
74
    public function make($value, Node $context = null): ValueInterface
75
    {
76
        try {
77
            return $this->create($value);
78
        } catch (\Throwable $e) {
79
            throw TypeErrorException::fromAst($e->getMessage(), $context, $e);
80
        }
81
    }
82
83
    /**
84
     * @param mixed $value
85
     * @return ValueInterface
86
     * @throws \InvalidArgumentException
87
     * @throws \OverflowException
88
     */
89
    private function create($value): ValueInterface
90
    {
91
        switch (true) {
92
            case $value instanceof ValueInterface:
93
                return $value;
94
95
            case \is_bool($value):
96
                return BooleanValue::parse($value);
97
98
            case \is_float($value):
99
                return FloatValue::parse($value);
100
101
            case \is_int($value):
102
                return IntValue::parse($value);
103
104
            case $value === null:
105
                return NullValue::parse($value);
106
107
            case \is_string($value):
108
                return StringValue::parse($value);
109
110
            case \is_iterable($value):
111
                return $this->fromIterator($value);
112
113
            default:
114
                foreach ($this->casters as $caster) {
115
                    if ($result = $caster($value)) {
116
                        return $result;
117
                    }
118
                }
119
120
                $error = 'Value of type %s can not be converted to GraphQL type';
121
122
                throw new \InvalidArgumentException(\sprintf($error, Facade::dump($value)));
123
        }
124
    }
125
126
    /**
127
     * @param iterable $iterator
128
     * @return ValueInterface
129
     * @throws \InvalidArgumentException
130
     * @throws \OverflowException
131
     */
132
    private function fromIterator(iterable $iterator): ValueInterface
133
    {
134
        [$result, $isObject] = [[], false];
135
136
        foreach ($iterator as $key => $value) {
137
            if (\is_string($key)) {
138
                $isObject = true;
139
            }
140
141
            if ($isObject) {
142
                $result[$key] = $this->create($value);
143
            } else {
144
                $result[] = $this->create($value);
145
            }
146
        }
147
148
        return $isObject
149
            ? InputObjectValue::parse($result)
150
            : ListValue::parse($result);
151
    }
152
}
153