Passed
Push — master ( 6a0cbe...537b6a )
by Jonas
07:23
created

HasRecursiveRelationships::getLocalKeyName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
namespace Staudenmeir\LaravelAdjacencyList\Eloquent;
4
5
use Illuminate\Database\Eloquent\Builder;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Staudenmeir\LaravelAdjacencyList\Eloquent\Builder. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
6
use Illuminate\Database\Eloquent\Model;
7
use Illuminate\Support\Str;
8
use RuntimeException;
9
use Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Ancestors;
10
use Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Descendants;
11
use Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Siblings;
12
use Staudenmeir\LaravelAdjacencyList\Query\Grammars\ExpressionGrammar;
13
use Staudenmeir\LaravelAdjacencyList\Query\Grammars\MySqlGrammar;
14
use Staudenmeir\LaravelAdjacencyList\Query\Grammars\PostgresGrammar;
15
use Staudenmeir\LaravelAdjacencyList\Query\Grammars\SQLiteGrammar;
16
use Staudenmeir\LaravelAdjacencyList\Query\Grammars\SqlServerGrammar;
17
use Staudenmeir\LaravelCte\Eloquent\QueriesExpressions;
18
19
trait HasRecursiveRelationships
20
{
21
    use QueriesExpressions;
22
23
    /**
24
     * Get the name of the parent key column.
25
     *
26
     * @return string
27
     */
28 196
    public function getParentKeyName()
29
    {
30 196
        return 'parent_id';
31
    }
32
33
    /**
34
     * Get the qualified parent key column.
35
     *
36
     * @return string
37
     */
38 160
    public function getQualifiedParentKeyName()
39
    {
40 160
        return (new static)->getTable().'.'.$this->getParentKeyName();
0 ignored issues
show
Bug introduced by
It seems like getTable() 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

40
        return (new static)->/** @scrutinizer ignore-call */ getTable().'.'.$this->getParentKeyName();
Loading history...
41
    }
42
43
    /**
44
     * Get the name of the local key column.
45
     *
46
     * @return string
47
     */
48 128
    public function getLocalKeyName()
49
    {
50 128
        return $this->getKeyName();
0 ignored issues
show
Bug introduced by
It seems like getKeyName() 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

50
        return $this->/** @scrutinizer ignore-call */ getKeyName();
Loading history...
51
    }
52
53
    /**
54
     * Get the qualified local key column.
55
     *
56
     * @return string
57
     */
58 145
    public function getQualifiedLocalKeyName()
59
    {
60 145
        return $this->qualifyColumn($this->getLocalKeyName());
0 ignored issues
show
Bug introduced by
It seems like qualifyColumn() 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

60
        return $this->/** @scrutinizer ignore-call */ qualifyColumn($this->getLocalKeyName());
Loading history...
61
    }
62
63
    /**
64
     * Get the name of the depth column.
65
     *
66
     * @return string
67
     */
68 145
    public function getDepthName()
69
    {
70 145
        return 'depth';
71
    }
72
73
    /**
74
     * Get the name of the path column.
75
     *
76
     * @return string
77
     */
78 128
    public function getPathName()
79
    {
80 128
        return 'path';
81
    }
82
83
    /**
84
     * Get the path separator.
85
     *
86
     * @return string
87
     */
88 32
    public function getPathSeparator()
89
    {
90 32
        return '.';
91 32
    }
92
93 32
    /**
94 32
     * Get the name of the common table expression.
95 32
     *
96
     * @return string
97
     */
98
    public function getExpressionName()
99
    {
100
        return 'laravel_cte';
101
    }
102
    
103
    /**
104 26
     * Get the model's ancestors.
105
     *
106 26
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Ancestors
107 26
     */
108
    public function ancestors()
109 26
    {
110 26
        return $this->newAncestors(
111 26
            (new static)->newQuery(),
0 ignored issues
show
Bug introduced by
It seems like newQuery() 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

111
            (new static)->/** @scrutinizer ignore-call */ newQuery(),
Loading history...
112
            $this,
0 ignored issues
show
Bug introduced by
$this of type Staudenmeir\LaravelAdjac...sRecursiveRelationships is incompatible with the type Illuminate\Database\Eloquent\Model expected by parameter $parent of Staudenmeir\LaravelAdjac...onships::newAncestors(). ( Ignorable by Annotation )

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

112
            /** @scrutinizer ignore-type */ $this,
Loading history...
113
            $this->getQualifiedParentKeyName(),
114
            $this->getLocalKeyName(),
115
            false
116
        );
117
    }
118
119
    /**
120
     * Get the model's ancestors and itself.
121
     *
122
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Ancestors
123
     */
124
    public function ancestorsAndSelf()
125 58
    {
126
        return $this->newAncestors(
127 58
            (new static)->newQuery(),
128
            $this,
0 ignored issues
show
Bug introduced by
$this of type Staudenmeir\LaravelAdjac...sRecursiveRelationships is incompatible with the type Illuminate\Database\Eloquent\Model expected by parameter $parent of Staudenmeir\LaravelAdjac...onships::newAncestors(). ( Ignorable by Annotation )

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

128
            /** @scrutinizer ignore-type */ $this,
Loading history...
129
            $this->getQualifiedParentKeyName(),
130
            $this->getLocalKeyName(),
131
            true
132
        );
133
    }
134
135 4
    /**
136
     * Instantiate a new Ancestors relationship.
137 4
     *
138
     * @param \Illuminate\Database\Eloquent\Builder $query
139
     * @param \Illuminate\Database\Eloquent\Model $parent
140
     * @param string $foreignKey
141
     * @param string $localKey
142
     * @param bool $andSelf
143
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Ancestors
144
     */
145 4
    protected function newAncestors(Builder $query, Model $parent, $foreignKey, $localKey, $andSelf)
146
    {
147 4
        return new Ancestors($query, $parent, $foreignKey, $localKey, $andSelf);
148
    }
149
150
    /**
151
     * Get the model's children.
152
     *
153
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
154
     */
155 44
    public function children()
156
    {
157 44
        return $this->hasMany(static::class, $this->getParentKeyName(), $this->getLocalKeyName());
0 ignored issues
show
Bug introduced by
It seems like hasMany() 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

157
        return $this->/** @scrutinizer ignore-call */ hasMany(static::class, $this->getParentKeyName(), $this->getLocalKeyName());
Loading history...
158 44
    }
159
160 44
    /**
161 44
     * Get the model's children and itself.
162 44
     *
163
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Descendants
164
     */
165
    public function childrenAndSelf()
166
    {
167
        return $this->descendantsAndSelf()->whereDepth('<=', 1);
0 ignored issues
show
Bug introduced by
The method whereDepth() does not exist on Staudenmeir\LaravelAdjac...t\Relations\Descendants. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

167
        return $this->descendantsAndSelf()->/** @scrutinizer ignore-call */ whereDepth('<=', 1);
Loading history...
168
    }
169
170
    /**
171 22
     * Get the model's descendants.
172
     *
173 22
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Descendants
174 22
     */
175
    public function descendants()
176 22
    {
177 22
        return $this->newDescendants(
178 22
            (new static)->newQuery(),
179
            $this,
0 ignored issues
show
Bug introduced by
$this of type Staudenmeir\LaravelAdjac...sRecursiveRelationships is incompatible with the type Illuminate\Database\Eloquent\Model expected by parameter $parent of Staudenmeir\LaravelAdjac...ships::newDescendants(). ( Ignorable by Annotation )

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

179
            /** @scrutinizer ignore-type */ $this,
Loading history...
180
            $this->getQualifiedParentKeyName(),
181
            $this->getLocalKeyName(),
182
            false
183
        );
184
    }
185
186
    /**
187
     * Get the model's descendants and itself.
188
     *
189
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Descendants
190
     */
191
    public function descendantsAndSelf()
192 66
    {
193
        return $this->newDescendants(
194 66
            (new static)->newQuery(),
195
            $this,
0 ignored issues
show
Bug introduced by
$this of type Staudenmeir\LaravelAdjac...sRecursiveRelationships is incompatible with the type Illuminate\Database\Eloquent\Model expected by parameter $parent of Staudenmeir\LaravelAdjac...ships::newDescendants(). ( Ignorable by Annotation )

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

195
            /** @scrutinizer ignore-type */ $this,
Loading history...
196
            $this->getQualifiedParentKeyName(),
197
            $this->getLocalKeyName(),
198
            true
199
        );
200
    }
201
202 4
    /**
203
     * Instantiate a new Descendants relationship.
204 4
     *
205
     * @param \Illuminate\Database\Eloquent\Builder $query
206
     * @param \Illuminate\Database\Eloquent\Model $parent
207
     * @param string $foreignKey
208
     * @param string $localKey
209
     * @param bool $andSelf
210
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Descendants
211
     */
212 4
    protected function newDescendants(Builder $query, Model $parent, $foreignKey, $localKey, $andSelf)
213
    {
214 4
        return new Descendants($query, $parent, $foreignKey, $localKey, $andSelf);
215
    }
216
217
    /**
218
     * Get the model's parent.
219
     *
220
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
221
     */
222 28
    public function parent()
223
    {
224 28
        return $this->belongsTo(static::class, $this->getParentKeyName(), $this->getLocalKeyName());
0 ignored issues
show
Bug introduced by
It seems like belongsTo() 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

224
        return $this->/** @scrutinizer ignore-call */ belongsTo(static::class, $this->getParentKeyName(), $this->getLocalKeyName());
Loading history...
225 28
    }
226
227 28
    /**
228 28
     * Get the model's parent and itself.
229 28
     *
230
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Ancestors
231
     */
232
    public function parentAndSelf()
233
    {
234
        return $this->ancestorsAndSelf()->whereDepth('>=', -1);
0 ignored issues
show
Bug introduced by
The method whereDepth() does not exist on Staudenmeir\LaravelAdjac...ent\Relations\Ancestors. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

234
        return $this->ancestorsAndSelf()->/** @scrutinizer ignore-call */ whereDepth('>=', -1);
Loading history...
235
    }
236
237
    /**
238 24
     * Get the model's siblings.
239
     *
240 24
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Siblings
241 24
     */
242
    public function siblings()
243 24
    {
244 24
        return $this->newSiblings(
245 24
            (new static)->newQuery(),
246
            $this,
0 ignored issues
show
Bug introduced by
$this of type Staudenmeir\LaravelAdjac...sRecursiveRelationships is incompatible with the type Illuminate\Database\Eloquent\Model expected by parameter $parent of Staudenmeir\LaravelAdjac...ionships::newSiblings(). ( Ignorable by Annotation )

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

246
            /** @scrutinizer ignore-type */ $this,
Loading history...
247
            $this->getQualifiedParentKeyName(),
248
            $this->getParentKeyName(),
249
            false
250
        );
251
    }
252
253
    /**
254
     * Get the model's siblings and itself.
255
     *
256
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Siblings
257
     */
258
    public function siblingsAndSelf()
259 52
    {
260
        return $this->newSiblings(
261 52
            (new static)->newQuery(),
262
            $this,
0 ignored issues
show
Bug introduced by
$this of type Staudenmeir\LaravelAdjac...sRecursiveRelationships is incompatible with the type Illuminate\Database\Eloquent\Model expected by parameter $parent of Staudenmeir\LaravelAdjac...ionships::newSiblings(). ( Ignorable by Annotation )

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

262
            /** @scrutinizer ignore-type */ $this,
Loading history...
263
            $this->getQualifiedParentKeyName(),
264
            $this->getParentKeyName(),
265
            true
266
        );
267
    }
268
269
    /**
270 16
     * Instantiate a new Siblings relationship.
271
     *
272
     * @param \Illuminate\Database\Eloquent\Builder $query
273 16
     * @param \Illuminate\Database\Eloquent\Model $parent
274 16
     * @param string $foreignKey
275
     * @param string $localKey
276 16
     * @param bool $andSelf
277
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Siblings
278
     */
279
    protected function newSiblings(Builder $query, Model $parent, $foreignKey, $localKey, $andSelf)
280
    {
281
        return new Siblings($query, $parent, $foreignKey, $localKey, $andSelf);
282
    }
283
284
    /**
285 4
     * Add a recursive expression for the relationship's whole tree to the query.
286
     *
287 4
     * @param \Illuminate\Database\Eloquent\Builder $query
288 4
     * @return \Illuminate\Database\Eloquent\Builder
289 4
     */
290
    public function scopeTree(Builder $query)
291 4
    {
292
        $constraint = function (Builder $query) {
293
            $query->isRoot();
294
        };
295
        
296
        return $query->withRelationshipExpression('desc', $constraint, 0);
297
    }
298
299
    /**
300 12
     * Limit the query to models with children.
301
     *
302 12
     * @param \Illuminate\Database\Eloquent\Builder $query
303
     * @return \Illuminate\Database\Eloquent\Builder
304
     */
305
    public function scopeHasChildren(Builder $query)
306
    {
307
        $keys = (new static)->newQuery()
308
            ->select($this->getParentKeyName())
309
            ->hasParent();
310
311 4
        return $query->whereIn($this->getLocalKeyName(), $keys);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->whereIn($...tLocalKeyName(), $keys) also could return the type Illuminate\Database\Query\Builder which is incompatible with the documented return type Illuminate\Database\Eloquent\Builder.
Loading history...
312
    }
313 4
314 4
    /**
315 4
     * Limit the query to models with a parent.
316
     *
317 4
     * @param \Illuminate\Database\Eloquent\Builder $query
318
     * @return \Illuminate\Database\Eloquent\Builder
319
     */
320
    public function scopeHasParent(Builder $query)
321
    {
322
        return $query->whereNotNull($this->getParentKeyName());
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->whereNotN...is->getParentKeyName()) also could return the type Illuminate\Database\Query\Builder which is incompatible with the documented return type Illuminate\Database\Eloquent\Builder.
Loading history...
323
    }
