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:52 queued 35s
created

DataTransferObject::boot()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

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