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
01:29
created

DataTransferObject::validateProperty()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 4
nc 2
nop 2
dl 0
loc 7
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
    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
        $this->setImmutable();
214
215
        return $this;
216
    }
217
218
    public function all(): array
219
    {
220
        $data = [];
221
222
        foreach ($this->properties as $property) {
223
            $data[$property->getName()] = $property->getValue();
224
        }
225
226
        return $data;
227
    }
228
229
    public function only(string ...$keys): DtoContract
230
    {
231
        $this->onlyKeys = array_merge($this->onlyKeys, $keys);
232
233
        return $this;
234
    }
235
236
    public function except(string ...$keys): DtoContract
237
    {
238
        foreach ($keys as $key) {
239
            $property = $this->properties[$key] ?? null;
240
            if (isset($property)) {
241
                $property->setVisible(false);
242
            }
243
        }
244
245
        return $this;
246
    }
247
248
    public function toArray(): array
249
    {
250
        $data = $this->all();
251
        $array = [];
252
253
        if (count($this->onlyKeys)) {
254
            $array = array_intersect_key($data, array_flip((array) $this->onlyKeys));
255
        } else {
256
            foreach ($data as $key => $propertyValue) {
257
                if ($this->properties[$key]->isVisible()) {
258
                    $array[$key] = $propertyValue;
259
                }
260
            }
261
        }
262
263
        return $this->parseArray($array);
264
    }
265
266
    protected function parseArray(array $array): array
267
    {
268
        foreach ($array as $key => $value) {
269
            if (
270
                $value instanceof DataTransferObject
271
                || $value instanceof DataTransferObjectCollection
272
            ) {
273
                $array[$key] = $value->toArray();
274
275
                continue;
276
            }
277
278
            if (! is_array($value)) {
279
                continue;
280
            }
281
282
            $array[$key] = $this->parseArray($value);
283
        }
284
285
        return $array;
286
    }
287
}
288