Ancestors::addEagerConstraints()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 2
c 1
b 0
f 0
dl 0
loc 5
ccs 1
cts 1
cp 1
rs 10
cc 2
nc 2
nop 1
crap 2
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\Relations\BelongsToMany;
8
use Illuminate\Database\Query\Expression;
9
use Staudenmeir\EloquentHasManyDeepContracts\Interfaces\ConcatenableRelation;
10
use Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Graph\Traits\Concatenation\IsConcatenableAncestorsRelation;
11
use Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Graph\Traits\IsRecursiveRelation;
12
13
/**
14
 * @template TRelatedModel of \Illuminate\Database\Eloquent\Model
15
 * @extends BelongsToMany<TRelatedModel>
16
 */
17
class Ancestors extends BelongsToMany implements ConcatenableRelation
18
{
19
    use IsConcatenableAncestorsRelation;
0 ignored issues
show
introduced by
The trait Staudenmeir\LaravelAdjac...enableAncestorsRelation requires some properties which are not provided by Staudenmeir\LaravelAdjac...lations\Graph\Ancestors: $laravel_through_key, $laravel_through_key_pivot_id
Loading history...
20
    use IsRecursiveRelation {
21
        buildDictionary as baseBuildDictionary;
22
    }
23
24
    /**
25
     * Set the base constraints on the relation query.
26 128
     *
27
     * @return void
28 128
     */
29 66
    public function addConstraints()
30
    {
31 66
        if (static::$constraints) {
32 66
            $column = $this->andSelf ? $this->getQualifiedParentKeyName() : $this->getQualifiedRelatedPivotKeyName();
33 66
34 66
            $constraint = function (Builder $query) use ($column) {
35 66
                $query->where(
36 66
                    $column,
37 66
                    '=',
38
                    $this->parent->{$this->parentKey}
39 66
                );
40
            };
41
42
            $this->addExpression($constraint);
43
        }
44
    }
45
46
    /**
47
     * Set the constraints for an eager load of the relation.
48
     *
49 44
     * @param array $models
50
     * @return void
51 44
     */
52
    public function addEagerConstraints(array $models)
53 44
    {
54
        $column = $this->andSelf ? $this->getQualifiedParentKeyName() : $this->getQualifiedRelatedPivotKeyName();
55
56
        $this->addEagerExpression($models, $column);
57
    }
58
59
    /**
60
     * Build model dictionary.
61
     *
62 44
     * @param \Illuminate\Database\Eloquent\Collection $results
63
     * @return array
64 44
     */
65 16
    protected function buildDictionary(Collection $results)
66
    {
67
        if ($this->andSelf) {
68 28
            return $this->baseBuildDictionary($results);
69
        }
70 28
71
        $dictionary = [];
72 28
73
        $depthName = $this->related->getDepthName();
74 28
75 28
        $firstLevelResults = $results->where($depthName, '=', -1)->groupBy($this->parentKey);
76
77 28
        foreach ($results as $result) {
78 28
            $keys = [];
79 28
80
            if ($result->$depthName < -1) {
81
                foreach ($firstLevelResults[$result->getFirstPathSegment()] as $model) {
82 28
                    $keys[] = $model->{$this->accessor}->{$this->relatedPivotKey};
83
                }
84
            } else {
85 28
                $keys[] = $result->{$this->accessor}->{$this->relatedPivotKey};
86 28
            }
87
88
            foreach ($keys as $key) {
89
                $dictionary[$key][] = $result;
90 28
            }
91
        }
92
93
        return $dictionary;
94
    }
95
96
    /**
97
     * Add the constraints for a relationship query.
98
     *
99
     * @param \Illuminate\Database\Eloquent\Builder $query
100
     * @param \Illuminate\Database\Eloquent\Builder $parentQuery
101 18
     * @param array|mixed $columns
102
     * @return \Illuminate\Database\Eloquent\Builder
103 18
     */
104 12
    public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*'])
105
    {
106
        if ($query->getQuery()->from === $parentQuery->getQuery()->from) {
107 6
            return $this->getRelationExistenceQueryForSelfRelation($query, $columns);
108 3
        }
109 3
110
        $first = $this->andSelf
111 6
            ? $query->getQuery()->from . '.' . $this->parentKey
0 ignored issues
show
Bug introduced by
Are you sure $query->getQuery()->from of type Illuminate\Database\Query\Expression|string can be used in concatenation? ( Ignorable by Annotation )

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

111
            ? /** @scrutinizer ignore-type */ $query->getQuery()->from . '.' . $this->parentKey
Loading history...
112 6
            : $this->getQualifiedRelatedPivotKeyName();
113 6
114 6
        $constraint = function (Builder $query) use ($first) {
115 6
            $query->whereColumn(
116 6
                $first,
117 6
                '=',
118
                $this->getQualifiedParentKeyName()
119 6
            );
120
        };
121
122
        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...estors::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

122
        return $this->addExpression($constraint, /** @scrutinizer ignore-type */ $query->select($columns));
Loading history...
123
    }
124
125
    /**
126
     * Add the constraints for a relationship query on the same table.
127
     *
128
     * @param \Illuminate\Database\Eloquent\Builder $query
129 12
     * @param array|mixed $columns
130
     * @return \Illuminate\Database\Eloquent\Builder
131
     */
132
    public function getRelationExistenceQueryForSelfRelation(
133 12
        Builder $query,
134 9
        $columns = ['*']
135
    ): Builder {
136
        if ($columns instanceof Expression) {
137 12
            $columns = $this->replaceTableHash($query, $columns);
138
        }
139 12
140
        $table = $this->getRelationCountHash();
141 12
142
        $from = $query->getModel()->getTable() . ' as ' . $table;
143 12
144 6
        $query->getModel()->setTable($table);
145 6
146
        $first = $this->andSelf
147 12
            ? "$table.$this->parentKey"
148 12
            : "$this->table.$this->relatedPivotKey";
149 12
150 12
        $constraint = function (Builder $query) use ($first) {
151 12
            $query->whereColumn(
152 12
                $first,
153 12
                '=',
154
                $this->getQualifiedParentKeyName()
155 12
            );
156
        };
157
158
        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...estors::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

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