Completed
Push — master ( f2d77a...6972d7 )
by Jasper
11s
created

Item::setType()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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

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

468
        $relationObject->associate(/** @scrutinizer ignore-type */ $value);
Loading history...
469 15
        $relationObject->setLinks($links);
470 20
        $relationObject->setMeta($meta);
471 10
472
        return $this;
473 15
    }
474
}
475