Passed
Push — master ( af341e...2b2ec9 )
by Jonas
07:18 queued 05:16
created

appendToDeepRelationship()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 28
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 15
c 1
b 0
f 0
nc 2
nop 4
dl 0
loc 28
ccs 15
cts 15
cp 1
crap 3
rs 9.7666
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 68
    public function appendToDeepRelationship(array $through, array $foreignKeys, array $localKeys, int $position): array
26
    {
27 68
        if ($position === 0) {
28 38
            $foreignKeys[] = function (Builder $query, Builder $parentQuery = null) {
29 23
                if ($parentQuery) {
30 10
                    $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 23
                $this->mergeWhereConstraints($query, $this->query);
34
            };
35
36 38
            $localKeys[] = $this->localKey;
37
        } else {
38 30
            $foreignKeys[] = function (Builder $query, JoinClause $join) {
39 30
                [$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 30
                $query->addBinding($bindings, 'join');
42
43 30
                $join->whereJsonContains(
44 30
                    $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

44
                    $this->/** @scrutinizer ignore-call */ 
45
                           getQualifiedPath(),
Loading history...
45 30
                    $query->getQuery()->connection->raw($sql)
46
                );
47
            };
48
49 30
            $localKeys[] = null;
50
        }
51
52 68
        return [$through, $foreignKeys, $localKeys];
53
    }
54
55
    /**
56
     * Get the custom through key for an eager load of the relation.
57
     *
58
     * @param string $alias
59
     * @return \Illuminate\Database\Query\Expression
60
     */
61 28
    public function getThroughKeyForDeepRelationships(string $alias): Expression
62
    {
63 28
        $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

63
        $throughKey = $this->/** @scrutinizer ignore-call */ getJsonGrammar($this->query)->compileJsonValueSelect($this->path);
Loading history...
64
65 28
        $alias = $this->query->getQuery()->grammar->wrap($alias);
66
67 28
        return new Expression("$throughKey as $alias");
68
    }
69
70
    /**
71
     * Match the eagerly loaded results for a deep relationship to their parents.
72
     *
73
     * @param array $models
74
     * @param \Illuminate\Database\Eloquent\Collection $results
75
     * @param string $relation
76
     * @return array
77
     */
78 15
    public function matchResultsForDeepRelationship(array $models, Collection $results, string $relation): array
79
    {
80 15
        $dictionary = $this->buildDictionaryForDeepRelationship($results);
81
82 15
        foreach ($models as $model) {
83 15
            $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

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