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