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