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:17
created

DataTransferObject::except()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

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