Passed
Push — master ( 1e5d16...77daa9 )
by Jonas
04:19
created

HasGraphAdjacencyList::newAncestors()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 19
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
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 2
cts 2
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\Relations\Graph\Ancestors;
9
use Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Graph\Descendants;
10
11
trait HasGraphAdjacencyList
12
{
13
    use HasGraphRelationshipScopes;
14
15
    /**
16
     * The additional constraint for the recursive query.
17
     *
18
     * @var callable|null
19
     */
20
    public static $recursiveQueryConstraint;
21
22
    /**
23
     * Get the name of the pivot table.
24
     *
25
     * @return string
26
     */
27
    abstract public function getPivotTableName(): string;
28
29
    /**
30
     * Get the name of the parent key column.
31
     *
32
     * @return string
33
     */
34 222
    public function getParentKeyName(): string
35
    {
36 222
        return 'parent_id';
37
    }
38
39
    /**
40
     * Get the qualified parent key column.
41
     *
42
     * @return string
43
     */
44 214
    public function getQualifiedParentKeyName()
45
    {
46 214
        return $this->getPivotTableName() . '.' . $this->getParentKeyName();
47
    }
48
49
    /**
50
     * Get the name of the child key column.
51
     *
52
     * @return string
53
     */
54 222
    public function getChildKeyName(): string
55
    {
56 222
        return 'child_id';
57
    }
58
59
    /**
60
     * Get the qualified child key column.
61
     *
62
     * @return string
63
     */
64 214
    public function getQualifiedChildKeyName()
65
    {
66 214
        return $this->getPivotTableName() . '.' . $this->getChildKeyName();
67
    }
68
69
    /**
70
     * Get the name of the local key column.
71
     *
72
     * @return string
73
     */
74 222
    public function getLocalKeyName(): string
75
    {
76 222
        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

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

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

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

190
            /** @scrutinizer ignore-type */ $this,
Loading history...
191 62
            $this->getPivotTableName(),
192 62
            $this->getParentKeyName(),
193 62
            $this->getChildKeyName(),
194 62
            $this->getLocalKeyName(),
195 62
            $this->getLocalKeyName(),
196
            false
197
        );
198
    }
199
200
    /**
201
     * Get the model's ancestors and itself.
202
     *
203
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Graph\Ancestors
204
     */
205 41
    public function ancestorsAndSelf(): Ancestors
206
    {
207 41
        return $this->newAncestors(
208 41
            (new static())->newQuery(),
209
            $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

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

261
        return $this->/** @scrutinizer ignore-call */ belongsToMany(
Loading history...
262
            static::class,
263 4
            $this->getPivotTableName(),
264 4
            $this->getParentKeyName(),
265 4
            $this->getChildKeyName(),
266 4
            $this->getLocalKeyName(),
267 4
            $this->getLocalKeyName()
268
        );
269
    }
270
271
    /**
272
     * Get the model's children and itself.
273
     *
274
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Graph\Descendants
275
     */
276 4
    public function childrenAndSelf(): Descendants
277
    {
278 4
        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

278
        return $this->descendantsAndSelf()->/** @scrutinizer ignore-call */ whereDepth('<=', 1);
Loading history...
279
    }
280
281
    /**
282
     * Get the model's descendants.
283
     *
284
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Graph\Descendants
285
     */
286 80
    public function descendants(): Descendants
287
    {
288 80
        return $this->newDescendants(
289 80
            (new static())->newQuery(),
290
            $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

290
            /** @scrutinizer ignore-type */ $this,
Loading history...
291 80
            $this->getPivotTableName(),
292 80
            $this->getParentKeyName(),
293 80
            $this->getChildKeyName(),
294 80
            $this->getLocalKeyName(),
295 80
            $this->getLocalKeyName(),
296
            false
297
        );
298
    }
299
300
    /**
301
     * Get the model's descendants and itself.
302
     *
303
     * @return \Staudenmeir\LaravelAdjacencyList\Eloquent\Relations\Graph\Descendants
304
     */
305 47
    public function descendantsAndSelf(): Descendants
306
    {
307 47
        return $this->newDescendants(
308 47
            (new static())->newQuery(),
309
            $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

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

378
        return $this->ancestorsAndSelf()->/** @scrutinizer ignore-call */ whereDepth('>=', -1);
Loading history...
379
    }
380
381
    /**
382
     * Get the first segment of the model's path.
383
     *
384
     * @return string
385
     */
386 64
    public function getFirstPathSegment(): string
387
    {
388 64
        $path = $this->attributes[$this->getPathName()];
389
390 64
        return explode($this->getPathSeparator(), $path)[0];
391
    }
392
393
    /**
394
     * Determine if an attribute is an integer.
395
     *
396
     * @param string $attribute
397
     * @return bool
398
     */
399 60
    public function isIntegerAttribute(string $attribute): bool
400
    {
401 60
        $segments = explode('.', $attribute);
402 60
        $attribute = end($segments);
403
404 60
        $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 60
        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 222
    public function newEloquentBuilder($query)
416
    {
417 222
        return new \Staudenmeir\LaravelAdjacencyList\Eloquent\Builder($query);
418
    }
419
420
    /**
421
     * Set an additional constraint for the recursive query.
422
     *
423
     * @param callable $constraint
424
     * @return void
425
     */
426 4
    public static function setRecursiveQueryConstraint(callable $constraint): void
427
    {
428 4
        static::$recursiveQueryConstraint = $constraint;
429
    }
430
431
    /**
432
     * Unset the additional constraint for the recursive query.
433
     *
434
     * @return void
435
     */
436 4
    public static function unsetRecursiveQueryConstraint(): void
437
    {
438 4
        static::$recursiveQueryConstraint = null;
439
    }
440
441
    /**
442
     * Execute a query with an additional constraint for the recursive query.
443
     *
444
     * @param callable $constraint
445
     * @param callable $query
446
     * @return mixed
447
     */
448 12
    public static function withRecursiveQueryConstraint(callable $constraint, callable $query): mixed
449
    {
450 12
        $previous = static::$recursiveQueryConstraint;
451
452 12
        static::$recursiveQueryConstraint = $constraint;
453
454 12
        $result = $query();
455
456 12
        static::$recursiveQueryConstraint = $previous;
457
458 12
        return $result;
459
    }
460
461
    /**
462
     * Execute a query with a maximum depth constraint for the recursive query.
463
     *
464
     * @param int $maxDepth
465
     * @param callable $query
466
     * @return mixed
467
     */
468 8
    public static function withMaxDepth(int $maxDepth, callable $query): mixed
469
    {
470 8
        $operator = $maxDepth > 0 ? '<' : '>';
471
472 8
        return static::withRecursiveQueryConstraint(
473 8
            fn (Builder $query) => $query->whereDepth($operator, $maxDepth),
474
            $query
475
        );
476
    }
477
}
478