Passed
Push — master ( a0a8dd...2952d5 )
by Jonas
10:46
created

getRelationExistenceQueryForSelfRelation()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 27
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 14
c 1
b 0
f 0
dl 0
loc 27
ccs 13
cts 13
cp 1
rs 9.7998
cc 3
nc 4
nop 2
crap 3
1
<?php
2
3
namespace Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Graph;
4
5
use Illuminate\Database\Eloquent\Builder;
6
use Illuminate\Database\Eloquent\Collection;
7
use Illuminate\Database\Eloquent\Model;
8
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
9
use Illuminate\Database\Query\Expression;
10
use Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Graph\Traits\IsRecursiveRelation;
11
12
class Descendants extends BelongsToMany
13
{
14
    use IsRecursiveRelation {
15
        buildDictionary as baseBuildDictionary;
16
    }
17
18
    /**
19
     * Set the base constraints on the relation query.
20
     *
21
     * @return void
22
     */
23 123
    public function addConstraints()
24
    {
25 123
        if (static::$constraints) {
26 61
            $column = $this->andSelf ? $this->getQualifiedParentKeyName() : $this->getQualifiedForeignPivotKeyName();
27
28 61
            $constraint = function (Builder $query) use ($column) {
29 61
                $query->where(
30
                    $column,
31
                    '=',
32 61
                    $this->parent->{$this->parentKey}
33
                );
34
            };
35
36 61
            $this->addExpression($constraint);
37
        }
38
    }
39
40
    /**
41
     * Set the constraints for an eager load of the relation.
42
     *
43
     * @param array $models
44
     * @return void
45
     */
46 32
    public function addEagerConstraints(array $models)
47
    {
48 32
        $whereIn = $this->whereInMethod($this->parent, $this->parentKey);
49
50 32
        $column = $this->andSelf ? $this->getQualifiedParentKeyName() : $this->getQualifiedForeignPivotKeyName();
51
52 32
        $keys = $this->getKeys($models, $this->parentKey);
53
54 32
        $constraint = function (Builder $query) use ($models, $whereIn, $column, $keys) {
0 ignored issues
show
Unused Code introduced by
The import $models is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
55 32
            $query->$whereIn($column, $keys);
56
        };
57
58 32
        $this->addExpression($constraint, null, null, $this->andSelf ? 'unionAll' : 'union');
59
    }
60
61
    /**
62
     * Build model dictionary.
63
     *
64
     * @param \Illuminate\Database\Eloquent\Collection $results
65
     * @return array
66
     */
67 32
    protected function buildDictionary(Collection $results)
68
    {
69 32
        if ($this->andSelf) {
70 16
            return $this->baseBuildDictionary($results);
71
        }
72
73 16
        $dictionary = [];
74
75 16
        $depthName = $this->related->getDepthName();
76
77 16
        $firstLevelResults = $results->where($depthName, '=', 1)->groupBy($this->parentKey);
78
79 16
        foreach ($results as $result) {
80 16
            $keys = [];
81
82 16
            if ($result->$depthName > 1) {
83 16
                foreach ($firstLevelResults[$result->getFirstPathSegment()] as $model) {
84 16
                    $keys[] = $model->{$this->accessor}->{$this->foreignPivotKey};
85
                }
86
            } else {
87 16
                $keys[] = $result->{$this->accessor}->{$this->foreignPivotKey};
88
            }
89
90 16
            foreach ($keys as $key) {
91 16
                if (!isset($dictionary[$key])) {
92 16
                    $dictionary[$key] = [];
93
                }
94
95 16
                $dictionary[$key][] = $result;
96
            }
97
        }
98
99 16
        return $dictionary;
100
    }
101
102
    /**
103
     * Add the constraints for a relationship query.
104
     *
105
     * @param \Illuminate\Database\Eloquent\Builder $query
106
     * @param \Illuminate\Database\Eloquent\Builder $parentQuery
107
     * @param array|mixed $columns
108
     * @return \Illuminate\Database\Eloquent\Builder
109
     */
110 30
    public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*'])
111
    {
112 30
        if ($query->getQuery()->from === $parentQuery->getQuery()->from) {
113 12
            return $this->getRelationExistenceQueryForSelfRelation($query, $columns);
114
        }
115
116 18
        $first = $this->andSelf
117 9
            ? $query->getQuery()->from . '.' . $this->parentKey
118 9
            : $this->getQualifiedForeignPivotKeyName();
119
120 18
        $constraint = function (Builder $query) use ($first) {
121 18
            $query->whereColumn(
122
                $first,
123
                '=',
124 18
                $this->getQualifiedParentKeyName()
125
            );
126
        };
127
128 18
        return $this->addExpression($constraint, $query->select($columns));
0 ignored issues
show
Bug introduced by
It seems like $query->select($columns) can also be of type Illuminate\Database\Query\Builder; however, parameter $query of Staudenmeir\LaravelAdjac...ndants::addExpression() does only seem to accept Illuminate\Database\Eloquent\Builder|null, maybe add an additional type check? ( Ignorable by Annotation )

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

128
        return $this->addExpression($constraint, /** @scrutinizer ignore-type */ $query->select($columns));
Loading history...
129
    }
130
131
    /**
132
     * Add the constraints for a relationship query on the same table.
133
     *
134
     * @param \Illuminate\Database\Eloquent\Builder $query
135
     * @param array|mixed $columns
136
     * @return \Illuminate\Database\Eloquent\Builder
137
     */
138 12
    public function getRelationExistenceQueryForSelfRelation(
139
        Builder $query,
140
        $columns = ['*']
141
    ): Builder {
142 12
        if ($columns instanceof Expression) {
143 9
            $columns = $this->replaceTableHash($query, $columns);
144
        }
145
146 12
        $table = $this->getRelationCountHash();
147
148 12
        $from = $query->getModel()->getTable() . ' as ' . $table;
149
150 12
        $query->getModel()->setTable($table);
151
152 12
        $first = $this->andSelf
153 6
            ? "$table.$this->parentKey"
154 6
            : "$this->table.$this->foreignPivotKey";
155
156 12
        $constraint = function (Builder $query) use ($first) {
157 12
            $query->whereColumn(
158
                $first,
159
                '=',
160 12
                $this->getQualifiedParentKeyName()
161
            );
162
        };
163
164 12
        return $this->addExpression($constraint, $query->select($columns), $from);
0 ignored issues
show
Bug introduced by
It seems like $query->select($columns) can also be of type Illuminate\Database\Query\Builder; however, parameter $query of Staudenmeir\LaravelAdjac...ndants::addExpression() does only seem to accept Illuminate\Database\Eloquent\Builder|null, maybe add an additional type check? ( Ignorable by Annotation )

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

164
        return $this->addExpression($constraint, /** @scrutinizer ignore-type */ $query->select($columns), $from);
Loading history...
165
    }
166
167
    /**
168
     * Add a recursive expression to the query.
169
     *
170
     * @param callable $constraint
171
     * @param \Illuminate\Database\Eloquent\Builder|null $query
172
     * @param string|null $from
173
     * @param string $union
174
     * @return \Illuminate\Database\Eloquent\Builder
175
     */
176 123
    protected function addExpression(
177
        callable $constraint,
178
        Builder $query = null,
179
        string $from = null,
180
        string $union = 'unionAll'
181
    ): Builder {
182 123
        $query = $query ?: $this->query;
183
184 123
        $initialDepth = $this->andSelf ? 0 : 1;
185
186 123
        return $query->withRelationshipExpression('desc', $constraint, $initialDepth, $from, null, $union);
187
    }
188
}
189