Completed
Branch feature/concerns-into-traits (c2fa68)
by Andrea Marco
02:54 queued 01:36
created

HasProperties::getNestedDto()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 7
c 0
b 0
f 0
nc 3
nop 1
dl 0
loc 14
ccs 8
cts 8
cp 1
crap 3
rs 10
1
<?php
2
3
namespace Cerbero\Dto\Traits;
4
5
use Cerbero\Dto\DtoProperty;
6
use Cerbero\Dto\Exceptions\UnknownDtoPropertyException;
7
use Cerbero\Dto\Exceptions\UnsetDtoPropertyException;
8
9
use const Cerbero\Dto\IGNORE_UNKNOWN_PROPERTIES;
0 ignored issues
show
Bug introduced by
The constant Cerbero\Dto\IGNORE_UNKNOWN_PROPERTIES was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
10
use const Cerbero\Dto\MUTABLE;
0 ignored issues
show
Bug introduced by
The constant Cerbero\Dto\MUTABLE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
11
use const Cerbero\Dto\PARTIAL;
0 ignored issues
show
Bug introduced by
The constant Cerbero\Dto\PARTIAL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
12
13
/**
14
 * Trait to interact with properties.
15
 *
16
 */
17
trait HasProperties
18
{
19
    /**
20
     * The properties map.
21
     *
22
     * @var array
23
     */
24
    protected $propertiesMap;
25
26
    /**
27
     * Retrieve the DTO properties map
28
     *
29
     * @return array
30
     */
31 42
    public function getPropertiesMap(): array
32
    {
33 42
        return $this->propertiesMap;
34
    }
35
36
    /**
37
     * Retrieve the DTO property names
38
     *
39
     * @return array
40
     */
41 6
    public function getPropertyNames(): array
42
    {
43 6
        return array_keys($this->getPropertiesMap());
44
    }
45
46
    /**
47
     * Retrieve the DTO properties
48
     *
49
     * @return DtoProperty[]
50
     */
51 6
    public function getProperties(): array
52
    {
53 6
        return array_values($this->getPropertiesMap());
54
    }
55
56
    /**
57
     * Determine whether the given property is set (even if its value is NULL)
58
     *
59
     * @param string $property
60
     * @return bool
61
     */
62 36
    public function hasProperty(string $property): bool
63
    {
64
        try {
65 36
            return !!$this->getProperty($property);
66 27
        } catch (UnknownDtoPropertyException $e) {
67 27
            return false;
68
        }
69
    }
70
71
    /**
72
     * Retrieve the given DTO property (support dot notation)
73
     *
74
     * @param string $property
75
     * @return DtoProperty
76
     * @throws UnknownDtoPropertyException
77
     */
78 108
    public function getProperty(string $property): DtoProperty
79
    {
80 108
        if (isset($this->propertiesMap[$property])) {
81 69
            return $this->propertiesMap[$property];
82
        }
83
84 63
        $nestedProperty = substr($property, strrpos($property, '.') + 1);
85
86 63
        return $this->getNestedDto($property)->getProperty($nestedProperty);
87
    }
88
89
    /**
90
     * Retrieve the given nested DTO
91
     *
92
     * @param string $property
93
     * @return self
94
     * @throws UnknownDtoPropertyException
95
     */
96 63
    protected function getNestedDto(string $property): self
97
    {
98 63
        if (strpos($property, '.') === false) {
99 57
            throw new UnknownDtoPropertyException(static::class, $property);
100
        }
101
102 18
        [$property, $nestedProperty] = explode('.', $property, 2);
103 18
        $presumedDto = $this->get($property);
104
105 15
        if ($presumedDto instanceof self) {
106 12
            return $presumedDto;
107
        }
108
109 3
        throw new UnknownDtoPropertyException(static::class, $nestedProperty);
110
    }
111
112
    /**
113
     * Determine whether the given property has a value (return FALSE if the value is NULL)
114
     *
115
     * @param string $property
116
     * @return bool
117
     */
118 30
    public function has(string $property): bool
119
    {
120
        try {
121 30
            return $this->get($property) !== null;
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->get($property) targeting Cerbero\Dto\Traits\HasProperties::get() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
122 9
        } catch (UnknownDtoPropertyException $e) {
123 9
            return false;
124
        }
125
    }
126
127
    /**
128
     * Retrieve the given property value
129
     *
130
     * @param string $property
131
     * @return mixed
132
     * @throws UnknownDtoPropertyException
133
     */
134 87
    public function get(string $property)
135
    {
136 87
        return $this->getProperty($property)->value();
137
    }
138
139
    /**
140
     * Set the given property to the provided value
141
     *
142
     * @param string $property
143
     * @param mixed $value
144
     * @return self
145
     * @throws UnknownDtoPropertyException
146
     */
147 24
    public function set(string $property, $value): self
148
    {
149 24
        $flags = $this->getFlags();
0 ignored issues
show
Bug introduced by
It seems like getFlags() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

149
        /** @scrutinizer ignore-call */ 
150
        $flags = $this->getFlags();
Loading history...
150 24
        $dto = ($flags & MUTABLE) ? $this : $this->clone();
0 ignored issues
show
Bug introduced by
It seems like clone() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

150
        $dto = ($flags & MUTABLE) ? $this : $this->/** @scrutinizer ignore-call */ clone();
Loading history...
151
152
        try {
153 24
            $dto->getProperty($property)->setValue($value, $flags);
154 6
        } catch (UnknownDtoPropertyException $e) {
155 6
            if (!($flags & IGNORE_UNKNOWN_PROPERTIES)) {
156 3
                throw $e;
157
            }
158
        }
159
160 21
        return $dto;
161
    }
162
163
    /**
164
     * Unset the given property
165
     *
166
     * @param string $property
167
     * @return self
168
     * @throws UnsetDtoPropertyException
169
     * @throws UnknownDtoPropertyException
170
     */
171 24
    public function unset(string $property): self
172
    {
173 24
        $flags = $this->getFlags();
174
175 24
        if (!($flags & PARTIAL)) {
176 6
            throw new UnsetDtoPropertyException(static::class, $property);
177
        }
178
179 18
        if (strpos($property, '.') !== false) {
180 9
            [$property, $nestedProperty] = explode('.', $property, 2);
181 9
            $unsetDto = $this->get($property)->unset($nestedProperty);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->get($property) targeting Cerbero\Dto\Traits\HasProperties::get() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
182 6
            return $this->set($property, $unsetDto);
183
        }
184
185 15
        if ($flags & MUTABLE) {
186 9
            unset($this->propertiesMap[$property]);
187 9
            return $this;
188
        }
189
190 6
        $data = $this->toArray();
0 ignored issues
show
Bug introduced by
It seems like toArray() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

190
        /** @scrutinizer ignore-call */ 
191
        $data = $this->toArray();
Loading history...
191 6
        unset($data[$property]);
192
193 6
        return new static($data, $flags);
0 ignored issues
show
Unused Code introduced by
The call to Cerbero\Dto\Traits\HasProperties::__construct() has too many arguments starting with $data. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

193
        return /** @scrutinizer ignore-call */ new static($data, $flags);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
194
    }
195
196
    /**
197
     * Determine whether a given property has a value
198
     *
199
     * @param string $property
200
     * @return bool
201
     */
202 9
    public function __isset(string $property): bool
203
    {
204 9
        return $this->offsetExists($property);
0 ignored issues
show
Bug introduced by
It seems like offsetExists() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

204
        return $this->/** @scrutinizer ignore-call */ offsetExists($property);
Loading history...
205
    }
206
207
    /**
208
     * Retrieve the given property value
209
     *
210
     * @param string $property
211
     * @return mixed
212
     * @throws UnknownDtoPropertyException
213
     */
214 27
    public function &__get(string $property)
215
    {
216 27
        return $this->offsetGet($property);
0 ignored issues
show
Bug introduced by
It seems like offsetGet() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

216
        return $this->/** @scrutinizer ignore-call */ offsetGet($property);
Loading history...
217
    }
218
219
    /**
220
     * Set the given property to the provided value
221
     *
222
     * @param string $property
223
     * @param mixed $value
224
     * @return void
225
     * @throws ImmutableDtoException
226
     * @throws UnknownDtoPropertyException
227
     */
228 6
    public function __set(string $property, $value): void
229
    {
230 6
        $this->offsetSet($property, $value);
0 ignored issues
show
Bug introduced by
It seems like offsetSet() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

230
        $this->/** @scrutinizer ignore-call */ 
231
               offsetSet($property, $value);
Loading history...
231 3
    }
232
}
233