Completed
Pull Request — master (#52)
by Jasper
11:29
created

Item::__set()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 4
c 0
b 0
f 0
nc 2
nop 2
dl 0
loc 9
ccs 0
cts 1
cp 0
crap 6
rs 10
1
<?php
2
3
namespace Swis\JsonApi\Client;
4
5
use Illuminate\Support\Str;
6
use Jenssegers\Model\Model;
7
use Swis\JsonApi\Client\Interfaces\DataInterface;
8
use Swis\JsonApi\Client\Interfaces\ItemInterface;
9
use Swis\JsonApi\Client\Interfaces\ManyRelationInterface;
10
use Swis\JsonApi\Client\Interfaces\OneRelationInterface;
11
use Swis\JsonApi\Client\Relations\HasManyRelation;
12
use Swis\JsonApi\Client\Relations\HasOneRelation;
13
use Swis\JsonApi\Client\Relations\MorphToManyRelation;
14
use Swis\JsonApi\Client\Relations\MorphToRelation;
15
use Swis\JsonApi\Client\Traits\HasLinks;
16
use Swis\JsonApi\Client\Traits\HasMeta;
17
use Swis\JsonApi\Client\Traits\HasType;
18
19
/**
20
 * @property string|null id
21
 */
22
class Item extends Model implements ItemInterface
23
{
24
    use HasLinks;
25
    use HasMeta;
26
    use HasType;
27
28
    /**
29
     * @var string|null
30
     */
31
    protected $id;
32
33
    /**
34
     * Contains the initial values.
35
     *
36
     * @var array
37
     */
38
    protected $initial = [];
39
40
    /**
41
     * @var \Swis\JsonApi\Client\Interfaces\OneRelationInterface[]|\Swis\JsonApi\Client\Interfaces\ManyRelationInterface[]
42
     */
43
    protected $relationships = [];
44
45
    /**
46
     * Available relations need to be explicitly set.
47
     *
48
     * @var array
49
     */
50
    protected $availableRelations = [];
51
52
    /**
53
     * @var array
54
     */
55
    protected $guarded = ['id'];
56
57
    /**
58
     * @return array
59
     */
60 115
    public function toJsonApiArray(): array
61
    {
62
        $data = [
63 115
            'type' => $this->getType(),
64
        ];
65
66 115
        if ($this->hasId()) {
67 70
            $data['id'] = $this->getId();
68
        }
69
70 115
        $attributes = $this->toArray();
71 115
        if (!empty($attributes)) {
72 10
            $data['attributes'] = $attributes;
73
        }
74
75 115
        $relationships = $this->getRelationships();
76 115
        if (!empty($relationships)) {
77 80
            $data['relationships'] = $relationships;
78
        }
79
80 115
        $links = $this->getLinks();
81 115
        if ($links !== null) {
82 5
            $data['links'] = $links->toArray();
83
        }
84
85 115
        $meta = $this->getMeta();
86 115
        if ($meta !== null) {
87 5
            $data['meta'] = $meta->toArray();
88
        }
89
90 115
        return $data;
91
    }
92
93
    /**
94
     * @return bool
95
     */
96 15
    public function isNew(): bool
97
    {
98 15
        return !$this->hasId();
99
    }
100
101
    /**
102
     * @return bool
103
     */
104 140
    public function hasId(): bool
105
    {
106 140
        return isset($this->id);
107
    }
108
109
    /**
110
     * @return string|null
111
     */
112 260
    public function getId(): ? string
113
    {
114 260
        return $this->id;
115
    }
116
117
    /**
118
     * @param string|null $id
119
     *
120
     * @return static
121
     */
122 270
    public function setId(? string $id)
123
    {
124 270
        $this->id = $id;
125
126 270
        return $this;
127
    }
128
129
    /**
130
     * @return array
131
     */
132 120
    public function getRelationships(): array
133
    {
134 120
        $relationships = [];
135
136 120
        foreach ($this->relationships as $name => $relationship) {
137 85
            if ($relationship instanceof OneRelationInterface) {
138 45
                $relationships[$name] = ['data' => null];
139
140 45
                if ($relationship->getIncluded() !== null) {
141 35
                    $relationships[$name] = [
142
                        'data' => [
143 35
                            'type' => $relationship->getIncluded()->getType(),
144 45
                            'id'   => $relationship->getIncluded()->getId(),
145
                        ],
146
                    ];
147
                }
148 40
            } elseif ($relationship instanceof ManyRelationInterface) {
149 40
                $relationships[$name]['data'] = [];
150
151 40
                foreach ($relationship->getIncluded() as $item) {
152 30
                    $relationships[$name]['data'][] =
153
                        [
154 30
                            'type' => $item->getType(),
155 41
                            'id'   => $item->getId(),
156
                        ];
157
                }
158
            }
159
        }
160
161 120
        return $relationships;
162
    }
163
164
    /**
165
     * @return bool
166
     */
167
    public function hasRelationships(): bool
168
    {
169 35
        return !empty($this->getRelationships());
170
    }
171 35
172
    /**
173 35
     * @param string $key
174
     *
175
     * @return mixed
176
     */
177
    public function __get($key)
178
    {
179
        if ($key === 'id') {
180
            return $this->getId();
181
        }
182
183
        return parent::__get($key);
184
    }
185
186
    /**
187
     * @param string $key
188
     *
189
     * @return \Swis\JsonApi\Client\Interfaces\DataInterface|mixed
190
     */
191
    public function getAttribute($key)
192
    {
193
        if ($this->hasAttribute($key) || $this->hasGetMutator($key)) {
194
            return parent::getAttribute($key);
195
        }
196
197
        return $this->getRelationValue($key);
198 35
    }
199 14
200
    /**
201 35
     * @param string $key
202
     *
203 35
     * @return bool
204
     */
205
    public function hasAttribute($key): bool
206
    {
207
        return array_key_exists($key, $this->attributes);
208
    }
209
210
    /**
211
     * @return bool
212
     */
213
    public function hasAttributes(): bool
214
    {
215
        return !empty($this->toArray());
216
    }
217
218
    /**
219
     * @param string $key
220
     * @param mixed  $value
221
     */
222
    public function __set($key, $value)
223
    {
224
        if ($key === 'id') {
225
            $this->setId($value);
226
227
            return;
228
        }
229
230
        parent::__set($key, $value);
231 35
    }
232
233 35
    /**
234 5
     * Get the relationship data.
235
     *
236
     * @param string $key
237 30
     *
238
     * @return \Swis\JsonApi\Client\Interfaces\DataInterface|null
239
     */
240
    public function getRelationValue($key)
241
    {
242
        // If the "attribute" exists as a method on the model, we will just assume
243
        // it is a relationship and will load and return the included items in the relationship
244
        $method = Str::camel($key);
245 55
        if (method_exists($this, $method)) {
246
            return $this->$method()->getIncluded();
247 55
        }
248 35
249
        // If the "attribute" exists as a relationship on the model, we will return
250
        // the included items in the relationship
251 20
        if ($this->hasRelationship($key)) {
252
            return $this->getRelationship($key)->getIncluded();
253
        }
254
255
        return null;
256
    }
257
258
    /**
259 55
     * Determine if an attribute exists on the model.
260
     *
261 55
     * @param string $key
262
     *
263
     * @return bool
264
     */
265
    public function __isset($key)
266
    {
267
        if ($key === 'id') {
268 5
            return $this->hasId();
269
        }
270 5
271 5
        return parent::__isset($key) || $this->hasRelationship($key) || $this->hasRelationship(Str::snake($key));
272
    }
273 5
274
    /**
275
     * @param string $name
276
     *
277
     * @return \Swis\JsonApi\Client\Interfaces\OneRelationInterface|\Swis\JsonApi\Client\Interfaces\ManyRelationInterface
278
     */
279
    public function getRelationship(string $name)
280
    {
281
        return $this->relationships[$name];
282
    }
283
284
    /**
285
     * @param string $name
286 20
     *
287
     * @return bool
288
     */
289
    public function hasRelationship(string $name): bool
290 20
    {
291 20
        return array_key_exists($name, $this->relationships);
292 10
    }
293
294
    /**
295
     * @param $name
296
     *
297 10
     * @return static
298 10
     */
299
    public function removeRelationship(string $name)
300
    {
301
        unset($this->relationships[$name]);
302
303
        return $this;
304
    }
305
306
    /**
307
     * Create a singular relation to another item.
308
     *
309
     * @param string      $class
310
     * @param string|null $relationName
311 5
     *
312
     * @return \Swis\JsonApi\Client\Relations\HasOneRelation
313 5
     */
314 5
    public function hasOne(string $class, string $relationName = null)
315
    {
316
        $relationName = $relationName ?: Str::snake(debug_backtrace()[1]['function']);
317
318
        if (!array_key_exists($relationName, $this->relationships)) {
319
            $this->relationships[$relationName] = new HasOneRelation((new $class())->getType());
320
        }
321
322
        return $this->relationships[$relationName];
323
    }
324
325 80
    /**
326
     * Create a plural relation to another item.
327 80
     *
328
     * @param string      $class
329
     * @param string|null $relationName
330
     *
331
     * @return \Swis\JsonApi\Client\Relations\HasManyRelation
332
     */
333
    public function hasMany(string $class, string $relationName = null)
334
    {
335 25
        $relationName = $relationName ?: Str::snake(debug_backtrace()[1]['function']);
336
337 25
        if (!array_key_exists($relationName, $this->relationships)) {
338
            $this->relationships[$relationName] = new HasManyRelation((new $class())->getType());
339
        }
340
341
        return $this->relationships[$relationName];
342
    }
343
344
    /**
345
     * Create a singular relation to another item.
346
     *
347
     * @param string|null $relationName
348
     *
349
     * @return \Swis\JsonApi\Client\Relations\MorphToRelation
350
     */
351
    public function morphTo(string $relationName = null)
352
    {
353
        $relationName = $relationName ?: Str::snake(debug_backtrace()[1]['function']);
354
355
        if (!array_key_exists($relationName, $this->relationships)) {
356
            $this->relationships[$relationName] = new MorphToRelation();
357
        }
358
359
        return $this->relationships[$relationName];
360 40
    }
361
362 40
    /**
363
     * Create a plural relation to another item.
364 40
     *
365 40
     * @param string|null $relationName
366
     *
367
     * @return \Swis\JsonApi\Client\Relations\MorphToManyRelation
368 40
     */
369
    public function morphToMany(string $relationName = null)
370
    {
371
        $relationName = $relationName ?: Str::snake(debug_backtrace()[1]['function']);
372
373
        if (!array_key_exists($relationName, $this->relationships)) {
374
            $this->relationships[$relationName] = new MorphToManyRelation();
375
        }
376
377
        return $this->relationships[$relationName];
378
    }
379 20
380
    /**
381 20
     * Sets the initial values of an Item.
382
     *
383 20
     * @param array $initial
384 20
     *
385
     * @return static
386
     */
387 20
    public function setInitial(array $initial)
388
    {
389
        $this->initial = $initial;
390
391
        return $this;
392
    }
393
394
    /**
395
     * Returns the initial values of an Item.
396
     *
397 50
     * @param string|null $key
398
     *
399 50
     * @return array|mixed
400
     */
401 50
    public function getInitial($key = null)
402 50
    {
403
        if (null === $key) {
404
            return $this->initial;
405 50
        }
406
407
        return $this->initial[$key];
408
    }
409
410
    /**
411
     * @param string $key
412
     *
413
     * @return bool
414
     */
415 55
    public function hasInitial($key): bool
416
    {
417 55
        return isset($this->getInitial()[$key]);
418
    }
419 55
420 55
    /**
421
     * Prefills the model with values from $initial, when adding new item.
422
     *
423 55
     * @return static
424
     */
425
    public function useInitial()
426
    {
427
        $this->fill($this->initial);
428
429
        return $this;
430
    }
431
432
    /**
433 10
     * @return array
434
     */
435 10
    public function getAvailableRelations(): array
436
    {
437 10
        return $this->availableRelations;
438
    }
439
440
    /**
441
     * Set the specific relationship on the model.
442
     *
443
     * @param string                                        $relation
444
     * @param \Swis\JsonApi\Client\Interfaces\DataInterface $value
445
     * @param \Swis\JsonApi\Client\Links|null               $links
446
     * @param \Swis\JsonApi\Client\Meta|null                $meta
447 5
     *
448
     * @return static
449 5
     */
450 5
    public function setRelation(string $relation, DataInterface $value, Links $links = null, Meta $meta = null)
451
    {
452
        if (method_exists($this, $relation)) {
453
            /** @var \Swis\JsonApi\Client\Interfaces\OneRelationInterface|\Swis\JsonApi\Client\Interfaces\ManyRelationInterface $relationObject */
454
            $relationObject = $this->$relation();
455
        } elseif ($value instanceof Collection) {
456
            $relationObject = $this->morphToMany(Str::snake($relation));
457
        } else {
458
            $relationObject = $this->morphTo(Str::snake($relation));
459
        }
460
461
        $relationObject->associate($value);
0 ignored issues
show
Bug introduced by
It seems like $value can also be of type Swis\JsonApi\Client\Collection; however, parameter $included of Swis\JsonApi\Client\Inte...nInterface::associate() does only seem to accept Swis\JsonApi\Client\Interfaces\ItemInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

461
        $relationObject->associate(/** @scrutinizer ignore-type */ $value);
Loading history...
Bug introduced by
It seems like $value can also be of type Swis\JsonApi\Client\Collection; however, parameter $included of Swis\JsonApi\Client\Rela...neRelation::associate() does only seem to accept Swis\JsonApi\Client\Interfaces\ItemInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

461
        $relationObject->associate(/** @scrutinizer ignore-type */ $value);
Loading history...
462
        $relationObject->setLinks($links);
463
        $relationObject->setMeta($meta);
464
465
        return $this;
466
    }
467
468
    /**
469
     * @return array
470
     */
471 5
    public function getRelations(): array
472
    {
473 5
        return $this->relationships;
474
    }
475
}
476