324
325
    /**
326 20
     * Limit the query to leaf models.
327
     *
328 20
     * @param \Illuminate\Database\Eloquent\Builder $query
329
     * @return \Illuminate\Database\Eloquent\Builder
330
     */
331
    public function scopeIsLeaf(Builder $query)
332
    {
333
        $keys = (new static)->newQuery()
334
            ->select($this->getParentKeyName())
335
            ->hasParent();
336
337
        return $query->whereNotIn($this->getLocalKeyName(), $keys);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->whereNotI...tLocalKeyName(), $keys) also could return the type Illuminate\Database\Query\Builder which is incompatible with the documented return type Illuminate\Database\Eloquent\Builder.
Loading history...
338
    }
339 16
340
    /**
341 16
     * Limit the query to root models.
342
     *
343 16
     * @param \Illuminate\Database\Eloquent\Builder $query
344
     * @return \Illuminate\Database\Eloquent\Builder
345
     */
346
    public function scopeIsRoot(Builder $query)
347
    {
348
        return $query->whereNull($this->getParentKeyName());
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->whereNull...is->getParentKeyName()) also could return the type Illuminate\Database\Query\Builder which is incompatible with the documented return type Illuminate\Database\Eloquent\Builder.
Loading history...
349
    }
350
351
    /**
352 4
     * Limit the query by depth.
353
     *
354 4
     * @param \Illuminate\Database\Eloquent\Builder $query
355
     * @param mixed $operator
356
     * @param mixed $value
357
     * @return \Illuminate\Database\Eloquent\Builder
358
     */
