GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Pull Request — master (#56)
by Arthur
02:24 queued 01:13
created

DataTransferObject::parseArray()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 10
nc 4
nop 1
dl 0
loc 20
rs 9.6111
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Spatie\DataTransferObject;
6
7
use ReflectionClass;
8
use ReflectionProperty;
9
use Spatie\DataTransferObject\Contracts\immutable;
10
use Spatie\DataTransferObject\Contracts\DtoContract;
11
use Spatie\DataTransferObject\Contracts\PropertyContract;
12
use Spatie\DataTransferObject\Exceptions\ImmutableDtoException;
13
use Spatie\DataTransferObject\Exceptions\PropertyNotFoundDtoException;
14
use Spatie\DataTransferObject\Exceptions\ImmutablePropertyDtoException;
15
use Spatie\DataTransferObject\Exceptions\UnknownPropertiesDtoException;
16
use Spatie\DataTransferObject\Exceptions\UninitialisedPropertyDtoException;
17
18
/**
19
 * Class DataTransferObject.
20
 */
21
abstract class DataTransferObject implements DtoContract
22
{
23
    /** @var array */
24
    protected $onlyKeys = [];
25
26
    /** @var Property[] | array */
27
    protected $properties = [];
28
29
    /** @var bool */
30
    protected $immutable = false;
31
32
    public function __construct(array $parameters)
33
    {
34
        $this->boot($parameters);
35
    }
36
37
    /**
38
     * Boot the dto and process all parameters.
39
     * @param array $parameters
40
     * @throws \ReflectionException
41
     */
42
    protected function boot(array $parameters): void
43
    {
44
        foreach ($this->getPublicProperties() as $property) {
45
46
            /*
47
             * Do not change the order of the following methods.
48
             * External packages rely on this order.
49
             */
50
51
            $this->setPropertyDefaultValue($property);
52
53
            $property = $this->mutateProperty($property);
54
55
            $this->validateProperty($property, $parameters);
56
57
            $this->setPropertyValue($property, $parameters);
58
59
            /* add the property to an associative array with the name as key */
60
            $this->properties[$property->getName()] = $property;
61
62
            /* remove the property from the value object and parameters array  */
63
            unset($parameters[$property->getName()], $this->{$property->getName()});
64
        }
65
66
        $this->processRemainingProperties($parameters);
67
        $this->determineImmutability();
68
    }
69
70
    protected function determineImmutability()
71
    {
72
        if ($this instanceof immutable) {
73
            $this->setImmutable();
74
        }
75
    }
76
77
    protected function setImmutable()
78
    {
79
        $this->immutable = true;
80
        foreach ($this->properties as $property) {
81
            $this->chainPropertiesImmutable($property);
82
        }
83
    }
84
85
    protected function chainPropertiesImmutable(PropertyContract $property)
86
    {
87
        $dto = $property->getValue();
88
        if ($dto instanceof DtoContract) {
89
            $dto->immutable();
90
        } elseif (is_iterable($dto)) {
91
            foreach ($dto as $aPotentialDto) {
92
                if ($aPotentialDto instanceof DtoContract) {
93
                    $aPotentialDto->immutable();
94
                }
95
            }
96
        }
97
    }
98
99
    /**
100
     * Get all public properties from the current object through reflection.
101
     * @return Property[]
102
     * @throws \ReflectionException
103
     */
104
    protected function getPublicProperties(): array
105
    {
106
        $class = new ReflectionClass(static::class);
107
108
        $properties = [];
109
        foreach ($class->getProperties(ReflectionProperty::IS_PUBLIC) as $reflectionProperty) {
110
            $properties[$reflectionProperty->getName()] = new Property($reflectionProperty);
111
        }
112
113
        return $properties;
114
    }
115
116
    /**
117
     * Check if property passes the basic conditions.
118
     * @param PropertyContract $property
119
     * @param array $parameters
120
     */
121
    protected function validateProperty(PropertyContract $property, array $parameters): void
122
    {
123
        if (! array_key_exists($property->getName(), $parameters)
124
            && is_null($property->getDefault())
125
            && ! $property->nullable()
126
        ) {
127
            throw new UninitialisedPropertyDtoException($property);
128
        }
129
    }
130
131
    /**
132
     * Set the value if it's present in the array.
133
     * @param PropertyContract $property
134
     * @param array $parameters
135
     */
136
    protected function setPropertyValue(PropertyContract $property, array $parameters): void
137
    {
138
        if (array_key_exists($property->getName(), $parameters)) {
139
            $property->set($parameters[$property->getName()]);
140
        }
141
    }
142
143
    /**
144
     * Set the value if it's present in the array.
145
     * @param PropertyContract $property
146
     */
147
    protected function setPropertyDefaultValue(PropertyContract $property): void
148
    {
149
        $property->setDefault($property->getValueFromReflection($this));
150
    }
151
152
    /**
153
     * Allows to mutate the property before it gets processed.
154
     * @param PropertyContract $property
155
     * @return PropertyContract
156
     */
157
    protected function mutateProperty(PropertyContract $property): PropertyContract
158
    {
159
        return $property;
160
    }
161
162
    /**
163
     * Check if there are additional parameters left.
164
     * Throw error if there are.
165
     * Additional properties are not allowed in a dto.
166
     * @param array $parameters
167
     * @throws UnknownPropertiesDtoException
168
     */
169
    protected function processRemainingProperties(array $parameters)
170
    {
171
        if (count($parameters)) {
172
            throw new UnknownPropertiesDtoException(array_keys($parameters), static::class);
173
        }
174
    }
175
176
    /**
177
     * Immutable behavior
178
     * Throw error if a user tries to set a property.
179
     * @param $name
180
     * @param $value
181
     * @throws ImmutableDtoException|ImmutablePropertyDtoException|PropertyNotFoundDtoException
182
     */
183
    public function __set($name, $value)
184
    {
185
        if ($this->immutable) {
186
            throw new ImmutableDtoException($name);
187
        }
188
        if (! isset($this->properties[$name])) {
189
            throw new PropertyNotFoundDtoException($name, get_class($this));
190
        }
191
192
        if ($this->properties[$name]->immutable()) {
193
            throw new ImmutablePropertyDtoException($name);
194
        }
195
        $this->$name = $value;
196
    }
197
198
    /**
199
     * Proxy through to the properties array.
200
     * @param $name
201
     * @return mixed
202
     */
203
    public function __get($name)
204
    {
205
        return $this->properties[$name]->getValue();
206
    }
207
208
    /**
209
     * @return static
210
     */
211
    public function immutable(): DtoContract
212
    {
213
        if (! $this->isImmutable()) {
214
            $this->setImmutable();
215
        }
216
217
        return $this;
218
    }
219
220
    public function isImmutable(): bool
221
    {
222
        return $this->immutable;
223
    }
224
225
    public function all(): array
226
    {
227
        $data = [];
228
229
        foreach ($this->properties as $property) {
230
            $data[$property->getName()] = $property->getValue();
231
        }
232
233
        return $data;
234
    }
235
236
    public function only(string ...$keys): DtoContract
237
    {
238
        $this->onlyKeys = array_merge($this->onlyKeys, $keys);
239
240
        return $this;
241
    }
242
243
    public function except(string ...$keys): DtoContract
244
    {
245
        foreach ($keys as $key) {
246
            $property = $this->properties[$key] ?? null;
247
            if (isset($property)) {
248
                $property->setVisible(false);
249
            }
250
        }
251
252
        return $this;
253
    }
254
255
    public function toArray(): array
256
    {
257
        $data = $this->all();
258
        $array = [];
259
260
        if (count($this->onlyKeys)) {
261
            $array = array_intersect_key($data, array_flip((array) $this->onlyKeys));
262
        } else {
263
            foreach ($data as $key => $propertyValue) {
264
                if ($this->properties[$key]->isVisible()) {
265
                    $array[$key] = $propertyValue;
266
                }
267
            }
268
        }
269
270
        return $this->parseArray($array);
271
    }
272
273
    protected function parseArray(array $array): array
274
    {
275
        foreach ($array as $key => $value) {
276
            if (
277
                $value instanceof DataTransferObject
278
                || $value instanceof DataTransferObjectCollection
279
            ) {
280
                $array[$key] = $value->toArray();
281
282
                continue;
283
            }
284
285
            if (! is_array($value)) {
286
                continue;
287
            }
288
289
            $array[$key] = $this->parseArray($value);
290
        }
291
292
        return $array;
293
    }
294
}
295