Completed
Push — master ( a0cce6...0fe793 )
by Chris
02:48 queued 20s
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
dl 0
loc 17
ccs 6
cts 9
cp 0.6667
rs 9.2
c 0
b 0
f 0
cc 4
eloc 8
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
     * @throws InvalidNodeValueException
25
     */
26
    private function throwInvalidValue($value): void
27
    {
28
        /** @noinspection PhpInternalEntityUsedInspection */
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
     * @uses createNodeFromScalarValue
45
     */
46 64
    private function createNodeFromScalarValue(?Document $ownerDoc, $value): Node
47
    {
48
        $className = [
49
            'boolean' => BooleanNode::class,
50
            'integer' => NumberNode::class,
51
            'double' => NumberNode::class,
52
            'string' => StringNode::class,
53 64
        ][\gettype($value)];
54
55 64
        return new $className($value, $ownerDoc);
56
    }
57
58
    /**
59
     * @throws InvalidNodeValueException
60
     * @throws Exception
61
     */
62 101
    final protected function tryCreateNodeFromValue($value, ?Document $ownerDoc, int $flags): ?Node
63
    {
64 101
        $factory = self::NODE_FACTORY_METHODS[\gettype($value)] ?? null;
65
66 101
        if ($factory !== null) {
67 101
            $node = $this->{$factory}($ownerDoc, $value, $flags);
68
        }
69
70 101
        if (isset($node)) {
71 101
            return $node;
72
        }
73
74
        if (!($flags & Node::IGNORE_INVALID_VALUES)) {
75
            $this->throwInvalidValue($value);
76
        }
77
78
        return null;
79
    }
80
81
    /**
82
     * @throws InvalidNodeValueException
83
     * @throws Exception
84
     */
85 94
    final protected function createArrayNodeFromPackedArray(array $values, ?Document $ownerDoc, int $flags): ArrayNode
86
    {
87 94
        $node = new ArrayNode([], $ownerDoc);
88
89 94
        foreach ($values as $value) {
90 89
            if (null !== $valueNode = $this->tryCreateNodeFromValue($value, $ownerDoc, $flags)) {
91 89
                $node->push($valueNode);
92
            }
93
        }
94
95 94
        return $node;
96
    }
97
98
    /**
99
     * @throws InvalidNodeValueException
100
     * @throws Exception
101
     */
102 64
    final protected function createObjectNodeFromPropertyMap($properties, ?Document $ownerDoc, int $flags): ObjectNode
103
    {
104 64
        $node = new ObjectNode([], $ownerDoc);
105
106 64
        foreach ($properties as $name => $value) {
107 64
            if (null !== $valueNode = $this->tryCreateNodeFromValue($value, $ownerDoc, $flags)) {
108 64
                $node->setProperty($name, $valueNode);
109
            }
110
        }
111
112 64
        return $node;
113
    }
114
115
    /**
116
     * @throws InvalidNodeValueException
117
     * @throws Exception
118
     */
119
    abstract protected function createNodeFromArrayValue(?Document $ownerDoc, array $array, int $flags): VectorNode;
120
121
    /**
122
     * @throws InvalidNodeValueException
123
     * @throws Exception
124
     */
125
    abstract protected function createNodeFromObjectValue(?Document $ownerDoc, object $object, int $flags): ?Node;
126
127
    /**
128
     * @throws InvalidNodeValueException
129
     * @throws Exception
130
     */
131 101
    final public function createNodeFromValue($value, ?Document $ownerDoc, int $flags): Node
132
    {
133 101
        $node = $this->tryCreateNodeFromValue($value, $ownerDoc, $flags);
134
135 101
        if ($node === null) {
136
            $this->throwInvalidValue($value);
137
        }
138
139 101
        return $node;
140
    }
141
}
142