Completed
Push — master ( 527079...b8d1ae )
by Jasper
15s
created

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

476
        $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

476
        $relationObject->associate(/** @scrutinizer ignore-type */ $value);
Loading history...
477
478 30
        return $this;
479
    }
480
}
481