Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
87.50% covered (warning)
87.50%
21 / 24
60.00% covered (warning)
60.00%
3 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
Icons
87.50% covered (warning)
87.50%
21 / 24
60.00% covered (warning)
60.00%
3 / 5
13.33
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
 icon
85.71% covered (warning)
85.71%
12 / 14
0.00% covered (danger)
0.00%
0 / 1
6.10
 providers
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 key
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 failed
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
2.15
1<?php
2
3declare(strict_types=1);
4
5namespace Cosray;
6
7use Celemas\Container\Container;
8
9final class Icons implements Contract\Icons
10{
11    /** @var array<string, string> */
12    private array $cache = [];
13
14    public function __construct(
15        private readonly Container $container,
16        private readonly Config $config,
17    ) {}
18
19    /** @param array<array-key, mixed> $args */
20    public function icon(string $id, array $args = []): string
21    {
22        $id = trim($id);
23
24        if ($id === '') {
25            return $this->failed('empty icon id');
26        }
27
28        $key = $this->key($id, $args);
29
30        if (array_key_exists($key, $this->cache)) {
31            return $this->cache[$key];
32        }
33
34        foreach ($this->providers() as $provider) {
35            if ($provider === $this) {
36                continue;
37            }
38
39            $svg = $provider->icon($id, $args);
40
41            if ($svg === '') {
42                continue;
43            }
44
45            return $this->cache[$key] = $svg;
46        }
47
48        return $this->cache[$key] = $this->failed('icon not found: ' . $id);
49    }
50
51    /** @return iterable<Contract\Icons> */
52    private function providers(): iterable
53    {
54        $tag = $this->container->tag(Contract\Icons::class);
55
56        foreach ($tag->entries() as $id) {
57            $provider = $tag->get($id);
58
59            if ($provider instanceof Contract\Icons) {
60                yield $provider;
61            }
62        }
63    }
64
65    /** @param array<array-key, mixed> $args */
66    private function key(string $id, array $args): string
67    {
68        return hash('xxh3', $id . "\x1f" . serialize($args));
69    }
70
71    private function failed(string $message): string
72    {
73        if (!$this->config->debug()) {
74            return '';
75        }
76
77        return sprintf('<!-- %s -->', escape($message));
78    }
79}