Completed
Push — master ( a71abd...472cae )
by Chris
02:38
created

Pointer::createFromString()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 19
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4.016

Importance

Changes 0
Metric Value
dl 0
loc 19
ccs 9
cts 10
cp 0.9
rs 9.2
c 0
b 0
f 0
cc 4
eloc 9
nc 3
nop 1
crap 4.016
1
<?php declare(strict_types=1);
2
3
namespace DaveRandom\Jom;
4
5
use DaveRandom\Jom\Exceptions\InvalidPointerException;
6
7
final class Pointer
8
{
9
    private $path = [];
10
    private $relativeLevels = null;
11
    private $keyLookup = false;
12
13
    private $string;
14
15 20
    private static function decodePath(string $path): array
16
    {
17 20
        $result = [];
18
19 20
        foreach (\explode('/', \substr($path, 1)) as $component) {
20 20
            $result[] = \str_replace(['~1', '~0'], ['/', '~'], $component);
21
        }
22
23 20
        return $result;
24
    }
25
26 22
    private static function encodePath(array $path): string
27
    {
28 22
        $result = '';
29
30 22
        foreach ($path as $component) {
31 14
            $result .= '/' . \str_replace(['~', '/'], ['~0', '~1'], $component);
32
        }
33
34 22
        return $result;
35
    }
36
37
    private function __construct() { }
38
39 49
    private static function splitRelativePointerComponents(string $pointer): array
40
    {
41 49
        return \preg_match('/^(0|[1-9][0-9]*)($|[^0-9].*)/i', $pointer, $match)
42 42
            ? [$match[2], (int)$match[1]]
43 49
            : [$pointer, null];
44
    }
45
46
    /**
47
     * @throws InvalidPointerException
48
     */
49 49
    public static function createFromString(string $pointer): self
50
    {
51 49
        $result = new self();
52
53 49
        [$pointer, $result->relativeLevels] = self::splitRelativePointerComponents($pointer);
54
55 49
        $result->keyLookup = $pointer === '#';
56
57 49
        if ($result->keyLookup || $pointer === '') {
58 29
            return $result;
59
        }
60
61 20
        if ($pointer[0] !== '/') {
62
            throw new InvalidPointerException('JSON pointer must be the empty string or begin with /');
63
        }
64
65 20
        $result->path = self::decodePath($pointer);
66
67 20
        return $result;
68
    }
69
70
    /**
71
     * @param string[] $path
72
     * @throws InvalidPointerException
73
     */
74 11
    public static function createFromParameters(array $path, ?int $relativeLevels = null, ?bool $isKeyLookup = false): self
75
    {
76 11
        if ($relativeLevels < 0) {
77
            throw new InvalidPointerException('Relative levels must be positive');
78
        }
79
80 11
        if ($isKeyLookup && $relativeLevels === null) {
81
            throw new InvalidPointerException('Key lookups are only valid for relative pointers');
82
        }
83
84 11
        $result = new self();
85
86 11
        foreach ($path as $component) {
87 7
            $result->path[] = (string)$component;
88
        }
89
90 11
        $result->relativeLevels = $relativeLevels;
91 11
        $result->keyLookup = $isKeyLookup ?? false;
92
93 11
        return $result;
94
    }
95
96 37
    public function getPath(): array
97
    {
98 37
        return $this->path;
99
    }
100
101 42
    public function getRelativeLevels(): ?int
102
    {
103 42
        return $this->relativeLevels;
104
    }
105
106 49
    public function isRelative(): bool
107
    {
108 49
        return $this->relativeLevels !== null;
109
    }
110
111 30
    public function isKeyLookup(): bool
112
    {
113 30
        return $this->keyLookup;
114
    }
115
116 26
    public function __toString(): string
117
    {
118 26
        if (isset($this->string)) {
119
            return $this->string;
120
        }
121
122 26
        $this->string = '';
123
124 26
        if ($this->relativeLevels !== null) {
125 19
            $this->string .= $this->relativeLevels;
126
        }
127
128 26
        $this->string .= $this->keyLookup
129 4
            ? '#'
130 22
            : self::encodePath($this->path);
131
132 26
        return $this->string;
133
    }
134
}
135