|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
declare(strict_types=1); |
|
4
|
|
|
|
|
5
|
|
|
namespace Rinvex\Attributes\Support; |
|
6
|
|
|
|
|
7
|
|
|
use Closure; |
|
8
|
|
|
use Rinvex\Attributes\Models\Attribute; |
|
9
|
|
|
use Illuminate\Database\Eloquent\Model as Entity; |
|
10
|
|
|
|
|
11
|
|
|
class RelationBuilder |
|
12
|
|
|
{ |
|
13
|
|
|
/** |
|
14
|
|
|
* Build the relations for the entity attributes. |
|
15
|
|
|
* |
|
16
|
|
|
* @param \Illuminate\Database\Eloquent\Model $entity |
|
17
|
|
|
* |
|
18
|
|
|
* @return void |
|
19
|
|
|
*/ |
|
20
|
|
|
public function build(Entity $entity): void |
|
21
|
|
|
{ |
|
22
|
|
|
$attributes = $entity->getEntityAttributes(); |
|
23
|
|
|
|
|
24
|
|
|
// We will manually add a relationship for every attribute registered |
|
25
|
|
|
// of this entity. Once we know the relation method we have to use, |
|
26
|
|
|
// we will just add it to the entityAttributeRelations property. |
|
27
|
|
|
foreach ($attributes as $attribute) { |
|
28
|
|
|
$relation = $this->getRelationClosure($entity, $attribute); |
|
29
|
|
|
|
|
30
|
|
|
$entity->setEntityAttributeRelation((string) ($attribute->getAttributes()['slug'] ?? null), $relation); |
|
31
|
|
|
} |
|
32
|
|
|
} |
|
33
|
|
|
|
|
34
|
|
|
/** |
|
35
|
|
|
* Generate the entity attribute relation closure. |
|
36
|
|
|
* |
|
37
|
|
|
* @param \Illuminate\Database\Eloquent\Model $entity |
|
38
|
|
|
* @param \Rinvex\Attributes\Models\Attribute $attribute |
|
39
|
|
|
* |
|
40
|
|
|
* @return \Closure |
|
41
|
|
|
*/ |
|
42
|
|
|
protected function getRelationClosure(Entity $entity, Attribute $attribute): Closure |
|
43
|
|
|
{ |
|
44
|
|
|
$method = (bool) ($attribute->getAttributes()['is_collection'] ?? null) ? 'hasMany' : 'hasOne'; |
|
45
|
|
|
|
|
46
|
|
|
// This will return a closure fully binded to the current entity instance, |
|
47
|
|
|
// which will help us to simulate any relation as if it was made in the |
|
48
|
|
|
// original entity class definition using a function statement. |
|
49
|
|
|
return Closure::bind(function () use ($entity, $attribute, $method) { |
|
50
|
|
|
$relation = $entity->{$method}(Attribute::getTypeModel($attribute->getAttribute('type')), 'entity_id', $entity->getKeyName()); |
|
51
|
|
|
|
|
52
|
|
|
// Since an attribute could be attached to multiple entities, then values could have |
|
53
|
|
|
// same entity ID, but for different entity types, so we need to add type where |
|
54
|
|
|
// clause to fetch only values related to the given entity ID + entity type. |
|
55
|
|
|
$relation->where('entity_type', $entity->getMorphClass()); |
|
56
|
|
|
|
|
57
|
|
|
// We add a where clause in order to fetch only the elements that are |
|
58
|
|
|
// related to the given attribute. If no condition is set, it will |
|
59
|
|
|
// fetch all the value rows related to the current entity. |
|
60
|
|
|
return $relation->where($attribute->getForeignKey(), $attribute->getKey()); |
|
61
|
|
|
}, $entity, get_class($entity)); |
|
62
|
|
|
} |
|
63
|
|
|
} |
|
64
|
|
|
|