Passed
Push — master ( e6bb40...c8f69f )
by Jonas
03:17 queued 12s
created

HasGraphAdjacencyList::newDescendants()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 19
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 9
c 1
b 0
f 0
dl 0
loc 19
ccs 10
cts 10
cp 1
rs 9.9666
cc 1
nc 1
nop 8
crap 1

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace Staudenmeir\LaravelAdjacencyList\Eloquent\Traits;
4
5
use Illuminate\Database\Eloquent\Builder;
6
use Illuminate\Database\Eloquent\Model;
7
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
8
use Staudenmeir\LaravelAdjacencyList\Eloquent\Graph\Collection;
9
use Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Graph\Ancestors;
10
use Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Graph\Descendants;
11
12
trait HasGraphAdjacencyList
13
{
14
    use HasGraphRelationshipScopes;
15
16
    /**
17
     * The additional constraint for the recursive query.
18
     *
19
     * @var callable|null
20
     */
21
    public static $recursiveQueryConstraint;
22
23
    /**
24
     * Get the name of the pivot table.
25
     *
26
     * @return string
27
     */
28
    abstract public function getPivotTableName(): string;
29
30
    /**
31
     * Get the name of the parent key column.
32
     *
33
     * @return string
34 248
     */
35
    public function getParentKeyName(): string
36 248
    {
37
        return 'parent_id';
38
    }
39
40
    /**
41
     * Get the qualified parent key column.
42
     *
43
     * @return string
44 270
     */
45
    public function getQualifiedParentKeyName()
46 270
    {
47
        return $this->getPivotTableName() . '.' . $this->getParentKeyName();
48
    }
49
50
    /**
51
     * Get the name of the child key column.
52
     *
53
     * @return string
54 248
     */
55
    public function getChildKeyName(): string
56 248
    {
57
        return 'child_id';
58
    }
59
60
    /**
61
     * Get the qualified child key column.
62
     *
63
     * @return string
64 270
     */
65
    public function getQualifiedChildKeyName()
66 270
    {
67
        return $this->getPivotTableName() . '.' . $this->getChildKeyName();
68
    }
69
70
    /**
71
     * Get the name of the local key column.
72
     *
73
     * @return string
74 248
     */
75
    public function getLocalKeyName(): string
76 248
    {
77
        return $this->getKeyName();
0 ignored issues
show
Bug introduced by
The method getKeyName() does not exist on Staudenmeir\LaravelAdjac...s\HasGraphAdjacencyList. Did you maybe mean getChildKeyName()? ( Ignorable by Annotation )

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

77
        return $this->/** @scrutinizer ignore-call */ getKeyName();

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...
78
    }
79
80
    /**
81
     * Get the qualified local key column.
82
     *
83
     * @return string
84 270
     */
85
    public function getQualifiedLocalKeyName(): string
86 270
    {
87 270
        return $this->qualifyColumn(
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

87
        return $this->/** @scrutinizer ignore-call */ qualifyColumn(
Loading history...
88 270
            $this->getLocalKeyName()
89
        );
90
    }
91
92
    /**
93
     * Get the name of the depth column.
94
     *
95
     * @return string
96 270
     */
97
    public function getDepthName(): string
98 270
    {
99
        return 'depth';
100
    }
101
102
    /**
103
     * Get the name of the path column.
104
     *
105
     * @return string
106 272
     */
107
    public function getPathName(): string
108 272
    {
109
        return 'path';
110
    }
111
112
    /**
113
     * Get the path separator.
114
     *
115
     * @return string
116 270
     */
117
    public function getPathSeparator(): string
118 270
    {
119
        return '.';
120
    }
121
122
    /**
123
     * Get the additional custom paths.
124
     *
125
     * @return array
126 270
     */
127
    public function getCustomPaths(): array
128 270
    {
129
        return [];
130
    }
131
132
    /**
133
     * Get the pivot table columns to retrieve.
134
     *
135
     * @return array
136 280
     */
137
    public function getPivotColumns(): array
138 280
    {
139
        return [];
140
    }
141
142
    /**
143
     * Get the name of the common table expression.
144
     *
145
     * @return string
146 270
     */
147
    public function getExpressionName(): string
148 270
    {
149
        return 'laravel_cte';
150
    }
151
152
    /**
153
     * Whether to enable cycle detection.
154
     *
155
     * @return bool
156 154
     */
157
    public function enableCycleDetection(): bool
158 154
    {
159
        return false;
160
    }
161
162
    /**
163
     * Whether to include the first row of the cycle in the query results.
164
     *
165
     * @return bool
166 58
     */
167
    public function includeCycleStart(): bool
168 58
    {
169
        return false;
170
    }
171
172
    /**
173
     * Get the name of the cycle detection column.
174
     *
175
     * @return string
176 58
     */
177
    public function getCycleDetectionColumnName(): string
178 58
    {
179
        return 'is_cycle';
180
    }
181
182
    /**
183
     * Get the model's ancestors.
184
     *
185
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Graph\Ancestors<static>
186 87
     */
187
    public function ancestors(): Ancestors
188 87
    {
189 87
        return $this->newAncestors(
190 87
            (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

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

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

191
            /** @scrutinizer ignore-type */ $this,
Loading history...
192 87
            $this->getPivotTableName(),
193 87
            $this->getParentKeyName(),
194 87
            $this->getChildKeyName(),
195 87
            $this->getLocalKeyName(),
196 87
            $this->getLocalKeyName(),
197 87
            false
198
        );
199
    }
200
201
    /**
202
     * Get the model's ancestors and itself.
203
     *
204
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Graph\Ancestors<static>
205 41
     */
206
    public function ancestorsAndSelf(): Ancestors
207 41
    {
208 41
        return $this->newAncestors(
209 41
            (new static())->newQuery(),
210 41
            $this,
0 ignored issues
show
Bug introduced by
$this of type Staudenmeir\LaravelAdjac...s\HasGraphAdjacencyList is incompatible with the type Illuminate\Database\Eloquent\Model expected by parameter $parent of Staudenmeir\LaravelAdjac...ncyList::newAncestors(). ( Ignorable by Annotation )

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

210
            /** @scrutinizer ignore-type */ $this,
Loading history...
211 41
            $this->getPivotTableName(),
212 41
            $this->getParentKeyName(),
213 41
            $this->getChildKeyName(),
214 41
            $this->getLocalKeyName(),
215 41
            $this->getLocalKeyName(),
216 41
            true
217
        );
218
    }
219
220
    /**
221
     * Instantiate a new Ancestors relationship.
222
     *
223
     * @param \Illuminate\Database\Eloquent\Builder $query
224
     * @param \Illuminate\Database\Eloquent\Model $parent
225
     * @param string $table
226
     * @param string $foreignPivotKey
227
     * @param string $relatedPivotKey
228
     * @param string $parentKey
229
     * @param string $relatedKey
230
     * @param bool $andSelf
231
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Graph\Ancestors<static>
232 128
     */
233
    protected function newAncestors(
234
        Builder $query,
235
        Model $parent,
236
        string $table,
237
        string $foreignPivotKey,
238
        string $relatedPivotKey,
239
        string $parentKey,
240
        string $relatedKey,
241
        bool $andSelf
242 128
    ): Ancestors {
243 128
        return new Ancestors(
244 128
            $query,
245 128
            $parent,
246 128
            $table,
247 128
            $foreignPivotKey,
248 128
            $relatedPivotKey,
249 128
            $parentKey,
250 128
            $relatedKey,
251 128
            $andSelf
252
        );
253
    }
254
255
    /**
256
     * Get the model's children.
257
     *
258
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany<static>
259 5
     */
260
    public function children(): BelongsToMany
261 5
    {
262 5
        return $this->belongsToMany(
0 ignored issues
show
Bug introduced by
It seems like belongsToMany() 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

262
        return $this->/** @scrutinizer ignore-call */ belongsToMany(
Loading history...
263 5
            static::class,
264 5
            $this->getPivotTableName(),
265 5
            $this->getParentKeyName(),
266 5
            $this->getChildKeyName(),
267 5
            $this->getLocalKeyName(),
268 5
            $this->getLocalKeyName()
269 5
        )->withPivot(
270 5
            $this->getPivotColumns()
271
        );
272
    }
273
274
    /**
275
     * Get the model's children and itself.
276
     *
277
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Graph\Descendants<static>
278 4
     */
279
    public function childrenAndSelf(): Descendants
280 4
    {
281
        return $this->descendantsAndSelf()->whereDepth('<=', 1);
0 ignored issues
show
Bug introduced by
The method whereDepth() does not exist on Staudenmeir\LaravelAdjac...tions\Graph\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

281
        return $this->descendantsAndSelf()->/** @scrutinizer ignore-call */ whereDepth('<=', 1);
Loading history...
282
    }
283
284
    /**
285
     * Get the model's descendants.
286
     *
287
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Graph\Descendants<static>
288 111
     */
289
    public function descendants(): Descendants
290 111
    {
291 111
        return $this->newDescendants(
292 111
            (new static())->newQuery(),
293 111
            $this,
0 ignored issues
show
Bug introduced by
$this of type Staudenmeir\LaravelAdjac...s\HasGraphAdjacencyList is incompatible with the type Illuminate\Database\Eloquent\Model expected by parameter $parent of Staudenmeir\LaravelAdjac...yList::newDescendants(). ( Ignorable by Annotation )

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

293
            /** @scrutinizer ignore-type */ $this,
Loading history...
294 111
            $this->getPivotTableName(),
295 111
            $this->getParentKeyName(),
296 111
            $this->getChildKeyName(),
297 111
            $this->getLocalKeyName(),
298 111
            $this->getLocalKeyName(),
299 111
            false
300
        );
301
    }
302
303
    /**
304
     * Get the model's descendants and itself.
305
     *
306
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Graph\Descendants<static>
307 47
     */
308
    public function descendantsAndSelf(): Descendants
309 47
    {
310 47
        return $this->newDescendants(
311 47
            (new static())->newQuery(),
312 47
            $this,
0 ignored issues
show
Bug introduced by
$this of type Staudenmeir\LaravelAdjac...s\HasGraphAdjacencyList is incompatible with the type Illuminate\Database\Eloquent\Model expected by parameter $parent of Staudenmeir\LaravelAdjac...yList::newDescendants(). ( Ignorable by Annotation )

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

312
            /** @scrutinizer ignore-type */ $this,
Loading history...
313 47
            $this->getPivotTableName(),
314 47
            $this->getParentKeyName(),
315 47
            $this->getChildKeyName(),
316 47
            $this->getLocalKeyName(),
317 47
            $this->getLocalKeyName(),
318 47
            true
319
        );
320
    }
321
322
    /**
323
     * Instantiate a new Descendants relationship.
324
     *
325
     * @param \Illuminate\Database\Eloquent\Builder $query
326
     * @param \Illuminate\Database\Eloquent\Model $parent
327
     * @param string $table
328
     * @param string $foreignPivotKey
329
     * @param string $relatedPivotKey
330
     * @param string $parentKey
331
     * @param string $relatedKey
332
     * @param bool $andSelf
333
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Graph\Descendants<static>
334 158
     */
335
    protected function newDescendants(
336
        Builder $query,
337
        Model $parent,
338
        string $table,
339
        string $foreignPivotKey,
340
        string $relatedPivotKey,
341
        string $parentKey,
342
        string $relatedKey,
343
        bool $andSelf
344 158
    ): Descendants {
345 158
        return new Descendants(
346 158
            $query,
347 158
            $parent,
348 158
            $table,
349 158
            $foreignPivotKey,
350 158
            $relatedPivotKey,
351 158
            $parentKey,
352 158
            $relatedKey,
353 158
            $andSelf
354
        );
355
    }
356
357
    /**
358
     * Get the model's parents.
359
     *
360
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany<static>
361 5
     */
362
    public function parents(): BelongsToMany
363 5
    {
364 5
        return $this->belongsToMany(
365 5
            static::class,
366 5
            $this->getPivotTableName(),
367 5
            $this->getChildKeyName(),
368 5
            $this->getParentKeyName(),
369 5
            $this->getLocalKeyName(),
370 5
            $this->getLocalKeyName()
371 5
        )->withPivot(
372 5
            $this->getPivotColumns()
373
        );
374
    }
375
376
    /**
377
     * Get the model's parents and itself.
378
     *
379
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Graph\Ancestors<static>
380 4
     */
381
    public function parentsAndSelf(): Ancestors
382 4
    {
383
        return $this->ancestorsAndSelf()->whereDepth('>=', -1);
0 ignored issues
show
Bug introduced by
The method whereDepth() does not exist on Staudenmeir\LaravelAdjac...lations\Graph\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

383
        return $this->ancestorsAndSelf()->/** @scrutinizer ignore-call */ whereDepth('>=', -1);
Loading history...
384
    }
385
386
    /**
387
     * Get the first segment of the model's path.
388
     *
389
     * @return string
390 88
     */
391
    public function getFirstPathSegment(): string
392 88
    {
393
        $path = $this->attributes[$this->getPathName()];
394 88
395
        return explode($this->getPathSeparator(), $path)[0];
396
    }
397
398
    /**
399
     * Determine if an attribute is an integer.
400
     *
401
     * @param string $attribute
402
     * @return bool
403 68
     */
404
    public function isIntegerAttribute(string $attribute): bool
405 68
    {
406 68
        $segments = explode('.', $attribute);
407
        $attribute = end($segments);
408 68
409
        $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

409
        /** @scrutinizer ignore-call */ 
410
        $casts = $this->getCasts();
Loading history...
410 68
411
        return isset($casts[$attribute]) && in_array($casts[$attribute], ['int', 'integer']);
412
    }
413
414
    /**
415
     * Create a new Eloquent query builder for the model.
416
     *
417
     * @param \Illuminate\Database\Query\Builder $query
418
     * @return \Illuminate\Database\Eloquent\Builder|static
419 280
     */
420
    public function newEloquentBuilder($query)
421 280
    {
422
        return new \Staudenmeir\LaravelAdjacencyList\Eloquent\Builder($query);
423
    }
424
425
    /**
426
     * Create a new Eloquent Collection instance.
427
     *
428
     * @param array $models
429
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Graph\Collection
430 5
     */
431
    public function newCollection(array $models = [])
432 5
    {
433
        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

433
        return new Collection(/** @scrutinizer ignore-type */ $models);
Loading history...
434
    }
435
436
    /**
437
     * Set an additional constraint for the recursive query.
438
     *
439
     * @param callable $constraint
440 5
     * @return void
441
     */
442 5
    public static function setRecursiveQueryConstraint(callable $constraint): void
443
    {
444
        static::$recursiveQueryConstraint = $constraint;
445
    }
446
447
    /**
448
     * Unset the additional constraint for the recursive query.
449
     *
450
     * @return void
451
     */
452 15
    public static function unsetRecursiveQueryConstraint(): void
453
    {
454 15
        static::$recursiveQueryConstraint = null;
455
    }
456 15
457
    /**
458 15
     * Execute a query with an additional constraint for the recursive query.
459
     *
460 15
     * @param callable $constraint
461
     * @param callable $query
462 15
     * @return mixed
463
     */
464
    public static function withRecursiveQueryConstraint(callable $constraint, callable $query): mixed
465
    {
466
        $previous = static::$recursiveQueryConstraint;
467
468
        static::$recursiveQueryConstraint = $constraint;
469
470
        $result = $query();
471
472 10
        static::$recursiveQueryConstraint = $previous;
473
474 10
        return $result;
475
    }
476 10
477 10
    /**
478 10
     * Execute a query with a maximum depth constraint for the recursive query.
479 10
     *
480
     * @param int $maxDepth
481
     * @param callable $query
482
     * @return mixed
483
     */
484
    public static function withMaxDepth(int $maxDepth, callable $query): mixed
485
    {
486
        $operator = $maxDepth > 0 ? '<' : '>';
487
488
        return static::withRecursiveQueryConstraint(
489
            fn (Builder $query) => $query->whereDepth($operator, $maxDepth),
490
            $query
491
        );
492
    }
493
}
494