ReferenceNode::getNativeValue()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 2
b 0
f 0
nc 2
nop 0
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 2
rs 10
1
<?php
2
/**
3
 * This file is part of NACL.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 *
8
 * @copyright 2019 Nuglif (2018) Inc.
9
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
10
 * @author    Pierrick Charron <[email protected]>
11
 * @author    Charle Demers <[email protected]>
12
 */
13
14
declare(strict_types=1);
15
16
namespace Nuglif\Nacl;
17
18
class ReferenceNode extends Node
19
{
20
    public const ROOT = '/';
21
22
    private mixed $path;
23
    private bool $isResolving = false;
24
    private bool $isResolved  = false;
25
    private string $file;
26
    private int $line;
27
    private mixed $value = null;
28
    private ObjectNode $options;
29
30 8
    public function __construct(string|Node $path, string $file, int $line, ObjectNode $options)
31
    {
32 8
        $this->path = $path;
33 8
        $this->file = $file;
34 8
        $this->line = $line;
35 8
        $this->options = $options;
36
    }
37
38 8
    public function getNativeValue(): mixed
39
    {
40 8
        if (!$this->isResolved) {
41 8
            $this->resolve();
42
        }
43
44 5
        return $this->value;
45
    }
46
47 8
    private function resolve(): void
48
    {
49 8
        if ($this->isResolving) {
50 1
            throw new ReferenceException('Circular dependence detected.', $this->file, $this->line);
51
        }
52 8
        if ($this->path instanceof Node) {
53 2
            $this->path = $this->path->getNativeValue();
54
        }
55 8
        if (!is_string($this->path)) {
56 1
            throw new ReferenceException(sprintf('.ref expects parameter to be string, %s given.', gettype($this->path)), $this->file, $this->line);
57
        }
58
59 7
        $this->isResolving = true;
60 7
        $value             = $this->isAbsolute() ? $this->getRoot() : $this->getParent();
61
62 7
        foreach (explode('/', ltrim($this->path, self::ROOT)) as $path) {
63
            switch ($path) {
64 7
                case '.':
65 7
                case '':
66 2
                    break;
67 7
                case '..':
68 1
                    $value = $value?->getParent();
69 1
                    break;
70
                default:
71
                    /** @psalm-suppress PossiblyUndefinedMethod */
72 7
                    if (!isset($value[$path])) {
73 3
                        if ($this->options->has('default')) {
74 2
                            $value = $this->options['default'];
75 2
                            break 2;
76
                        }
77 1
                        throw new ReferenceException(sprintf('Undefined property: %s.', $this->path), $this->file, $this->line);
78
                    }
79 5
                    $value = $value[$path];
80
            }
81
        }
82
83 6
        if ($value instanceof Node) {
84 1
            $value = $value->getNativeValue();
85
        }
86
87 5
        $this->isResolving = false;
88 5
        $this->isResolved  = true;
89 5
        $this->value       = $value;
90
    }
91
92 7
    private function isAbsolute(): bool
93
    {
94 7
        return self::ROOT === substr($this->path, 0, 1);
95
    }
96
}
97