359
    public function scopeWhereDepth(Builder $query, $operator, $value = null)
360
    {
361
        $arguments = array_slice(func_get_args(), 1);
362
363 8
        return $query->where($this->getDepthName(), ...$arguments);
364
    }
365 8
366
    /**
367
     * Order the query breadth-first.
368
     *
369
     * @param \Illuminate\Database\Eloquent\Builder $query
370
     * @return \Illuminate\Database\Eloquent\Builder
371
     */
372
    public function scopeBreadthFirst(Builder $query)
373
    {
374
        return $query->orderBy($this->getDepthName());
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->orderBy($this->getDepthName()) also could return the type Illuminate\Database\Query\Builder which is incompatible with the documented return type Illuminate\Database\Eloquent\Builder.
Loading history...
375
    }
376
377
    /**
378 128
     * Order the query depth-first.
379
     *
380 128
     * @param \Illuminate\Database\Eloquent\Builder $query
381
     * @return \Illuminate\Database\Eloquent\Builder
382 128
     */
383
    public function scopeDepthFirst(Builder $query)
384 128
    {
385 128
        return $query->orderBy($this->getPathName());
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->orderBy($this->getPathName()) also could return the type Illuminate\Database\Query\Builder which is incompatible with the documented return type Illuminate\Database\Eloquent\Builder.
Loading history...
386 128
    }
