Completed
Push — master ( cec909...bbe7af )
by Jasper
11s queued 10s
created

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