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

HasRecursiveRelationships::newBloodline()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
ccs 0
cts 0
cp 0
rs 10
cc 1
nc 1
nop 4
crap 2
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
     * Allows to make a query with decorating function
26 678
     *
27
     * @param callable $decoratingFunction
28 678
     * @param callable $callback
29
     * @return mixed
30
     */
31
    public static function withRecursiveQueryDecoratingFunction(callable $decoratingFunction, callable $callback)
32
    {
33
        $previous = static::$recursiveQueryDecoratingFunction;
34
35
        static::$recursiveQueryDecoratingFunction = $decoratingFunction;
36 279
37
        $result = $callback();
38 279
39
        static::$recursiveQueryDecoratingFunction = $previous;
40
41
        return $result;
42
    }
43
44
    /**
45
     * Set function for decorating recursive query
46 643
     *
47
     * @param callable $function
48 643
     * @return void
49
     */
50
    public function setRecursiveQueryDecoratingFunction(callable $function) {
51
        static::$recursiveQueryDecoratingFunction = $function;
52
    }
53
54
    /**
55
     * Unset function for decorating recursive query
56 316
     *
57
     * @return void
58 316
     */
59
    public function unsetRecursiveQueryDecoratingFunction() {
60
        static::$recursiveQueryDecoratingFunction = null;
61
    }
62
63
    /**
64
     * Get the name of the parent key column.
65
     *
66 593
     * @return string
67
     */
68 593
    public function getParentKeyName()
69
    {
70
        return 'parent_id';
71
    }
72
73
    /**
74
     * Get the qualified parent key column.
75
     *
76 421
     * @return string
77
     */
78 421
    public function getQualifiedParentKeyName()
79
    {
80
        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

80
        return (new static())->/** @scrutinizer ignore-call */ getTable().'.'.$this->getParentKeyName();
Loading history...
81
    }
82
83
    /**
84
     * Get the name of the local key column.
85
     *
86 352
     * @return string
87
     */
88 352
    public function getLocalKeyName()
89
    {
90
        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

90
        return $this->/** @scrutinizer ignore-call */ getKeyName();
Loading history...
91
    }
92
93
    /**
94
     * Get the qualified local key column.
95
     *
96 272
     * @return string
97
     */
98 272
    public function getQualifiedLocalKeyName()
99
    {
100
        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

100
        return $this->/** @scrutinizer ignore-call */ qualifyColumn($this->getLocalKeyName());
Loading history...
101
    }
102
103
    /**
104
     * Get the name of the depth column.
105
     *
106 593
     * @return string
107
     */
108 593
    public function getDepthName()
109
    {
110
        return 'depth';
111
    }
112
113
    /**
114
     * Get the name of the path column.
115
     *
116 60
     * @return string
117
     */
118 60
    public function getPathName()
119 60
    {
120
        return 'path';
121 60
    }
122 60
123 60
    /**
124
     * Get the path separator.
125
     *
126
     * @return string
127
     */
128
    public function getPathSeparator()
129
    {
130
        return '.';
131
    }
132 31
133
    /**
134 31
     * Get the additional custom paths.
135 31
     *
136
     * @return array
137 31
     */
138 31
    public function getCustomPaths()
139 31
    {
140
        return [];
141
    }
142
143
    /**
144
     * Get the name of the common table expression.
145
     *
146
     * @return string
147
     */
148
    public function getExpressionName()
149
    {
150
        return 'laravel_cte';
151
    }
152
153 91
    /**
154
     * Get the model's ancestors.
155 91
     *
156
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Ancestors
157
     */
158
    public function ancestors()