387
388
    /**
389 128
     * Add a recursive expression for the relationship to the query.
390
     *
391 128
     * @param \Illuminate\Database\Eloquent\Builder $query
392
     * @param string $direction
393 128
     * @param callable $constraint
394
     * @param int $initialDepth
395
     * @param string|null $from
396
     * @return \Illuminate\Database\Eloquent\Builder
397
     */
398
    public function scopeWithRelationshipExpression(Builder $query, $direction, callable $constraint, $initialDepth, $from = null)
399
    {
400
        $from = $from ?: $this->getTable();
401
402
        $grammar = $this->getExpressionGrammar($query);
403
404
        $expression = $this->getInitialQuery($grammar, $constraint, $initialDepth, $from)
405 128
            ->unionAll(
406
                $this->getRecursiveQuery($grammar, $direction, $from)
407 128
            );
408
409 128
        $name = $this->getExpressionName();
410 128
411 128
        $query->getModel()->setTable($name);
412
413
        return $query->withRecursiveExpression($name, $expression)->from($name);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->withRecur...xpression)->from($name) also could return the type Illuminate\Database\Query\Builder which is incompatible with the documented return type Illuminate\Database\Eloquent\Builder.
Loading history...
414 128
    }
415 128
416 128
    /**
417 128
     * Get the initial query for a relationship expression.
418 128
     *
419
     * @param \Staudenmeir\LaravelAdjacencyList\Query\Grammars\ExpressionGrammar|\Illuminate\Database\Grammar $grammar
420 128
     * @param callable $constraint
421
     * @param int $initialDepth
422 128
     * @param string $from
423
     * @return \Illuminate\Database\Eloquent\Builder $query
424
     */
