Completed
Push — master ( e32b70...1a827f )
by Chris
03:55
created

NodeFactory::tryCreateNodeFromValue()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 17
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 4.5923

Importance

Changes 0
Metric Value
eloc 8
dl 0
loc 17
c 0
b 0
f 0
ccs 6
cts 9
cp 0.6667
rs 10
cc 4
nc 6
nop 3
crap 4.5923
1
<?php declare(strict_types=1);
2
3
namespace DaveRandom\Jom;
4
5
use DaveRandom\Jom\Exceptions\Exception;
6
use DaveRandom\Jom\Exceptions\InvalidNodeValueException;
7
8
abstract class NodeFactory
9
{
10
    private const ENABLE_INVALID_VALUE_IGNORE = 0x8000;
11
    private const IGNORE_INVALID_VALUES = Node::IGNORE_INVALID_VALUES | self::ENABLE_INVALID_VALUE_IGNORE;
12
13
    private const NODE_FACTORY_METHODS = [
14
        'NULL'    => 'createNullNode',
15
        'boolean' => 'createNodeFromScalarValue',
16
        'integer' => 'createNodeFromScalarValue',
17
        'double'  => 'createNodeFromScalarValue',
18
        'string'  => 'createNodeFromScalarValue',
19
        'array'   => 'createNodeFromArrayValue',
20
        'object'  => 'createNodeFromObjectValue',
21
    ];
22
23
    /**
24
     * @param mixed $value
25
     * @throws InvalidNodeValueException
26
     */
27
    private function throwInvalidValue($value): void
28
    {
29
        throw new InvalidNodeValueException(\sprintf(
30
            "Failed to create node from value of type '%s'",
31
            describe($value)
32
        ));
33
    }
34
35
    /**
36
     * @uses createNullNode
37
     */
38 35
    private function createNullNode(?Document $ownerDoc): NullNode
39
    {
40 35
        return new NullNode($ownerDoc);
41
    }
42
43
    /**
44
     * @param mixed $value
45
     * @uses createNodeFromScalarValue
46
     */
47 64
    private function createNodeFromScalarValue(?Document $ownerDoc, $value): Node
48
    {
49
        $className = [
50
            'boolean' => BooleanNode::class,
51
            'integer' => NumberNode::class,
52
            'double' => NumberNode::class,
53
            'string' => StringNode::class,
54 64
        ][\gettype($value)];
55
56 64
        return new $className($value, $ownerDoc);
57
    }
58
59
    /**
60
     * @param mixed $value
61
     * @throws InvalidNodeValueException
62
     * @throws Exception
63
     */
64 101
    final protected function tryCreateNodeFromValue($value, ?Document $ownerDoc, int $flags): ?Node
65
    {
66 101
        $factory = self::NODE_FACTORY_METHODS[\gettype($value)] ?? null;
67
68 101
        if ($factory !== null) {
69 101
            $node = $this->{$factory}($ownerDoc, $value, $flags);
70
        }
71
72 101
        if (isset($node)) {
73 101
            return $node;
74
        }
75
76
        if (!($flags & Node::IGNORE_INVALID_VALUES)) {
77
            $this->throwInvalidValue($value);
78
        }
79
80
        return null;
81
    }
82
83
    /**
84
     * @param mixed[] $values
85
     * @throws InvalidNodeValueException
86
     * @throws Exception
87
     */
88 94
    final protected function createArrayNodeFromPackedArray(array $values, ?Document $ownerDoc, int $flags): ArrayNode
89
    {
90 94
        $node = new ArrayNode([], $ownerDoc);
91
92 94
        foreach ($values as $value) {
93 89
            if (null !== $valueNode = $this->tryCreateNodeFromValue($value, $ownerDoc, $flags)) {
94 89
                $node->push($valueNode);
95
            }
96
        }
97
98 94
        return $node;
99
    }
100
101
    /**
102
     * @param array|object $properties
103
     * @throws InvalidNodeValueException
104
     * @throws Exception
105
     */
106 64
    final protected function createObjectNodeFromPropertyMap($properties, ?Document $ownerDoc, int $flags): ObjectNode
107
    {
108 64
        $node = new ObjectNode([], $ownerDoc);
109
110 64
        foreach ($properties as $name => $value) {
111 64
            if (null !== $valueNode = $this->tryCreateNodeFromValue($value, $ownerDoc, $flags)) {
112 64
                $node->setProperty($name, $valueNode);
113
            }
114
        }
115
116 64
        return $node;
117
    }
118
119
    /**
120
     * @param mixed[] $array
121
     * @throws InvalidNodeValueException
122
     * @throws Exception
123
     */
124
    abstract protected function createNodeFromArrayValue(?Document $ownerDoc, array $array, int $flags): VectorNode;
125
126
    /**
127
     * @throws InvalidNodeValueException
128
     * @throws Exception
129
     */
130
    abstract protected function createNodeFromObjectValue(?Document $ownerDoc, object $object, int $flags): ?Node;
131
132
    /**
133
     * @param bool|int|float|string|array|object|null A value that can be encoded as JSON
134
     * @throws InvalidNodeValueException
135
     * @throws Exception
136
     */
137 101
    final public function createNodeFromValue($value, ?Document $ownerDoc, int $flags): Node
138
    {
139 101
        $node = $this->tryCreateNodeFromValue($value, $ownerDoc, $flags);
140
141 101
        if ($node === null) {
142
            $this->throwInvalidValue($value);
143
        }
144
145 101
        return $node;
146
    }
147
}
148