With::withoutPropertyKey()   A
last analyzed

Complexity

Conditions 5
Paths 4

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
eloc 9
nc 4
nop 2
dl 0
loc 17
ccs 10
cts 10
cp 1
crap 5
rs 9.6111
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Jasny\Immutable;
6
7
/**
8
 * Trait with the `withProperty` methods that can be used by classes of immutable objects.
9
 *
10
 * {@internal Some lines are expected to be covered, which should be ignored. Added codeCoverageIgnore. }}
11
 */
12
trait With
13
{
14
    /**
15
     * Return a copy with a changed property.
16
     * Returns this object if the resulting object would be the same as the current one.
17
     *
18
     * @param string  $property
19
     * @param mixed   $value
20
     * @return static
21
     * @throws \BadMethodCallException if property doesn't exist
22
     */
23 2
    private function withProperty(string $property, $value)
24
    {
25 2
        if (!property_exists($this, $property)) {
26 1
            throw new \BadMethodCallException(sprintf('%s has no property "%s"', get_class($this), $property));
27
        }
28
29
        if (
30 1
            (isset($this->{$property}) && $this->{$property} === $value) || // Typed property may be not initialized
31 1
            (!isset($this->{$property}) && $value === null)        
32
        ) {
33 1
            return $this;
34
        }
35
36 1
        $clone = clone $this;
37 1
        $clone->{$property} = $value;
38
39 1
        return $clone;
40
    }
41
42
    /**
43
     * Return a copy with a property unset.
44
     * Returns this object if the resulting object would be the same as the current one.
45
     *
46
     * @param string  $property
47
     * @return static
48
     * @throws \BadMethodCallException if property doesn't exist
49
     */
50 2
    private function withoutProperty(string $property)
51
    {
52 2
        if (!property_exists($this, $property)) {
53 1
            throw new \BadMethodCallException(sprintf('%s has no property "%s"', get_class($this), $property));
54
        }
55
56 1
        if (!isset($this->{$property})) {
57 1
            return $this;
58
        }
59
60 1
        $clone = clone $this;
61 1
        unset($clone->{$property});
62
63 1
        return $clone;
64
    }
65
66
67
    /**
68
     * Return a copy with an added item for a property.
69
     * Returns this object if the resulting object would be the same as the current one.
70
     *
71
     * @param string  $property
72
     * @param string  $key
73
     * @param mixed   $value
74
     * @return static
75
     * @throws \BadMethodCallException if property doesn't exist
76
     */
77 3
    private function withPropertyKey(string $property, string $key, $value)
78
    {
79 3
        if (!property_exists($this, $property)) {
80 1
            throw new \BadMethodCallException(sprintf('%s has no property "%s"', get_class($this), $property));
81
        } // @codeCoverageIgnore
82 2
        if (!is_array($this->{$property}) && !$this->{$property} instanceof \ArrayAccess) {
83 1
            throw new \BadMethodCallException(sprintf('%s::$%s is not an array', get_class($this), $property));
84
        }
85
86 1
        if (isset($this->{$property}[$key]) && $this->{$property}[$key] === $value) {
87 1
            return $this;
88
        }
89
90 1
        $clone = clone $this;
91 1
        $clone->{$property}[$key] = $value;
92
93 1
        return $clone;
94
    }
95
96
    /**
97
     * Return a copy with a removed item from a property.
98
     * Returns this object if the resulting object would be the same as the current one.
99
     *
100
     * @param string  $property
101
     * @param string  $key
102
     * @return static
103
     * @throws \BadMethodCallException if property doesn't exist or isn't an array
104
     */
105 3
    private function withoutPropertyKey(string $property, string $key)
106
    {
107 3
        if (!property_exists($this, $property)) {
108 1
            throw new \BadMethodCallException(sprintf('%s has no property "%s"', get_class($this), $property));
109
        } // @codeCoverageIgnore
110 2
        if (!is_array($this->{$property}) && !$this->{$property} instanceof \ArrayAccess) {
111 1
            throw new \BadMethodCallException(sprintf('%s::$%s is not an array', get_class($this), $property));
112
        }
113
114 1
        if (!isset($this->{$property}[$key])) {
115 1
            return $this;
116
        }
117
118 1
        $clone = clone $this;
119 1
        unset($clone->{$property}[$key]);
120
121 1
        return $clone;
122
    }
123
124
125
    /**
126
     * Return a copy with a value added to a sequential array.
127
     *
128
     * @param string  $property
129
     * @param mixed   $value
130
     * @param mixed   $unique    Don't add if the array already has a copy of the value.
131
     * @return static
132
     * @throws \BadMethodCallException if property doesn't exist or isn't an array
133
     */
134 3
    private function withPropertyItem(string $property, $value, bool $unique = false)
135
    {
136 3
        if (!property_exists($this, $property)) {
137 1
            throw new \BadMethodCallException(sprintf('%s has no property "%s"', get_class($this), $property));
138
        }
139 2
        if (!is_array($this->{$property})) {
140 1
            throw new \BadMethodCallException(sprintf('%s::$%s is not an array', get_class($this), $property));
141
        }
142
143 1
        if ($unique && in_array($value, $this->{$property}, true)) {
144 1
            return $this;
145
        }
146
147 1
        $clone = clone $this;
148 1
        $clone->{$property}[] = $value;
149
150 1
        return $clone;
151
    }
152
153
    /**
154
     * Return a copy with a value removed from a sequential array.
155
     * Returns this object if the resulting object would be the same as the current one.
156
     *
157
     * @param string  $property
158
     * @param mixed   $value
159
     * @return static
160
     * @throws \BadMethodCallException if property doesn't exist or isn't an array
161
     */
162 3
    private function withoutPropertyItem(string $property, $value)
163
    {
164 3
        if (!property_exists($this, $property)) {
165 1
            throw new \BadMethodCallException(sprintf('%s has no property "%s"', get_class($this), $property));
166
        }
167 2
        if (!is_array($this->{$property})) {
168 1
            throw new \BadMethodCallException(sprintf('%s::$%s is not an array', get_class($this), $property));
169
        }
170
171 1
        $keys = array_keys($this->{$property}, $value, true);
172
173 1
        if ($keys === []) {
174 1
            return $this;
175
        }
176
177 1
        $clone = clone $this;
178 1
        $clone->{$property} = array_values(array_diff_key($clone->{$property}, array_fill_keys($keys, null)));
179
180 1
        return $clone;
181
    }
182
}
183