425
    protected function getInitialQuery(ExpressionGrammar $grammar, callable $constraint, $initialDepth, $from)
426
    {
427
        $depth = $grammar->wrap($this->getDepthName());
0 ignored issues
show
Bug introduced by
The method wrap() does not exist on Staudenmeir\LaravelAdjac...mmars\ExpressionGrammar. Since it exists in all sub-types, consider adding an abstract or default implementation to Staudenmeir\LaravelAdjac...mmars\ExpressionGrammar. ( Ignorable by Annotation )

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

427
        /** @scrutinizer ignore-call */ 
428
        $depth = $grammar->wrap($this->getDepthName());
Loading history...
428
429
        $initialPath = $grammar->compileInitialPath(
430
            $this->getLocalKeyName(),
431
            $this->getPathName()
432
        );
433 128
434
        $query = $this->newModelQuery()
0 ignored issues
show
Bug introduced by
It seems like newModelQuery() 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

434
        $query = $this->/** @scrutinizer ignore-call */ newModelQuery()
Loading history...
435 128
            ->select('*')
436
            ->selectRaw($initialDepth.' as '.$depth)
437 128
            ->selectRaw($initialPath)
438
            ->from($from);
439 128
440
        $constraint($query);
441 128
442
        return $query;
443 128
    }
444 128
445 128
    /**
446 128
     * Get the recursive query for a relationship expression.
447
     *
448
     * @param \Staudenmeir\LaravelAdjacencyList\Query\Grammars\ExpressionGrammar|\Illuminate\Database\Grammar $grammar
449 128
     * @param string $direction
450 128
     * @param string $from
451 128
     * @return \Illuminate\Database\Eloquent\Builder $query
452 128
     */
453 128
    protected function getRecursiveQuery(ExpressionGrammar $grammar, $direction, $from)
