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.
Completed
Pull Request — master (#56)
by Arthur
01:17
created

DataTransferObject::__get()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
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
    public function setImmutable(): void
78
    {
79
        if (!$this->isImmutable()) {
80
            $this->immutable = true;
81
            foreach ($this->properties as $property) {
82
                $this->chainPropertiesImmutable($property);
83
            }
84
        }
85
    }
86
87
    protected function chainPropertiesImmutable(PropertyContract $property)
88
    {
89
        $dto = $property->getValue();
90
        if ($dto instanceof DtoContract)
91
            $dto->setImmutable();
92
        elseif (is_iterable($dto)) {
93
            foreach ($dto as $aPotentialDto) {
94
                if ($aPotentialDto instanceof DtoContract)
95
                    $aPotentialDto->setImmutable();
96
            }
97
        }
98
    }
99
100
    /**
101
     * Get all public properties from the current object through reflection.
102
     * @return Property[]
103
     * @throws \ReflectionException
104
     */
105
    protected function getPublicProperties(): array
106
    {
107
        $class = new ReflectionClass(static::class);
108
109
        $properties = [];
110
        foreach ($class->getProperties(ReflectionProperty::IS_PUBLIC) as $reflectionProperty) {
111
            $properties[$reflectionProperty->getName()] = new Property($reflectionProperty);
112
        }
113
114
        return $properties;
115
    }
116
117
    /**
118
     * Check if property passes the basic conditions.
119
     * @param PropertyContract $property
120
     * @param array $parameters
121
     */
122
    protected function validateProperty(PropertyContract $property, array $parameters): void
123
    {
124
        if (!array_key_exists($property->getName(), $parameters)
125
            && is_null($property->getDefault())
126
            && !$property->nullable()
127
        ) {
128
            throw new UninitialisedPropertyDtoException($property);
129
        }
130
    }
131
132
    /**
133
     * Set the value if it's present in the array.
134
     * @param PropertyContract $property
135
     * @param array $parameters
136
     */
137
    protected function setPropertyValue(PropertyContract $property, array $parameters): void
138
    {
139
        if (array_key_exists($property->getName(), $parameters)) {
140
            $property->set($parameters[$property->getName()]);
141
        }
142
    }
143
144
    /**
145
     * Set the value if it's present in the array.
146
     * @param PropertyContract $property
147
     */
148
    protected function setPropertyDefaultValue(PropertyContract $property): void
149
    {
150
        $property->setDefault($property->getValueFromReflection($this));
151
    }
152
153
    /**
154
     * Allows to mutate the property before it gets processed.
155
     * @param PropertyContract $property
156
     * @return PropertyContract
157
     */
158
    protected function mutateProperty(PropertyContract $property): PropertyContract
159
    {
160
        return $property;
161
    }
162
163
    /**
164
     * Check if there are additional parameters left.
165
     * Throw error if there are.
166
     * Additional properties are not allowed in a dto.
167
     * @param array $parameters
168
     * @throws UnknownPropertiesDtoException
169
     */
170
    protected function processRemainingProperties(array $parameters)
171
    {
172
        if (count($parameters)) {
173
            throw new UnknownPropertiesDtoException(array_keys($parameters), static::class);
174
        }
175
    }
176
177
    /**
178
     * Immutable behavior
179
     * Throw error if a user tries to set a property.
180
     * @param $name
181
     * @param $value
182
     * @throws ImmutableDtoException|ImmutablePropertyDtoException|PropertyNotFoundDtoException
183
     */
184
    public function __set($name, $value)
185
    {
186
        if ($this->immutable) {
187
            throw new ImmutableDtoException($name);
188
        }
189
        if (!isset($this->properties[$name])) {
190
            throw new PropertyNotFoundDtoException($name, get_class($this));
191
        }
192
193
        if ($this->properties[$name]->immutable()) {
194
            throw new ImmutablePropertyDtoException($name);
195
        }
196
        $this->$name = $value;
197
    }
198
199
    /**
200
     * Proxy through to the properties array.
201
     * @param $name
202
     * @return mixed
203
     */
204
    public function __get($name)
205
    {
206
        return $this->properties[$name]->getValue();
207
    }
208
209
    /**
210
     * @deprecated
211
     * @param array $data
212
     * @return static
213
     */
214
    public static function immutable(array $data): DtoContract
215
    {
216
        $dto = new static($data);
217
        $dto->setImmutable();
218
        return $dto;
219
    }
220
221
    public function isImmutable(): bool
222
    {
223
        return $this->immutable;
224
    }
225
226
    public function all(): array
227
    {
228
        $data = [];
229
230
        foreach ($this->properties as $property) {
231
            $data[$property->getName()] = $property->getValue();
232
        }
233
234
        return $data;
235
    }
236
237
    public function only(string ...$keys): DtoContract
238
    {
239
        $this->onlyKeys = array_merge($this->onlyKeys, $keys);
240
241
        return $this;
242
    }
243
244
    public function except(string ...$keys): DtoContract
245
    {
246
        foreach ($keys as $key) {
247
            $property = $this->properties[$key] ?? null;
248
            if (isset($property)) {
249
                $property->setVisible(false);
250
            }
251
        }
252
253
        return $this;
254
    }
255
256
    public function toArray(): array
257
    {
258
        $data = $this->all();
259
        $array = [];
260
261
        if (count($this->onlyKeys)) {
262
            $array = array_intersect_key($data, array_flip((array)$this->onlyKeys));
263
        } else {
264
            foreach ($data as $key => $propertyValue) {
265
                if ($this->properties[$key]->isVisible()) {
266
                    $array[$key] = $propertyValue;
267
                }
268
            }
269
        }
270
271
        return $this->parseArray($array);
272
    }
273
274
    protected function parseArray(array $array): array
275
    {
276
        foreach ($array as $key => $value) {
277
            if (
278
                $value instanceof DataTransferObject
279
                || $value instanceof DataTransferObjectCollection
280
            ) {
281
                $array[$key] = $value->toArray();
282
283
                continue;
284
            }
285
286
            if (!is_array($value)) {
287
                continue;
288
            }
289
290
            $array[$key] = $this->parseArray($value);
291
        }
292
293
        return $array;
294
    }
295
}
296