Passed
Pull Request — master (#77)
by
unknown
13:35
created

HasRecursiveRelationships::descendants()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 6
c 1
b 0
f 0
dl 0
loc 8
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 Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Ancestors;
9
use Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Bloodline;
10
use Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Descendants;
11
use Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\RootAncestor;
12
use Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Siblings;
13
use Staudenmeir\LaravelCte\Eloquent\QueriesExpressions;
14
15
trait HasRecursiveRelationships
16
{
17
    use HasOfDescendantsRelationships;
18
    use HasRecursiveRelationshipScopes;
19
    use QueriesExpressions;
20
21
    /** @var null|callable */
22
    public static $recursiveQueryDecoratingFunction;
23
24
    /**
25
     * Set function for decorating recursive query
26 678
     *
27
     * @param callable $function
28 678
     * @return void
29
     */
30
    public function setRecursiveQueryDecoratingFunction(callable $function) {
31
        static::$recursiveQueryDecoratingFunction = $function;
32
    }
33
34
    /**
35
     * Unset function for decorating recursive query
36 279
     *
37
     * @return void
38 279
     */
39
    public function unsetRecursiveQueryDecoratingFunction() {
40
        static::$recursiveQueryDecoratingFunction = null;
41
    }
42
43
    /**
44
     * Get the name of the parent key column.
45
     *
46 643
     * @return string
47
     */
48 643
    public function getParentKeyName()
49
    {
50
        return 'parent_id';
51
    }
52
53
    /**
54
     * Get the qualified parent key column.
55
     *
56 316
     * @return string
57
     */
58 316
    public function getQualifiedParentKeyName()
59
    {
60
        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

60
        return (new static())->/** @scrutinizer ignore-call */ getTable().'.'.$this->getParentKeyName();
Loading history...
61
    }
62
63
    /**
64
     * Get the name of the local key column.
65
     *
66 593
     * @return string
67
     */
68 593
    public function getLocalKeyName()
69
    {
70
        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

70
        return $this->/** @scrutinizer ignore-call */ getKeyName();
Loading history...
71
    }
72
73
    /**
74
     * Get the qualified local key column.
75
     *
76 421
     * @return string
77
     */
78 421
    public function getQualifiedLocalKeyName()
79
    {
80
        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

80
        return $this->/** @scrutinizer ignore-call */ qualifyColumn($this->getLocalKeyName());
Loading history...
81
    }
82
83
    /**
84
     * Get the name of the depth column.
85
     *
86 352
     * @return string
87
     */
88 352
    public function getDepthName()
89
    {
90
        return 'depth';
91
    }
92
93
    /**
94
     * Get the name of the path column.
95
     *
96 272
     * @return string
97
     */
98 272
    public function getPathName()
99
    {
100
        return 'path';
101
    }
102
103
    /**
104
     * Get the path separator.
105
     *
106 593
     * @return string
107
     */
108 593
    public function getPathSeparator()
109
    {
110
        return '.';
111
    }
112
113
    /**
114
     * Get the additional custom paths.
115
     *
116 60
     * @return array
117
     */
118 60
    public function getCustomPaths()
119 60
    {
120
        return [];
121 60
    }
122 60
123 60
    /**
124
     * Get the name of the common table expression.
125
     *
126
     * @return string
127
     */
128
    public function getExpressionName()
129
    {
130
        return 'laravel_cte';
131
    }
132 31
133
    /**
134 31
     * Get the model's ancestors.
135 31
     *
136
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Ancestors
137 31
     */
138 31
    public function ancestors()
139 31
    {
140
        return $this->newAncestors(
141
            (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

141
            (new static())->/** @scrutinizer ignore-call */ newQuery(),
Loading history...
142
            $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

142
            /** @scrutinizer ignore-type */ $this,
Loading history...
143
            $this->getQualifiedParentKeyName(),
144
            $this->getLocalKeyName(),
145
            false
146
        );
147
    }
148
149
    /**
150
     * Get the model's ancestors and itself.
151
     *
152
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Ancestors
153 91
     */
154
    public function ancestorsAndSelf()
155 91
    {
156
        return $this->newAncestors(
157
            (new static())->newQuery(),
158
            $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

158
            /** @scrutinizer ignore-type */ $this,
Loading history...
159
            $this->getQualifiedParentKeyName(),
160
            $this->getLocalKeyName(),
161
            true
162
        );
163 29
    }
164
165 29
    /**
166 29
     * Instantiate a new Ancestors relationship.
167
     *
168 29
     * @param \Illuminate\Database\Eloquent\Builder $query
169 29
     * @param \Illuminate\Database\Eloquent\Model $parent
170
     * @param string $foreignKey
171
     * @param string $localKey
172
     * @param bool $andSelf
173
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Ancestors
174
     */
175
    protected function newAncestors(Builder $query, Model $parent, $foreignKey, $localKey, $andSelf)
176
    {
177
        return new Ancestors($query, $parent, $foreignKey, $localKey, $andSelf);
178
    }
179
180
    /**
181
     * Get the model's bloodline.
182 29
     *
183
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Bloodline
184 29
     */
185
    public function bloodline()
186
    {
187
        return $this->newBloodline(
188
            (new static())->newQuery(),
189
            $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::newBloodline(). ( Ignorable by Annotation )

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

189
            /** @scrutinizer ignore-type */ $this,
Loading history...
190
            $this->getQualifiedParentKeyName(),
191
            $this->getLocalKeyName()
192 5
        );
193
    }
194 5
195
    /**
196
     * Instantiate a new Bloodline relationship.
197
     *
198
     * @param \Illuminate\Database\Eloquent\Builder $query
199
     * @param \Illuminate\Database\Eloquent\Model $parent
200
     * @param string $foreignKey
201
     * @param string $localKey
202 5
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Bloodline
203
     */
204 5
    protected function newBloodline(Builder $query, Model $parent, $foreignKey, $localKey)
205
    {
206
        return new Bloodline($query, $parent, $foreignKey, $localKey);
207
    }
208
209
    /**
210
     * Get the model's children.
211
     *
212 66
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
213
     */
214 66
    public function children()
215 66
    {
216
        return $this->hasMany(static::class, $this->getParentKeyName(), $this->getLocalKeyName());
0 ignored issues
show
Bug introduced by
The method hasMany() does not exist on Staudenmeir\LaravelAdjac...sRecursiveRelationships. Did you maybe mean hasManyOfDescendantsAndSelf()? ( Ignorable by Annotation )

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

216
        return $this->/** @scrutinizer ignore-call */ hasMany(static::class, $this->getParentKeyName(), $this->getLocalKeyName());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
217 66
    }
218 66
219 66
    /**
220
     * Get the model's children and itself.
221
     *
222
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Descendants
223
     */
224
    public function childrenAndSelf()
225
    {
226
        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

226
        return $this->descendantsAndSelf()->/** @scrutinizer ignore-call */ whereDepth('<=', 1);
Loading history...
227
    }
228 26
229
    /**
230 26
     * Get the model's descendants.
231 26
     *
232
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Descendants
233 26
     */
234 26
    public function descendants()
235 26
    {
236
        return $this->newDescendants(
237
            (new static())->newQuery(),
238
            $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

238
            /** @scrutinizer ignore-type */ $this,
Loading history...
239
            $this->getQualifiedParentKeyName(),
240
            $this->getLocalKeyName(),
241
            false
242
        );
243
    }
244
245
    /**
246
     * Get the model's descendants and itself.
247
     *
248
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Descendants
249 92
     */
250
    public function descendantsAndSelf()
251 92
    {
252
        return $this->newDescendants(
253
            (new static())->newQuery(),
254
            $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

254
            /** @scrutinizer ignore-type */ $this,
Loading history...
255
            $this->getQualifiedParentKeyName(),
256
            $this->getLocalKeyName(),
257
            true
258
        );
259 5
    }
260
261 5
    /**
262
     * Instantiate a new Descendants relationship.
263
     *
264
     * @param \Illuminate\Database\Eloquent\Builder $query
265
     * @param \Illuminate\Database\Eloquent\Model $parent
266
     * @param string $foreignKey
267
     * @param string $localKey
268
     * @param bool $andSelf
269 5
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Descendants
270
     */
271 5
    protected function newDescendants(Builder $query, Model $parent, $foreignKey, $localKey, $andSelf)
272
    {
273
        return new Descendants($query, $parent, $foreignKey, $localKey, $andSelf);
274
    }
275
276
    /**
277
     * Get the model's parent.
278
     *
279 25
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
280
     */
281 25
    public function parent()
282 25
    {
283
        return $this->belongsTo(static::class, $this->getParentKeyName(), $this->getLocalKeyName());
0 ignored issues
show
Bug introduced by
The method belongsTo() does not exist on Staudenmeir\LaravelAdjac...sRecursiveRelationships. Did you maybe mean belongsToManyOfDescendantsAndSelf()? ( Ignorable by Annotation )

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

283
        return $this->/** @scrutinizer ignore-call */ belongsTo(static::class, $this->getParentKeyName(), $this->getLocalKeyName());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
284 25
    }
285 25
286
    /**
287
     * Get the model's parent and itself.
288
     *
289
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Ancestors
290
     */
291
    public function parentAndSelf()
292
    {
293
        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

293
        return $this->ancestorsAndSelf()->/** @scrutinizer ignore-call */ whereDepth('>=', -1);
Loading history...
294
    }
295
296
    /**
297
     * Get the model's root ancestor.
298 25
     *
299
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\RootAncestor
300 25
     */
301
    public function rootAncestor()
302
    {
303
        return $this->newRootAncestor(
304
            (new static())->newQuery(),
305
            $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...hips::newRootAncestor(). ( Ignorable by Annotation )

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

305
            /** @scrutinizer ignore-type */ $this,
Loading history...
306
            $this->getQualifiedParentKeyName(),
307
            $this->getLocalKeyName()
308 35
        );
309
    }
310 35
311 35
    /**
312
     * Instantiate a new RootAncestor relationship.
313 35
     *
314 35
     * @param \Illuminate\Database\Eloquent\Builder $query
315 35
     * @param \Illuminate\Database\Eloquent\Model $parent
316
     * @param string $foreignKey
317
     * @param string $localKey
318
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\RootAncestor
319
     */
320
    protected function newRootAncestor(Builder $query, Model $parent, $foreignKey, $localKey)
321
    {
322
        return new RootAncestor($query, $parent, $foreignKey, $localKey);
323
    }
324 30
325
    /**
326 30
     * Get the model's siblings.
327 30
     *
328
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Siblings
329 30
     */
330 30
    public function siblings()
331 30
    {
332
        return $this->newSiblings(
333
            (new static())->newQuery(),
334
            $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

334
            /** @scrutinizer ignore-type */ $this,
Loading history...
335
            $this->getQualifiedParentKeyName(),
336
            $this->getParentKeyName(),
337
            false
338
        );
339
    }
340
341
    /**
342
     * Get the model's siblings and itself.
343
     *
344
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Siblings
345 65
     */
346
    public function siblingsAndSelf()
347 65
    {
348
        return $this->newSiblings(
349
            (new static())->newQuery(),
350
            $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

350
            /** @scrutinizer ignore-type */ $this,
Loading history...
351
            $this->getQualifiedParentKeyName(),
352
            $this->getParentKeyName(),
353
            true
354
        );
355 60
    }
356
357 60
    /**
358
     * Instantiate a new Siblings relationship.
359 60
     *
360
     * @param \Illuminate\Database\Eloquent\Builder $query
361
     * @param \Illuminate\Database\Eloquent\Model $parent
362
     * @param string $foreignKey
363
     * @param string $localKey
364
     * @param bool $andSelf
365
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Siblings
366
     */
367 10
    protected function newSiblings(Builder $query, Model $parent, $foreignKey, $localKey, $andSelf)
368
    {
369 10
        return new Siblings($query, $parent, $foreignKey, $localKey, $andSelf);
370
    }
371 10
372
    /**
373
     * Get the first segment of the model's path.
374
     *
375
     * @return string
376
     */
377
    public function getFirstPathSegment()
378
    {
379
        $path = $this->attributes[$this->getPathName()];
380 88
381
        return explode($this->getPathSeparator(), $path)[0];
382 88
    }
383
384 88
    /**
385
     * Determine whether the model's path is nested.
386
     *
387
     * @return bool
388
     */
389
    public function hasNestedPath()
390
    {
391
        $path = $this->attributes[$this->getPathName()];
392
393 678
        return Str::contains($path, $this->getPathSeparator());
394
    }
395 678
396
    /**
397
     * Determine if an attribute is an integer.
398
     *
399
     * @param string $attribute
400
     * @return bool
401
     */
402
    public function isIntegerAttribute($attribute)
403
    {
404 673
        $casts = $this->getCasts();
0 ignored issues
show
Bug introduced by
It seems like getCasts() 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

404
        /** @scrutinizer ignore-call */ 
405
        $casts = $this->getCasts();
Loading history...
405
406 673
        return isset($casts[$attribute]) && in_array($casts[$attribute], ['int', 'integer']);
407
    }
408
409
    /**
410
     * Create a new Eloquent query builder for the model.
411
     *
412
     * @param \Illuminate\Database\Query\Builder $query
413
     * @return \Illuminate\Database\Eloquent\Builder|static
414
     */
415
    public function newEloquentBuilder($query)
416
    {
417
        return new \Staudenmeir\LaravelAdjacencyList\Eloquent\Builder($query);
418
    }
419
420
    /**
421
     * Create a new Eloquent Collection instance.
422
     *
423
     * @param array $models
424
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Collection
425
     */
426
    public function newCollection(array $models = [])
427
    {
428
        return new Collection($models);
0 ignored issues
show
Bug introduced by
$models of type array is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $items of Staudenmeir\LaravelAdjac...llection::__construct(). ( Ignorable by Annotation )

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

428
        return new Collection(/** @scrutinizer ignore-type */ $models);
Loading history...
429
    }
430
}
431