PointerGenerator::nodePathToPointerPath()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 9
c 0
b 0
f 0
ccs 5
cts 5
cp 1
rs 10
cc 2
nc 2
nop 1
crap 2
1
<?php declare(strict_types=1);
2
3
namespace DaveRandom\Jom;
4
5
use DaveRandom\Jom\Exceptions\InvalidReferenceNodeException;
6
use DaveRandom\Jom\Exceptions\InvalidSubjectNodeException;
7
8
final class PointerGenerator
9
{
10
    /**
11
     * @var Node
12
     */
13
    private $root;
14
15
    /**
16
     * @var Node|null
17
     */
18
    private $rootParent;
19
20
    /**
21
     * @var Document
22
     */
23
    private $ownerDocument;
24
25
    /**
26
     * @param Node[] $nodePath
27
     * @return string[]
28
     */
29 11
    private function nodePathToPointerPath(array $nodePath): array
30
    {
31 11
        $result = [];
32
33 11
        for ($i = \count($nodePath) - 1; $i >= 0; $i--) {
34 7
            $result[] = $nodePath[$i]->getKey();
35
        }
36
37 11
        return $result;
38
    }
39
40
    /**
41
     * @param Node[] $targetPath
42
     * @param Node[]|null $basePath
43
     * @throws InvalidSubjectNodeException
44
     * @throws InvalidReferenceNodeException
45
     */
46 11
    private function validateAndRemoveNodePathRoots(array &$targetPath, array &$basePath = null): void
47
    {
48 11
        if (\array_pop($targetPath) !== $this->root) {
49
            throw new InvalidSubjectNodeException('Target node for pointer is not a child of the generator root node');
50
        }
51
52 11
        if ($basePath !== null && \array_pop($basePath) !== $this->root) {
53
            throw new InvalidReferenceNodeException('Base node for pointer is not a child of the generator root node');
54
        }
55
    }
56
57
    /**
58
     * @param Node|Document $root
59
     * @throws InvalidReferenceNodeException
60
     */
61 14
    public function __construct($root)
62
    {
63 14
        if ($root instanceof Document) {
64 1
            $root = $root->getRootNode();
65
        }
66
67 14
        if (!($root instanceof Node)) {
68 1
            throw new InvalidReferenceNodeException(
69 1
                'Pointer generator root node must be instance of ' . Node::class . ' or ' . Document::class
70
            );
71
        }
72
73 13
        $this->root = $root;
74 13
        $this->rootParent = $root->getParent();
75 13
        $this->ownerDocument = $root->getOwnerDocument();
76
    }
77
78 2
    public function getRootNode(): Node
79
    {
80 2
        return $this->root;
81
    }
82
83
    /**
84
     * @throws InvalidSubjectNodeException
85
     */
86 4
    public function generateAbsolutePointer(Node $target): Pointer
87
    {
88
        try {
89 4
            $targetPath = $target->getAncestors($this->root);
90
91 4
            $this->validateAndRemoveNodePathRoots($targetPath);
92
93 4
            return Pointer::createFromParameters($this->nodePathToPointerPath($targetPath));
94
        } catch (InvalidSubjectNodeException $e) {
95
            throw $e;
96
        //@codeCoverageIgnoreStart
97
        } catch (\Exception $e) {
98
            throw unexpected($e);
99
        }
100
        //@codeCoverageIgnoreEnd
101
    }
102
103
    /**
104
     * @throws InvalidSubjectNodeException
105
     * @throws InvalidReferenceNodeException
106
     */
107 7
    public function generateRelativePointer(Node $target, Node $base): Pointer
108
    {
109 7
        $targetPath = $target->getAncestors($this->root);
110 7
        $basePath = $base->getAncestors($this->root);
111
112 7
        $this->validateAndRemoveNodePathRoots($targetPath, $basePath);
113
114 7
        while (!empty($targetPath) && \end($targetPath) === \end($basePath)) {
115 2
            \array_pop($targetPath);
116 2
            \array_pop($basePath);
117
        }
118
119
        try {
120 7
            return Pointer::createFromParameters($this->nodePathToPointerPath($targetPath), \count($basePath));
121
        //@codeCoverageIgnoreStart
122
        } catch (\Exception $e) {
123
            throw unexpected($e);
124
        }
125
        //@codeCoverageIgnoreEnd
126
    }
127
}
128