appendToDeepRelationship()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 29
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 16
nc 2
nop 4
dl 0
loc 29
rs 9.7333
c 1
b 0
f 0
1
<?php
2
3
namespace Staudenmeir\EloquentJsonRelations\Relations\Traits\Concatenation;
4
5
use Illuminate\Database\Eloquent\Builder;
6
use Illuminate\Database\Eloquent\Collection;
7
use Illuminate\Database\Eloquent\Model;
8
use Illuminate\Database\Query\Expression;
9
use Illuminate\Database\Query\JoinClause;
10
use Illuminate\Support\Arr;
11
12
trait IsConcatenableHasManyJsonRelation
13
{
14
    use IsConcatenableRelation;
15
16
    /**
17
     * Append the relation's through parents, foreign and local keys to a deep relationship.
18
     *
19
     * @param \Illuminate\Database\Eloquent\Model[] $through
20
     * @param array $foreignKeys
21
     * @param array $localKeys
22
     * @param int $position
23
     * @return array
24
     */
25
    public function appendToDeepRelationship(array $through, array $foreignKeys, array $localKeys, int $position): array
26
    {
27
        if ($position === 0) {
28
            $foreignKeys[] = function (Builder $query, ?Builder $parentQuery = null) {
29
                if ($parentQuery) {
30
                    $this->getRelationExistenceQuery($this->query, $parentQuery);
0 ignored issues
show
Bug introduced by
It seems like getRelationExistenceQuery() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

30
                    $this->/** @scrutinizer ignore-call */ 
31
                           getRelationExistenceQuery($this->query, $parentQuery);
Loading history...
31
                }
32
33
                $this->mergeWhereConstraints($query, $this->query);
34
            };
35
36
            $localKeys[] = $this->localKey;
37
        } else {
38
            $foreignKeys[] = function (Builder $query, JoinClause $join) {
39
                [$sql, $bindings] = $this->relationExistenceQueryParentKey($query);
0 ignored issues
show
Bug introduced by
It seems like relationExistenceQueryParentKey() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

39
                /** @scrutinizer ignore-call */ 
40
                [$sql, $bindings] = $this->relationExistenceQueryParentKey($query);
Loading history...
40
41
                $query->addBinding($bindings, 'join');
42
43
                $this->whereJsonContainsOrMemberOf(
0 ignored issues
show
Bug introduced by
It seems like whereJsonContainsOrMemberOf() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

43
                $this->/** @scrutinizer ignore-call */ 
44
                       whereJsonContainsOrMemberOf(
Loading history...
44
                    $join,
45
                    $this->getQualifiedPath(),
0 ignored issues
show
Bug introduced by
It seems like getQualifiedPath() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

45
                    $this->/** @scrutinizer ignore-call */ 
46
                           getQualifiedPath(),
Loading history...
46
                    $query->getQuery()->connection->raw($sql)
47
                );
48
            };
49
50
            $localKeys[] = null;
51
        }
52
53
        return [$through, $foreignKeys, $localKeys];
54
    }
55
56
    /**
57
     * Get the custom through key for an eager load of the relation.
58
     *
59
     * @param string $alias
60
     * @return \Illuminate\Database\Query\Expression
61
     */
62
    public function getThroughKeyForDeepRelationships(string $alias): Expression
63
    {
64
        $throughKey = $this->getJsonGrammar($this->query)->compileJsonValueSelect($this->path);
0 ignored issues
show
Bug introduced by
It seems like getJsonGrammar() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

64
        $throughKey = $this->/** @scrutinizer ignore-call */ getJsonGrammar($this->query)->compileJsonValueSelect($this->path);
Loading history...
65
66
        $alias = $this->query->getQuery()->grammar->wrap($alias);
67
68
        return new Expression("$throughKey as $alias");
69
    }
70
71
    /**
72
     * Match the eagerly loaded results for a deep relationship to their parents.
73
     *
74
     * @param array $models
75
     * @param \Illuminate\Database\Eloquent\Collection $results
76
     * @param string $relation
77
     * @param string $type
78
     * @return array
79
     */
80
    public function matchResultsForDeepRelationship(
81
        array $models,
82
        Collection $results,
83
        string $relation,
84
        string $type = 'many'
85
    ): array {
86
        $dictionary = $this->buildDictionaryForDeepRelationship($results);
87
88
        foreach ($models as $model) {
89
            $key = $this->getDictionaryKey($model->{$this->localKey});
0 ignored issues
show
Bug introduced by
It seems like getDictionaryKey() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

89
            /** @scrutinizer ignore-call */ 
90
            $key = $this->getDictionaryKey($model->{$this->localKey});
Loading history...
90
91
            if (isset($dictionary[$key])) {
92
                $value = $dictionary[$key];
93
94
                $value = $type === 'one'
95
                    ? (reset($value) ?: null)
96
                    : $this->related->newCollection($value);
97
98
                $model->setRelation($relation, $value);
99
            }
100
        }
101
102
        return $models;
103
    }
104
105
    /**
106
     * Build the model dictionary for a deep relation.
107
     *
108
     * @param \Illuminate\Database\Eloquent\Collection $results
109
     * @return array
110
     */
111
    protected function buildDictionaryForDeepRelationship(Collection $results): array
112
    {
113
        $dictionary = [];
114
115
        $key = $this->key ? str_replace('->', '.', $this->key) : null;
116
117
        foreach ($results as $result) {
118
            $values = json_decode($result->laravel_through_key, true);
119
120
            if ($key) {
121
                $values = array_filter(
122
                    Arr::pluck($values, $key),
123
                    fn ($value) => $value !== null
124
                );
125
            }
126
127
            foreach ($values as $value) {
128
                $dictionary[$value][] = $result;
129
            }
130
        }
131
132
        return $dictionary;
133
    }
134
}
135