Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.61% covered (success)
96.61%
57 / 59
88.89% covered (warning)
88.89%
8 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
Menu
96.61% covered (success)
96.61%
57 / 59
88.89% covered (warning)
88.89%
8 / 9
24
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 rewind
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 current
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 key
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 next
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 valid
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 html
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 compileHtml
94.87% covered (success)
94.87%
37 / 39
0.00% covered (danger)
0.00%
0 / 1
12.02
 makeTree
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
4
1<?php
2
3declare(strict_types=1);
4
5namespace Cosray\Finder;
6
7use Cosray\Context;
8use Cosray\Exception\RuntimeException;
9use Iterator;
10
11class Menu implements Iterator
12{
13    protected array $items;
14    protected int $pointer = 0;
15
16    public function __construct(
17        protected readonly Context $context,
18        string $menu,
19    ) {
20        $this->items = $this->makeTree(
21            $context->db->menus->get(['menu' => $menu])->all(),
22        );
23
24        if (count($this->items) === 0) {
25            throw new RuntimeException('Menu not found');
26        }
27    }
28
29    public function rewind(): void
30    {
31        reset($this->items);
32    }
33
34    public function current(): MenuItem
35    {
36        return new MenuItem($this->context, current($this->items));
37    }
38
39    public function key(): string
40    {
41        return key($this->items);
42    }
43
44    public function next(): void
45    {
46        next($this->items);
47    }
48
49    public function valid(): bool
50    {
51        return key($this->items) !== null;
52    }
53
54    public function html(string $class = '', string $tag = 'nav'): string
55    {
56        return $this->compileHtml($this, $class, $tag);
57    }
58
59    protected function compileHtml(
60        Iterator $items,
61        string $class = '',
62        string $tag = 'nav',
63    ): string {
64        $out = '';
65
66        foreach ($items as $item) {
67            $class = $item->class();
68            $image = $item->image() ?: '';
69
70            if ($image) {
71                $image = sprintf('<div class="nav-image"><img src="%s" alt="Navigation Icon"/></div>', $image);
72            }
73
74            $submenu = $this->compileHtml($item->children(), tag: '');
75
76            if ($submenu) {
77                $submenu = sprintf('<div class="nav-submenu">%s</div>', $submenu);
78            }
79
80            $content = sprintf(
81                '%s<div class="nav-label"><span>%s</span></div>%s',
82                $image,
83                $item->title(),
84                $submenu,
85            );
86
87            $content = match ($item->type()) {
88                'page' => sprintf('<a href="%s">%s</a>', $item->path(), $content),
89                default => $content,
90            };
91
92            $out .= sprintf(
93                '<li class="nav-level-%s%s%s">%s</li>',
94                (string) $item->level(),
95                $item->hasChildren() ? ' nav-has-children' : '',
96                $class ? ' ' . $class : '',
97                $content,
98            );
99        }
100
101        if ($out) {
102            $class = $class ? sprintf(' class="%s"', $class) : '';
103
104            return $tag
105                ? sprintf(
106                    '<%s%s><ul class="nav-level-%s">%s</ul></%s>',
107                    $tag,
108                    $class,
109                    $item->level(),
110                    $out,
111                    $tag,
112                )
113                : sprintf('<ul%s class="nav-level-%s">%s</ul>', $class, $item->level(), $out);
114        }
115
116        return '';
117    }
118
119    protected function makeTree(array $items): array
120    {
121        $tree = [];
122
123        foreach ($items as $item) {
124            $arr = &$tree;
125
126            foreach (explode('.', $item['path']) as $segment) {
127                if (isset($arr[$segment])) {
128                    $arr = &$arr[$segment]['children'];
129                } else {
130                    $arr[$segment] = $item;
131                    $arr[$segment]['children'] = [];
132                }
133            }
134        }
135
136        return $tree;
137    }
138}