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

HasGraphAdjacencyList::getDepthName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
ccs 1
cts 1
cp 1
cc 1
nc 1
nop 0
crap 1
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