159
    {
160
        return $this->newAncestors(
161
            (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

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

162
            /** @scrutinizer ignore-type */ $this,
Loading history...
163 29
            $this->getQualifiedParentKeyName(),
164
            $this->getLocalKeyName(),
165 29
            false
166 29
        );
167
    }
168 29
169 29
    /**
170
     * Get the model's ancestors and itself.
171
     *
172
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Ancestors
173
     */
174
    public function ancestorsAndSelf()
175
    {
176
        return $this->newAncestors(
177
            (new static())->newQuery(),
178
            $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

178
            /** @scrutinizer ignore-type */ $this,
Loading history...
179
            $this->getQualifiedParentKeyName(),
180
            $this->getLocalKeyName(),
181
            true
182 29
        );
183
    }
184 29
185
    /**
186
     * Instantiate a new Ancestors relationship.
187
     *
188
     * @param \Illuminate\Database\Eloquent\Builder $query
189
     * @param \Illuminate\Database\Eloquent\Model $parent
190
     * @param string $foreignKey
191
     * @param string $localKey
192 5
     * @param bool $andSelf
193
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Ancestors
194 5
     */
195
    protected function newAncestors(Builder $query, Model $parent, $foreignKey, $localKey, $andSelf)
196
    {
197
        return new Ancestors($query, $parent, $foreignKey, $localKey, $andSelf);
198
    }
199
200
    /**
201
     * Get the model's bloodline.
202 5
     *
203
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Bloodline
204 5
     */
205
    public function bloodline()
206
    {
207
        return $this->newBloodline(
208
            (new static())->newQuery(),
209
            $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

209
            /** @scrutinizer ignore-type */ $this,
Loading history...
210
            $this->getQualifiedParentKeyName(),
211
            $this->getLocalKeyName()
212 66
        );
213
    }
214 66
215 66
    /**
216
     * Instantiate a new Bloodline relationship.
217 66
     *
218 66
     * @param \Illuminate\Database\Eloquent\Builder $query
219 66
     * @param \Illuminate\Database\Eloquent\Model $parent
220
     * @param string $foreignKey
221
     * @param string $localKey
222
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Bloodline
223
     */
224
    protected function newBloodline(Builder $query, Model $parent, $foreignKey, $localKey)
225
    {
226
        return new Bloodline($query, $parent, $foreignKey, $localKey);
227
    }
228 26
229
    /**
230 26
     * Get the model's children.
231 26
     *
232
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
233 26
     */
234 26
    public function children()
235 26
    {
236
        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

236
        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...
237
    }
238
239
    /**
240
     * Get the model's children and itself.
241
     *
242
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Descendants
243
     */
244
    public function childrenAndSelf()
245
    {
246
        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

246
        return $this->descendantsAndSelf()->/** @scrutinizer ignore-call */ whereDepth('<=', 1);
Loading history...
247
    }
248
249 92
    /**
250
     * Get the model's descendants.
251 92
     *
252
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Descendants
253
     */
254
    public function descendants()
255
    {
256
        return $this->newDescendants(
257
            (new static())->newQuery(),
258
            $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

258
            /** @scrutinizer ignore-type */ $this,
Loading history...
259 5
            $this->getQualifiedParentKeyName(),
260
            $this->getLocalKeyName(),
261 5
            false
262
        );
263
    }
264
265
    /**
266
     * Get the model's descendants and itself.
267
     *
268
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Descendants
269 5
     */
270
    public function descendantsAndSelf()
271 5
    {
272
        return $this->newDescendants(
273
            (new static())->newQuery(),
274
            $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

274
            /** @scrutinizer ignore-type */ $this,
Loading history...
275
            $this->getQualifiedParentKeyName(),
276
            $this->getLocalKeyName(),
277
            true
278
        );
279 25
    }
280
281 25
    /**
282 25
     * Instantiate a new Descendants relationship.
283
     *
284 25
     * @param \Illuminate\Database\Eloquent\Builder $query
285 25
     * @param \Illuminate\Database\Eloquent\Model $parent
286
     * @param string $foreignKey
287
     * @param string $localKey
288
     * @param bool $andSelf
289
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Descendants
290
     */
291
    protected function newDescendants(Builder $query, Model $parent, $foreignKey, $localKey, $andSelf)
292
    {
293
        return new Descendants($query, $parent, $foreignKey, $localKey, $andSelf);
294
    }
295
296
    /**
297
     * Get the model's parent.
298 25
     *
299
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
300 25
     */
301
    public function parent()
302
    {
303
        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

303
        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...
304
    }
305
306
    /**
307
     * Get the model's parent and itself.
308 35
     *
309
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Ancestors
310 35
     */
311 35
    public function parentAndSelf()
312
    {
313 35
        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

313
        return $this->ancestorsAndSelf()->/** @scrutinizer ignore-call */ whereDepth('>=', -1);
Loading history...
314 35
    }
315 35
316
    /**
317
     * Get the model's root ancestor.
318
     *
319
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\RootAncestor
320
     */
321
    public function rootAncestor()
322
    {
323
        return $this->newRootAncestor(
324 30
            (new static())->newQuery(),
325
            $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

325
            /** @scrutinizer ignore-type */ $this,
Loading history...
326 30
            $this->getQualifiedParentKeyName(),
327 30
            $this->getLocalKeyName()
328
        );
329 30
    }
330 30
331 30
    /**
332
     * Instantiate a new RootAncestor relationship.
333
     *
334
     * @param \Illuminate\Database\Eloquent\Builder $query
335
     * @param \Illuminate\Database\Eloquent\Model $parent
336
     * @param string $foreignKey
337
     * @param string $localKey
338
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\RootAncestor
339
     */
340
    protected function newRootAncestor(Builder $query, Model $parent, $foreignKey, $localKey)
341
    {
342
        return new RootAncestor($query, $parent, $foreignKey, $localKey);
343
    }
344
345 65
    /**
346
     * Get the model's siblings.
347 65
     *
348
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Siblings
349
     */
350
    public function siblings()
351
    {
352
        return $this->newSiblings(
353
            (new static())->newQuery(),
354
            $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

354
            /** @scrutinizer ignore-type */ $this,
Loading history...
355 60
            $this->getQualifiedParentKeyName(),
356
            $this->getParentKeyName(),
357 60
            false
358
        );
359 60
    }
360
361
    /**
362
     * Get the model's siblings and itself.
363
     *
364
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Siblings
365
     */
366
    public function siblingsAndSelf()
367 10
    {
368
        return $this->newSiblings(
369 10
            (new static())->newQuery(),
370
            $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

370
            /** @scrutinizer ignore-type */ $this,
Loading history...
371 10
            $this->getQualifiedParentKeyName(),
372
            $this->getParentKeyName(),
373
            true
374
        );
375
    }
376
377
    /**
378
     * Instantiate a new Siblings relationship.
379
     *
380 88
     * @param \Illuminate\Database\Eloquent\Builder $query
381
     * @param \Illuminate\Database\Eloquent\Model $parent
382 88
     * @param string $foreignKey
383
     * @param string $localKey
384 88
     * @param bool $andSelf
385
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Siblings
386
     */
387
    protected function newSiblings(Builder $query, Model $parent, $foreignKey, $localKey, $andSelf)
388
    {
389
        return new Siblings($query, $parent, $foreignKey, $localKey, $andSelf);
390
    }
391
392
    /**
393 678
     * Get the first segment of the model's path.
394
     *
395 678
     * @return string
396
     */
397
    public function getFirstPathSegment()
398
    {
399
        $path = $this->attributes[$this->getPathName()];
400
401
        return explode($this->getPathSeparator(), $path)[0];
402
    }
403
404 673
    /**
405
     * Determine whether the model's path is nested.
406 673
     *
407
     * @return bool
408
     */
409
    public function hasNestedPath()
410
    {
411
        $path = $this->attributes[$this->getPathName()];
412
413
        return Str::contains($path, $this->getPathSeparator());
414
    }
415
416
    /**
417
     * Determine if an attribute is an integer.
418
     *
419
     * @param string $attribute
420
     * @return bool
421
     */
422
    public function isIntegerAttribute($attribute)
423
    {
424
        $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

424
        /** @scrutinizer ignore-call */ 
425
        $casts = $this->getCasts();
Loading history...
425
426
        return isset($casts[$attribute]) && in_array($casts[$attribute], ['int', 'integer']);
427
    }
428
429
    /**
430
     * Create a new Eloquent query builder for the model.
431
     *
432
     * @param \Illuminate\Database\Query\Builder $query
433
     * @return \Illuminate\Database\Eloquent\Builder|static
434
     */
435
    public function newEloquentBuilder($query)
436
    {
437
        return new \Staudenmeir\LaravelAdjacencyList\Eloquent\Builder($query);
438
    }
439
440
    /**
441
     * Create a new Eloquent Collection instance.
442
     *
443
     * @param array $models
444
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Collection
445
     */
446
    public function newCollection(array $models = [])
447
    {
448
        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

448
        return new Collection(/** @scrutinizer ignore-type */ $models);
Loading history...
449
    }
450
}
451