Completed
Pull Request — master (#20)
by Jasper
05:44
created

JenssegersItem   F

Complexity

Total Complexity 62

Size/Duplication

Total Lines 452
Duplicated Lines 0 %

Test Coverage

Coverage 82.35%

Importance

Changes 0
Metric Value
wmc 62
dl 0
loc 452
ccs 112
cts 136
cp 0.8235
rs 3.44
c 0
b 0
f 0

25 Methods

Rating   Name   Duplication   Size   Complexity  
B getIncluded() 0 32 10
A hasAttribute() 0 3 1
A useInitial() 0 5 1
A setId() 0 5 1
A getAttribute() 0 7 3
A getId() 0 3 1
A hasOne() 0 10 3
B getRelationships() 0 44 8
A setInitial() 0 5 1
A morphToMany() 0 9 3
A isNew() 0 3 1
A hasMany() 0 10 3
A hasRelationship() 0 3 1
A getRelationValue() 0 13 3
A setType() 0 5 1
A getAvailableRelations() 0 3 1
A __isset() 0 6 4
A getRelationship() 0 3 1
A hasInitial() 0 3 1
A getType() 0 3 1
A getInitial() 0 7 2
A morphTo() 0 9 3
A setRelation() 0 16 3
A toJsonApiArray() 0 21 4
A hasId() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like JenssegersItem often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use JenssegersItem, and based on these observations, apply Extract Interface, too.

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