Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
80.56% covered (warning)
80.56%
29 / 36
64.52% covered (warning)
64.52%
20 / 31
30.56% covered (danger)
30.56%
11 / 36
54.55% covered (warning)
54.55%
6 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
MenuTwig
80.56% covered (warning)
80.56%
29 / 36
64.52% covered (warning)
64.52%
20 / 31
30.56% covered (danger)
30.56%
11 / 36
54.55% covered (warning)
54.55%
6 / 11
153.96
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getFunctions
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 newItem
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 addItem
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
6 / 6
50.00% covered (danger)
50.00%
2 / 4
100.00% covered (success)
100.00%
1 / 1
4.12
 getItem
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getUrl
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 isMenuItemActive
66.67% covered (warning)
66.67%
6 / 9
50.00% covered (danger)
50.00%
7 / 14
13.64% covered (danger)
13.64%
3 / 22
0.00% covered (danger)
0.00%
0 / 1
38.56
 isUrlMenuItemActive
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getMenuItems
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getMenuSubItems
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getMenuOptions
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace App\Menu;
4
5use Symfony\Component\HttpFoundation\Request;
6use Symfony\Component\HttpFoundation\RequestStack;
7use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
8use Symfony\Component\Routing\Router;
9use Symfony\Component\Routing\RouterInterface;
10use Twig\Extension\AbstractExtension;
11use Twig\TwigFunction;
12
13class MenuTwig extends AbstractExtension
14{
15    /**
16     * @var array<array<array<MenuItem>>>
17     */
18    public array $menu = [];
19    public UrlGeneratorInterface $urlGenerator;
20    public ?Request $request;
21    public string $activeUri;
22
23    public function __construct(RouterInterface $router, RequestStack $requestStack)
24    {
25        /** @var Router $r */
26        $r = $router;
27        $this->urlGenerator = $r->getGenerator();
28        $this->request = $requestStack->getCurrentRequest();
29    }
30
31    public function getFunctions(): array
32    {
33        return [
34            new TwigFunction('getMenuItems', [$this, 'getMenuItems']),
35            new TwigFunction('getMenuSubItems', [$this, 'getMenuSubItems']),
36            new TwigFunction('getMenuOptions', [$this, 'getMenuOptions']),
37            new TwigFunction('isMenuItemActive', [$this, 'isMenuItemActive']),
38            new TwigFunction('isUrlMenuItemActive', [$this, 'isUrlMenuItemActive']),
39            new TwigFunction('addMenuItem', [$this, 'addItem']),
40            new TwigFunction('newMenuItem', [$this, 'newItem']),
41        ];
42    }
43
44    /**
45     * @param array<array<mixed>>|null $routeParams
46     * @param array<array<mixed>>|null $options
47     * @param MenuItem[]|null          $subItems
48     */
49    public function newItem(
50        string $id,
51        ?string $label,
52        ?string $route,
53        ?array $routeParams = [],
54        ?array $options = [],
55        ?array $subItems = [],
56    ): MenuItem {
57        return new MenuItem($id, $label, $route, $routeParams, $options, $subItems);
58    }
59
60    public function addItem(string $menuName, MenuItem $item): MenuTwig
61    {
62        $item->url = $this->getUrl($item);
63
64        if ($item->subItems) {
65            foreach ($item->subItems as $subItem) {
66                $subItem->url = $this->getUrl($subItem);
67            }
68        }
69        $this->menu[$menuName]['items'][$item->label] = $item;
70
71        return $this;
72    }
73
74    public function getItem(string $menuName, string $label): MenuItem|bool
75    {
76        return $this->menu[$menuName]['items'][$label] ?? false;
77    }
78
79    public function getUrl(MenuItem $item): ?string
80    {
81        if ($item->route) {
82            return $this->urlGenerator->generate($item->route, $item->routeParams ?? []);
83        }
84
85        /** @var ?string */
86        return $item->options['url'] ?? null;
87    }
88
89    public function isMenuItemActive(MenuItem $item): bool
90    {
91        $activeRoute = $this->request?->get('_route');
92        if ($item->route && $activeRoute == $item->route) {
93            return true;
94        }
95        $routes = $item->options['activeRoutes'] ?? false;
96        if ($routes && is_iterable($routes)) {
97            foreach ($routes as $route) {
98                if ($activeRoute == $route) {
99                    return true;
100                }
101            }
102        }
103
104        return false;
105    }
106
107    public function isUrlMenuItemActive(MenuItem $item): bool
108    {
109        return $item->url === $this->request?->getRequestUri();
110    }
111
112    /**
113     * @return MenuItem[]
114     */
115    public function getMenuItems(string $nom): array
116    {
117        return $this->menu[$nom]['items'] ?? [];
118    }
119
120    /**
121     * @return MenuItem[]|null
122     */
123    public function getMenuSubItems(MenuItem $item): ?array
124    {
125        return $item->subItems ?? [];
126    }
127
128    /**
129     * @return array<mixed>
130     */
131    public function getMenuOptions(string $nom): array
132    {
133        return $this->menu[$nom]['options'] ?? [];
134    }
135}