RelationBuilder   A
last analyzed

Complexity

Total Complexity 4

Size/Duplication

Total Lines 53
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
wmc 4
lcom 1
cbo 2
dl 0
loc 53
rs 10
c 0
b 0
f 0

2 Methods

Rating   Name   Duplication   Size   Complexity  
A build() 0 13 2
A getRelationClosure() 0 21 2
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