Passed
Push — master ( 97d537...c37a03 )
by Jasper
10:30 queued 07:13
created

Item::hasAttributes()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
3
namespace Swis\JsonApi\Client;
4
5
use ArrayAccess;
6
use Illuminate\Contracts\Support\Arrayable;
7
use Illuminate\Contracts\Support\Jsonable;
8
use JsonSerializable;
9
use Swis\JsonApi\Client\Exceptions\MassAssignmentException;
10
use Swis\JsonApi\Client\Interfaces\ItemInterface;
11
use Swis\JsonApi\Client\Interfaces\ManyRelationInterface;
12
use Swis\JsonApi\Client\Interfaces\OneRelationInterface;
13
14
/**
15
 * @property string|null id
16
 */
17
class Item implements ArrayAccess, Arrayable, Jsonable, JsonSerializable, ItemInterface
18
{
19
    use Concerns\GuardsAttributes;
20
    use Concerns\HasAttributes;
21
    use Concerns\HasId;
22
    use Concerns\HasInitial;
23
    use Concerns\HasLinks;
24
    use Concerns\HasMeta;
25
    use Concerns\HasRelations;
26
    use Concerns\HasType;
27
    use Concerns\HidesAttributes;
28
29
    /**
30
     * Available relations need to be explicitly set.
31
     *
32
     * @var array
33
     */
34
    protected $availableRelations = [];
35
36
    /**
37
     * Create a new Item instance.
38
     *
39
     * @param array $attributes
40
     *
41
     * @return void
42
     */
43 516
    public function __construct(array $attributes = [])
44
    {
45 516
        $this->fill($attributes);
46 516
    }
47
48
    /**
49
     * Fill the model with an array of attributes.
50
     *
51
     * @param array $attributes
52
     *
53
     * @throws \Swis\JsonApi\Client\Exceptions\MassAssignmentException
54
     *
55
     * @return $this
56
     */
57 516
    public function fill(array $attributes)
58
    {
59 516
        $totallyGuarded = $this->totallyGuarded();
60
61 516
        foreach ($this->fillableFromArray($attributes) as $key => $value) {
62
            // The developers may choose to place some attributes in the "fillable" array
63
            // which means only those attributes may be set through mass assignment to
64
            // the model, and all others will just get ignored for security reasons.
65 177
            if ($this->isFillable($key)) {
66 150
                $this->setAttribute($key, $value);
67 39
            } elseif ($totallyGuarded) {
68 3
                throw new MassAssignmentException(sprintf('Add [%s] to fillable property to allow mass assignment on [%s].', $key, get_class($this)));
69
            }
70
        }
71
72 516
        return $this;
73
    }
74
75
    /**
76
     * Fill the model with an array of attributes. Force mass assignment.
77
     *
78
     * @param array $attributes
79
     *
80
     * @return $this
81
     */
82 3
    public function forceFill(array $attributes)
83
    {
84
        return static::unguarded(function () use ($attributes) {
85 3
            return $this->fill($attributes);
86 3
        });
87
    }
88
89
    /**
90
     * Create a new instance of the given model.
91
     *
92
     * @param array $attributes
93
     *
94
     * @return static
95
     */
96 6
    public function newInstance(array $attributes = [])
97
    {
98 6
        $model = new static($attributes);
99
100 6
        $model->mergeCasts($this->casts);
101
102 6
        return $model;
103
    }
104
105
    /**
106
     * Create a list of models from plain arrays.
107
     *
108
     * @param array $items
109
     *
110
     * @return array
111
     */
112 3
    public static function hydrate(array $items): array
113
    {
114 3
        $instance = new static();
115
116
        return array_map(static function ($item) use ($instance) {
117 3
            return $instance->newInstance($item);
118 3
        }, $items);
119
    }
120
121
    /**
122
     * @return array
123
     */
124 96
    public function toJsonApiArray(): array
125
    {
126
        $data = [
127 96
            'type' => $this->getType(),
128
        ];
129
130 96
        if ($this->hasId()) {
131 54
            $data['id'] = $this->getId();
132
        }
133
134 96
        $attributes = $this->toArray();
135 96
        if (!empty($attributes)) {
136 6
            $data['attributes'] = $attributes;
137
        }
138
139 96
        $relationships = $this->getRelationships();
140 96
        if (!empty($relationships)) {
141 63
            $data['relationships'] = $relationships;
142
        }
143
144 96
        $links = $this->getLinks();
145 96
        if ($links !== null) {
146 3
            $data['links'] = $links->toArray();
147
        }
148
149 96
        $meta = $this->getMeta();
150 96
        if ($meta !== null) {
151 3
            $data['meta'] = $meta->toArray();
152
        }
153
154 96
        return $data;
155
    }
156
157
    /**
158
     * Convert the model instance to JSON.
159
     *
160
     * @param int $options
161
     *
162
     * @return string
163
     */
164 3
    public function toJson($options = 0)
165
    {
166 3
        return json_encode($this->jsonSerialize(), $options);
167
    }
168
169
    /**
170
     * Convert the object into something JSON serializable.
171
     *
172
     * @return array
173
     */
174 6
    public function jsonSerialize()
175
    {
176 6
        return $this->toArray();
177
    }
178
179
    /**
180
     * Convert the model instance to an array.
181
     *
182
     * @return array
183
     */
184 135
    public function toArray()
185
    {
186 135
        return $this->attributesToArray();
187
    }
188
189
    /**
190
     * Clone the model into a new, non-existing instance.
191
     *
192
     * @param array|null $except
193
     *
194
     * @return static
195
     */
196 3
    public function replicate(array $except = null)
197
    {
198 3
        $attributes = Util::arrayExcept($this->getAttributes(), $except ?? []);
199
200 3
        return new static($attributes);
201
    }
202
203
    /**
204
     * @return bool
205
     */
206 9
    public function isNew(): bool
207
    {
208 9
        return !$this->hasId();
209
    }
210
211
    /**
212
     * @return bool
213
     */
214 24
    public function hasAttributes(): bool
215
    {
216 24
        return !empty($this->toArray());
217
    }
218
219
    /**
220
     * @param string $key
221
     *
222
     * @return bool
223
     */
224 120
    public function hasAttribute($key): bool
225
    {
226 120
        return array_key_exists($key, $this->attributes);
227
    }
228
229
    /**
230
     * @return array
231
     */
232 75
    public function getAvailableRelations(): array
233
    {
234 75
        return $this->availableRelations;
235
    }
236
237
    /**
238
     * @return array
239
     */
240 108
    public function getRelationships(): array
241
    {
242 108
        $relationships = [];
243
244 108
        foreach ($this->getRelations() as $name => $relation) {
245 84
            if (!$relation->hasIncluded()) {
246 12
                continue;
247
            }
248
249 72
            if ($relation instanceof OneRelationInterface) {
250 42
                $relationships[$name]['data'] = null;
251
252 42
                if ($relation->getIncluded() !== null) {
253 30
                    $relationships[$name]['data'] = [
254 30
                        'type' => $relation->getIncluded()->getType(),
255 30
                        'id' => $relation->getIncluded()->getId(),
256
                    ];
257 30
                    if ($relation->getIncluded()->getMeta()) {
258 42
                        $relationships[$name]['data']['meta'] = $relation->getIncluded()->getMeta()->toArray();
259
                    }
260
                }
261 33
            } elseif ($relation instanceof ManyRelationInterface) {
262 33
                $relationships[$name]['data'] = [];
263
264 33
                foreach ($relation->getIncluded() as $item) {
265
                    $data = [
266 21
                        'type' => $item->getType(),
267 21
                        'id' => $item->getId(),
268
                    ];
269 21
                    if ($item->getMeta()) {
270 3
                        $data['meta'] = $item->getMeta()->toArray();
271
                    }
272 21
                    $relationships[$name]['data'][] = $data;
273
                }
274
            }
275
276 72
            $links = $relation->getLinks();
277 72
            if ($links !== null) {
278 12
                $relationships[$name]['links'] = $links->toArray();
279
            }
280
281 72
            $meta = $relation->getMeta();
282 72
            if ($meta !== null) {
283 12
                $relationships[$name]['meta'] = $meta->toArray();
284
            }
285
        }
286
287 108
        return $relationships;
288
    }
289
290
    /**
291
     * @return bool
292
     */
293 9
    public function hasRelationships(): bool
294
    {
295 9
        return !empty($this->getRelationships());
296
    }
297
298
    /**
299
     * Fills the model with the values from $initial. This is useful for setting defaults when creating a new item.
300
     *
301
     * @return static
302
     */
303 3
    public function useInitial()
304
    {
305 3
        $this->fill($this->initial);
306
307 3
        return $this;
308
    }
309
310
    /**
311
     * Dynamically retrieve attributes on the model.
312
     *
313
     * @param string $key
314
     *
315
     * @return mixed
316
     */
317 36
    public function __get(string $key)
318
    {
319 36
        return $this->offsetGet($key);
320
    }
321
322
    /**
323
     * Dynamically set attributes on the model.
324
     *
325
     * @param string $key
326
     * @param mixed  $value
327
     *
328
     * @return void
329
     */
330 51
    public function __set(string $key, $value)
331
    {
332 51
        $this->offsetSet($key, $value);
333 51
    }
334
335
    /**
336
     * Determine if the given attribute exists.
337
     *
338
     * @param mixed $offset
339
     *
340
     * @return bool
341
     */
342 9
    public function offsetExists($offset)
343
    {
344 9
        if ($offset === 'id') {
345 3
            return $this->hasId();
346
        }
347
348 6
        return !is_null($this->getAttribute($offset));
349
    }
350
351
    /**
352
     * Get the value for a given offset.
353
     *
354
     * @param mixed $offset
355
     *
356
     * @return mixed
357
     */
358 36
    public function offsetGet($offset)
359
    {
360 36
        if ($offset === 'id') {
361 3
            return $this->getId();
362
        }
363
364 33
        return $this->getAttribute($offset);
365
    }
366
367
    /**
368
     * Set the value for a given offset.
369
     *
370
     * @param mixed $offset
371
     * @param mixed $value
372
     *
373
     * @return void
374
     */
375 51
    public function offsetSet($offset, $value)
376
    {
377 51
        if ($offset === 'id') {
378 6
            $this->setId($value);
379
380 6
            return;
381
        }
382
383 45
        $this->setAttribute($offset, $value);
384 45
    }
385
386
    /**
387
     * Unset the value for a given offset.
388
     *
389
     * @param mixed $offset
390
     *
391
     * @return void
392
     */
393 9
    public function offsetUnset($offset)
394
    {
395 9
        if ($offset === 'id') {
396 3
            $this->id = null;
397
        }
398
399 9
        unset($this->attributes[$offset], $this->relations[$offset]);
400 9
    }
401
402
    /**
403
     * Determine if an attribute or relation exists on the model.
404
     *
405
     * @param string $key
406
     *
407
     * @return bool
408
     */
409 9
    public function __isset(string $key)
410
    {
411 9
        return $this->offsetExists($key);
412
    }
413
414
    /**
415
     * Unset an attribute on the model.
416
     *
417
     * @param string $key
418
     *
419
     * @return void
420
     */
421 9
    public function __unset(string $key)
422
    {
423 9
        $this->offsetUnset($key);
424 9
    }
425
426
    /**
427
     * Convert the model to its string representation.
428
     *
429
     * @return string
430
     */
431 3
    public function __toString()
432
    {
433 3
        return $this->toJson();
434
    }
435
}
436