Passed
Push — master ( 51edae...d29a9b )
by Curtis
11:52 queued 05:54
created

TreeBuilder::menus()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 4
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 7
rs 10
1
<?php
2
3
namespace App\Service\enso\menus;
4
5
use Illuminate\Support\Collection;
6
use Illuminate\Support\Facades\Auth;
7
use Illuminate\Support\Str;
8
use App\Models\enso\Menus\Menu;
9
10
class TreeBuilder
11
{
12
    private Collection $permissions;
13
    private Collection $menus;
14
15
    public function handle()
16
    {
17
        return $this->permissions()
18
            ->menus()
19
            ->filter()
20
            ->map()
21
            ->build();
22
    }
23
24
    private function build(?int $parentId = null): Collection
25
    {
26
        return $this->menus
27
            ->filter(fn ($menu) => $menu->parent_id === $parentId)
28
            ->reduce(fn ($tree, $menu) => $tree
29
                ->push($this->withChildren($menu)), new Collection());
30
    }
31
32
    private function withChildren(Menu $menu): Menu
33
    {
34
        $menu->children = $menu->has_children
35
            ? $this->build($menu->id)
36
            : null;
37
38
        $menu->route = optional($menu->permission)->name;
0 ignored issues
show
Bug introduced by
The property route does not seem to exist on App\Models\enso\Menus\Menu. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
39
40
        unset($menu->permission);
41
42
        return $menu;
43
    }
44
45
    private function permissions(): self
46
    {
47
        $this->permissions = Auth::user()->role
0 ignored issues
show
Bug introduced by
Accessing role on the interface Illuminate\Contracts\Auth\Authenticatable suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
48
            ->permissions()
49
            ->has('menu')
50
            ->get(['id', 'name']);
51
52
        return $this;
53
    }
54
55
    private function menus(): self
56
    {
57
        $this->menus = Menu::with('permission:id,name')
58
            ->orderBy('order_index')
59
            ->get(['id', 'parent_id', 'permission_id', 'name', 'icon', 'has_children']);
60
61
        return $this;
62
    }
63
64
    private function filter(): self
65
    {
66
        $this->menus = $this->menus->filter(fn ($menu) => $this->allowed($menu));
67
68
        return $this;
69
    }
70
71
    private function map(): self
72
    {
73
        $this->menus = $this->menus->map(fn ($menu) => $this->computeIcon($menu));
74
75
        return $this;
76
    }
77
78
    private function computeIcon(Menu $menu): Menu
79
    {
80
        if (Str::contains($menu->icon, ' ')) {
81
            $menu->icon = explode(' ', $menu->icon);
82
        }
83
84
        return $menu;
85
    }
86
87
    private function allowed($menu): bool
88
    {
89
        return $this->permissions->pluck('id')->contains($menu->permission_id)
90
            || $menu->has_children && $this->someChildrenAllowed($menu);
91
    }
92
93
    private function someChildrenAllowed($parent): bool
94
    {
95
        return $this->menus->some(
96
            fn ($child) => $child->parent_id === $parent->id && $this->allowed($child)
97
        );
98
    }
99
}
100