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

HasGraphAdjacencyList::getLocalKeyName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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