Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
93.94% covered (success)
93.94%
31 / 33
80.00% covered (warning)
80.00%
4 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
Menus
93.94% covered (success)
93.94%
31 / 33
80.00% covered (warning)
80.00%
4 / 5
12.03
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 list
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
 menu
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 item
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
1
 localized
66.67% covered (warning)
66.67%
4 / 6
0.00% covered (danger)
0.00%
0 / 1
5.93
1<?php
2
3declare(strict_types=1);
4
5namespace Cosray\Api\Controller;
6
7use Celema\Core\Exception\HttpNotFound;
8use Celema\Core\Request;
9use Cosray\Api\Responses;
10use Cosray\Cms;
11use Cosray\Context;
12use Cosray\Exception\RuntimeException;
13use Cosray\Finder\MenuItem;
14use Psr\Http\Message\ResponseInterface as Response;
15
16/** Menus as the website renders them: hidden items left out, `children` items expanded. */
17final class Menus
18{
19    public function __construct(
20        private readonly Responses $responses,
21    ) {}
22
23    public function list(Context $context): Response
24    {
25        $items = [];
26
27        foreach ($context->db->menus->list()->all() as $row) {
28            $description = json_decode((string) ($row['description'] ?? 'null'), true);
29            $items[] = [
30                'handle' => $row['menu'],
31                'description' => is_array($description) ? $this->localized($context, $description) : $description,
32            ];
33        }
34
35        return $this->responses->json(['items' => $items]);
36    }
37
38    public function menu(Request $request, Cms $cms, string $menu): Response
39    {
40        try {
41            $items = iterator_to_array($cms->menu($menu), false);
42        } catch (RuntimeException $e) {
43            throw new HttpNotFound($request, payload: ['message' => "There is no menu '{$menu}'."], previous: $e);
44        }
45
46        return $this->responses->json([
47            'handle' => $menu,
48            'items' => array_map($this->item(...), $items),
49        ]);
50    }
51
52    /** @return array<string, mixed> */
53    private function item(MenuItem $item): array
54    {
55        return [
56            'id' => $item->id(),
57            'type' => $item->type(),
58            'title' => $item->title(),
59            'href' => $item->href(),
60            'node' => $item->node(),
61            'target' => $item->target(),
62            'image' => $item->image(),
63            'class' => $item->class(),
64            'children' => array_map($this->item(...), iterator_to_array($item->children(), false)),
65        ];
66    }
67
68    /** @param array<array-key, mixed> $map */
69    private function localized(Context $context, array $map): ?string
70    {
71        $locale = $context->locale();
72
73        while ($locale) {
74            if (is_string($map[$locale->id] ?? null) && $map[$locale->id] !== '') {
75                return $map[$locale->id];
76            }
77
78            $locale = $locale->fallback();
79        }
80
81        return is_string($map['zxx'] ?? null) ? $map['zxx'] : null;
82    }
83}