454
    {
455 128
        $name = $this->getExpressionName();
456 58
457 58
        $table = explode(' as ', $from)[1] ?? $from;
458
459 82
        $depth = $grammar->wrap($this->getDepthName());
460 82
461
        $recursiveDepth = $grammar->wrap($this->getDepthName()).' '.($direction === 'asc' ? '-' : '+').' 1';
462
463 128
        $recursivePath = $grammar->compileRecursivePath(
464
            $this->getQualifiedLocalKeyName(),
465 128
            $this->getPathName(),
466
            $this->getPathSeparator()
467
        );
468
469
        $query = $this->newModelQuery()
470
            ->select($table.'.*')
471
            ->selectRaw($recursiveDepth.' as '.$depth)
472
            ->selectRaw($recursivePath)
473
            ->from($from);
474 128
475
        if ($direction === 'asc') {
476 128
            $first = $this->getParentKeyName();
477
            $second = $this->getQualifiedLocalKeyName();
478 128
        } else {
479 128
            $first = $this->getLocalKeyName();
480 34
            $second = $this->qualifyColumn($this->getParentKeyName());
481 94
        }
482 34
483 60
        $query->join($name, $name.'.'.$first, '=', $second);
484 34
485 26
        return $query;
486 26
    }
487
488
    /**
489
     * Get the expression grammar.
490
     *
491
     * @param \Illuminate\Database\Eloquent\Builder $query
492
     * @return \Staudenmeir\LaravelAdjacencyList\Query\Grammars\ExpressionGrammar
493
     */
494
    protected function getExpressionGrammar(Builder $query)
495
    {
496
        $driver = $query->getConnection()->getDriverName();
497 32
498
        switch ($driver) {
499 32
            case 'mysql':
500
                return $query->getConnection()->withTablePrefix(new MySqlGrammar);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->getConnec...rammars\MySqlGrammar()) also could return the type Illuminate\Database\Conn...tabase\Eloquent\Builder which is incompatible with the documented return type Staudenmeir\LaravelAdjac...mmars\ExpressionGrammar.
Loading history...
501 32
            case 'pgsql':
502
                return $query->getConnection()->withTablePrefix(new PostgresGrammar);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->getConnec...mars\PostgresGrammar()) also could return the type Illuminate\Database\Conn...tabase\Eloquent\Builder which is incompatible with the documented return type Staudenmeir\LaravelAdjac...mmars\ExpressionGrammar.
Loading history...
503
            case 'sqlite':
504
                return $query->getConnection()->withTablePrefix(new SQLiteGrammar);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->getConnec...ammars\SQLiteGrammar()) also could return the type Illuminate\Database\Conn...tabase\Eloquent\Builder which is incompatible with the documented return type Staudenmeir\LaravelAdjac...mmars\ExpressionGrammar.
Loading history...
505
            case 'sqlsrv':
506
                return $query->getConnection()->withTablePrefix(new SqlServerGrammar);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->getConnec...ars\SqlServerGrammar()) also could return the type Illuminate\Database\Conn...tabase\Eloquent\Builder which is incompatible with the documented return type Staudenmeir\LaravelAdjac...mmars\ExpressionGrammar.
Loading history...
507
        }
508
509 8
        throw new RuntimeException('This database is not supported.'); // @codeCoverageIgnore
510
    }
511 8
512
    /**
513 8
     * Get the first segment of the model's path.
514
     *
515
     * @return string
516
     */
517
    public function getFirstPathSegment()
518
    {
519
        $path = $this->attributes[$this->getPathName()];
520
521
        return explode($this->getPathSeparator(), $path)[0];
522 196
    }
523
524 196
    /**
525
     * Determine whether the model's path is nested.
526
     *
527
     * @return bool
528
     */
529
    public function hasNestedPath()
530
    {
531
        $path = $this->attributes[$this->getPathName()];
532
533
        return Str::contains($path, $this->getPathSeparator());
534
    }
535
536
    /**
537
     * Create a new Eloquent query builder for the model.
538
     *
539
     * @param \Illuminate\Database\Query\Builder $query
540
     * @return \Illuminate\Database\Eloquent\Builder|static
541
     */
542
    public function newEloquentBuilder($query)
543
    {
544
        return new \Staudenmeir\LaravelAdjacencyList\Eloquent\Builder($query);
545
    }
546
}
547