Completed
Pull Request — master (#17)
by Matt
02:30
created

Pointer   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 127
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 98.04%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 127
ccs 50
cts 51
cp 0.9804
rs 10
wmc 20
lcom 1
cbo 2

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A get() 0 6 1
A has() 0 10 2
C set() 0 36 7
D traverse() 0 33 9
1
<?php
2
3
namespace League\JsonGuard;
4
5
use League\JsonGuard\Pointer\InvalidPointerException;
6
use League\JsonGuard\Pointer\Parser;
7
8
/**
9
 * A simple JSON Pointer implementation that can traverse
10
 * an object resulting from a json_decode() call.
11
 *
12
 * @see https://tools.ietf.org/html/rfc6901
13
 */
14
class Pointer
15
{
16
    /**
17
     * @var object
18
     */
19
    private $json;
20
21
    /**
22
     * Pointer constructor.
23
     * @param object $json
24
     */
25 27
    public function __construct($json)
26
    {
27 27
        $this->json = $json;
28 27
    }
29
30
    /**
31
     * @param string $pointer
32
     * @return mixed
33
     * @throws InvalidPointerException
34
     */
35 21
    public function get($pointer)
36
    {
37 21
        $pointer = (new Parser($pointer))->get();
38
39 19
        return $this->traverse($this->json, $pointer);
40
    }
41
42
    /**
43
     * @param string $pointer
44
     * @return bool
45
     */
46 16
    public function has($pointer)
47
    {
48
        try {
49 16
            $this->get($pointer);
50
51 16
            return true;
52 1
        } catch (InvalidPointerException $e) {
53 1
            return false;
54
        }
55
    }
56
57
    /**
58
     * @param string $pointer
59
     * @param mixed  $data
60
     * @return null
61
     * @throws InvalidPointerException
62
     * @throws \InvalidArgumentException
63
     *
64
     */
65 22
    public function set($pointer, $data)
66
    {
67 22
        if ($pointer === '') {
68 1
            throw new \InvalidArgumentException('Cannot replace the object with set.');
69
        }
70
71 21
        $pointer = (new Parser($pointer))->get();
72
73
        // Simple way to check if the path exists.
74
        // It will throw an exception if it isn't valid.
75 21
        $this->traverse($this->json, $pointer);
76
77 20
        $replace = array_pop($pointer);
78 20
        $target  = $this->json;
79 20
        foreach ($pointer as $segment) {
80 17
            if (is_array($target)) {
81 4
                $target =& $target[$segment];
82 4
            } else {
83 17
                $target =& $target->$segment;
84
            }
85 20
        }
86
87 20
        if (is_array($target)) {
88 6
            if ($replace === '-') {
89 1
                $target[] = $data;
90 1
            } else {
91 5
                $target[$replace] = $data;
92
            }
93 20
        } elseif (is_object($target)) {
94 17
            $target->$replace = $data;
95 17
        } else {
96
            throw new \InvalidArgumentException('Cannot set data because pointer target is not an object or array.');
97
        }
98
99 20
        return null;
100
    }
101
102
    /**
103
     * @param mixed $json    The result of a json_decode call or a portion of it.
104
     * @param array $pointer The parsed pointer
105
     * @return mixed
106
     */
107 24
    private function traverse($json, $pointer)
108
    {
109
        // If we are out of pointers to process we are done.
110 24
        if (empty($pointer)) {
111 20
            return $json;
112
        }
113
114 24
        $reference = array_shift($pointer);
115
116
        // who does this?
117 24
        if ($reference === '' && property_exists($json, '_empty_')) {
118 1
            return $this->traverse($json->_empty_, $pointer);
119
        }
120
121 24
        if (is_object($json)) {
122 24
            if (!property_exists($json, $reference)) {
123 1
                throw InvalidPointerException::nonexistentValue($reference);
124
            }
125
126 24
            return $this->traverse($json->$reference, $pointer);
127 11
        } elseif (is_array($json)) {
128 11
            if ($reference === '-') {
129 1
                return $json;
130
            }
131 10
            if (!array_key_exists($reference, $json)) {
132 1
                throw InvalidPointerException::nonexistentValue($reference);
133
            }
134
135 9
            return $this->traverse($json[$reference], $pointer);
136
        } else {
137 2
            throw InvalidPointerException::nonexistentValue($reference);
138
        }
139
    }
140
}
141