Document::importVectorNode()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
eloc 6
dl 0
loc 13
c 0
b 0
f 0
ccs 0
cts 7
cp 0
rs 10
cc 3
nc 3
nop 1
crap 12
1
<?php declare(strict_types=1);
2
3
namespace DaveRandom\Jom;
4
5
use DaveRandom\Jom\Exceptions\InvalidNodeValueException;
6
use DaveRandom\Jom\Exceptions\InvalidSubjectNodeException;
7
use DaveRandom\Jom\Exceptions\ParseFailureException;
8
use DaveRandom\Jom\Exceptions\WriteOperationForbiddenException;
9
use ExceptionalJSON\DecodeErrorException;
10
11
final class Document implements \JsonSerializable, Taggable
12
{
13
    use TagData;
14
15
    public const IGNORE_INVALID_VALUES = Node::IGNORE_INVALID_VALUES;
16
17
    /** @var NodeFactory */
18
    private static $nodeFactory;
19
20
    /** @var Node */
21
    private $rootNode;
22
23
    /** @uses __init() */
24 1
    private static function __init(): void
25
    {
26 1
        self::$nodeFactory = new SafeNodeFactory();
27
    }
28
29
    /**
30
     * @throws InvalidNodeValueException
31
     * @throws InvalidSubjectNodeException
32
     * @throws WriteOperationForbiddenException
33
     */
34
    private function importVectorNode(VectorNode $node): VectorNode
35
    {
36
        if (!\in_array(\get_class($node), [ArrayNode::class, ObjectNode::class])) {
37
            throw new InvalidSubjectNodeException('Source node is of unknown type: ' . \get_class($node));
38
        }
39
40
        $newNode = new $node(null, $this);
41
42
        foreach ($node as $key => $value) {
43
            $newNode[$key] = $this->import($value);
44
        }
45
46
        return $newNode;
47
    }
48
49
    /**
50
     * @throws InvalidSubjectNodeException
51
     */
52
    private function importScalarNode(Node $node): Node
53
    {
54
        if (!\in_array(\get_class($node), [BooleanNode::class, NumberNode::class, StringNode::class])) {
55
            throw new InvalidSubjectNodeException('Source node is of unknown type: ' . \get_class($node));
56
        }
57
58
        try {
59
            return Node::createFromValue($node->getValue(), $this);
60
        //@codeCoverageIgnoreStart
61
        } catch (\Exception $e) {
62
            throw unexpected($e);
63
        }
64
        //@codeCoverageIgnoreEnd
65
    }
66
67
    private function __construct() { }
68
69
    public function __clone()
70
    {
71
        try {
72
            $this->rootNode = $this->import($this->rootNode);
73
        //@codeCoverageIgnoreStart
74
        } catch (\Exception $e) {
75
            throw unexpected($e);
76
        }
77
        //@codeCoverageIgnoreEnd
78
    }
79
80
    /**
81
     * @throws ParseFailureException
82
     */
83 64
    public static function parse(string $json, ?int $depthLimit = 512, ?int $options = 0): Document
84
    {
85 64
        $depthLimit = $depthLimit ?? 512;
86 64
        $options = ($options ?? 0) & ~\JSON_OBJECT_AS_ARRAY;
87
88
        try {
89 64
            $data = \ExceptionalJSON\decode($json, false, $depthLimit, $options);
90
91 64
            $doc = new self();
92 64
            $doc->rootNode = self::$nodeFactory->createNodeFromValue($data, $doc, 0);
93
94 64
            return $doc;
95
        } catch (DecodeErrorException $e) {
96
            throw new ParseFailureException("Decoding JSON string failed: {$e->getMessage()}", $e);
97
        //@codeCoverageIgnoreStart
98
        } catch (\Exception $e) {
99
            throw unexpected($e);
100
        }
101
        //@codeCoverageIgnoreEnd
102
    }
103
104
    /**
105
     * @param bool|int|float|string|array|object|null A value that can be encoded as JSON
106
     * @throws InvalidNodeValueException
107
     */
108 21
    public static function createFromValue($value, ?int $flags = 0): Document
109
    {
110
        try {
111 21
            $doc = new self();
112 21
            $doc->rootNode = Node::createFromValue($value, $doc, $flags);
113
114 21
            return $doc;
115
        } catch (InvalidNodeValueException $e) {
116
            throw $e;
117
        //@codeCoverageIgnoreStart
118
        } catch (\Exception $e) {
119
            throw unexpected($e);
120
        }
121
        //@codeCoverageIgnoreEnd
122
    }
123
124
    public static function createFromNode(Node $node): Document
125
    {
126
        try {
127
            $doc = new self();
128
            $doc->rootNode = $doc->import($node);
129
130
            return $doc;
131
        //@codeCoverageIgnoreStart
132
        } catch (\Exception $e) {
133
            throw unexpected($e);
134
        }
135
        //@codeCoverageIgnoreEnd
136
    }
137
138 84
    public function getRootNode(): Node
139
    {
140 84
        return $this->rootNode;
141
    }
142
143
    /**
144
     * @throws InvalidSubjectNodeException
145
     * @throws WriteOperationForbiddenException
146
     * @throws InvalidNodeValueException
147
     * @throws InvalidSubjectNodeException
148
     */
149
    public function import(Node $node): Node
150
    {
151
        if ($node->getOwnerDocument() === $this) {
152
            throw new InvalidSubjectNodeException('Cannot import tne supplied node, already owned by this document');
153
        }
154
155
        if ($node instanceof NullNode) {
156
            return new NullNode($this);
157
        }
158
159
        return $node instanceof VectorNode
160
            ? $this->importVectorNode($node)
161
            : $this->importScalarNode($node);
162
    }
163
164
    public function jsonSerialize()
165
    {
166
        return $this->rootNode !== null
167
            ? $this->rootNode->jsonSerialize()
168
            : null;
169
    }
170
}
171
172
\DaveRandom\Jom\initialize(Document::class);
173