ReferencedValue   A
last analyzed

Complexity

Total Complexity 32

Size/Duplication

Total Lines 152
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 15
Bugs 1 Features 0
Metric Value
dl 0
loc 152
c 15
b 1
f 0
wmc 32
lcom 1
cbo 4
rs 9.6

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 14 3
A hasValue() 0 4 1
A getValue() 0 10 2
A setValue() 0 21 3
A insertValue() 0 12 2
A unsetValue() 0 18 2
A assertAccessorCovers() 0 10 3
A assertPropertiesAccessible() 0 6 3
A assertInsertableToken() 0 6 3
A insertReplaces() 0 7 3
A isIndexedArray() 0 5 2
A assertElementExists() 0 12 3
A assertOwnerExists() 0 6 2
1
<?php
2
declare(strict_types=1);
3
4
namespace gamringer\JSONPointer;
5
6
use gamringer\JSONPointer\Access\Accesses;
7
use gamringer\JSONPointer\Access\ArrayAccessor;
8
9
class ReferencedValue
10
{
11
    private $owner;
12
    private $token;
13
    private $accessor;
14
15
    private $isNext = false;
16
17
    public function __construct(&$owner, $token = null, Accesses $accessor = null)
18
    {
19
        $this->owner = &$owner;
20
        $this->token = $token;
21
        $this->accessor = $accessor;
22
23
        $this->assertPropertiesAccessible();
24
25
        $this->assertAccessorCovers();
26
27
        if ($token == '-' && $this->isIndexedArray()) {
28
            $this->isNext = true;
29
        }
30
    }
31
32
    public function hasValue()
33
    {
34
        $this->assertElementExists();
35
    }
36
37
    public function getValue()
38
    {
39
        $this->assertElementExists();
40
41
        if ($this->token === null) {
42
            return $this->owner;
43
        }
44
45
        return $this->accessor->getValue($this->owner, $this->token);
46
    }
47
48
    public function setValue(&$value)
49
    {
50
        if ($this->isNext) {
51
            $this->owner[] = &$value;
52
53
            return new VoidValue($this->owner, (string)(sizeof($this->owner)-1));
54
        }
55
56
        if ($this->token === null) {
57
            $previousValue = $this->owner;
58
59
            $this->owner = $value;
60
61
            return $previousValue;
62
        }
63
        $previousValue = $this->accessor->getValue($this->owner, $this->token);
64
65
        $this->accessor->setValue($this->owner, $this->token, $value);
66
67
        return $previousValue;
68
    }
69
70
    public function insertValue($value)
71
    {
72
        if ($this->insertReplaces()) {
73
            return $this->setValue($value);
74
        }
75
76
        $this->assertInsertableToken();
77
78
        array_splice($this->owner, (int)$this->token, 0, $value);
79
80
        return new VoidValue($this->owner, $this->token);
81
    }
82
83
    public function unsetValue()
84
    {
85
        $this->assertElementExists();
86
87
        if ($this->token === null) {
88
            $previousValue = $this->owner;
89
90
            $this->owner = new VoidValue();
91
92
            return $previousValue;
93
        }
94
95
        $previousValue = $this->accessor->getValue($this->owner, $this->token);
96
97
        $this->accessor->unsetValue($this->owner, $this->token);
98
99
        return $previousValue;
100
    }
101
    
102
    protected function assertAccessorCovers()
103
    {
104
        if ($this->accessor === null) {
105
            return;
106
        }
107
108
        if (!$this->accessor->covers($this->owner)) {
109
            throw new Exception('Provided Accessor does not handle owner');
110
        }
111
    }
112
113
    protected function assertPropertiesAccessible()
114
    {
115
        if ($this->accessor === null && $this->token !== null) {
116
            throw new Exception('Properties are not accessible');
117
        }
118
    }
119
120
    private function assertInsertableToken()
121
    {
122
        if (!(array_key_exists($this->token, $this->owner) || $this->token == sizeof($this->owner))) {
123
            throw new Exception('Index is out of range');
124
        }
125
    }
126
127
    private function insertReplaces(): bool
128
    {
129
        return $this->isNext
130
            || filter_var($this->token, FILTER_VALIDATE_INT) === false
131
            || !$this->isIndexedArray()
132
        ;
133
    }
134
135
    private function isIndexedArray(): bool
136
    {
137
        return $this->accessor instanceof ArrayAccessor
138
            && $this->accessor->isIndexedArray($this->owner);
0 ignored issues
show
Bug introduced by
It seems like $this->owner can also be of type object<gamringer\JSONPointer\VoidValue>; however, gamringer\JSONPointer\Ac...essor::isIndexedArray() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
139
    }
140
141
    private function assertElementExists()
142
    {
143
        $this->assertOwnerExists();
144
145
        if ($this->token === null) {
146
            return;
147
        }
148
149
        if (!$this->accessor->hasValue($this->owner, $this->token)) {
150
            throw new Exception('Referenced value does not exist');
151
        }
152
    }
153
154
    private function assertOwnerExists()
155
    {
156
        if ($this->owner instanceof VoidValue) {
157
            throw new Exception('Referenced value does not exist');
158
        }
159
    }
160
}
161