Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
95.74% covered (success)
95.74%
45 / 47
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
TranslationAndMenuConfigurator
95.65% covered (success)
95.65%
44 / 46
50.00% covered (danger)
50.00%
1 / 2
3
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
38 / 38
100.00% covered (success)
100.00%
1 / 1
1
 createContainer
75.00% covered (warning)
75.00%
6 / 8
0.00% covered (danger)
0.00%
0 / 1
2.06
1<?php
2
3declare(strict_types=1);
4
5/** @license For full copyright and license information, please see the LICENSE.md file. */
6
7namespace App\Core\Bootstrap\Configurator;
8
9defined('AMMONLY_APP') || exit('Direct script access is forbidden.');
10
11use App\Core\Cron\Presentation\Api\CronApiController;
12use App\Core\Engine\Domain\Repository\MetadataRepositoryInterface;
13use App\Core\Instance\Application\Service\InstanceContextManagerInterface;
14use App\Core\Layout\PositionManager;
15use App\Core\Layout\Presentation\Api\LayoutApiController;
16use App\Core\Layout\TwigPositionExtension;
17use App\Core\Settings\Presentation\Api\SettingsApiController;
18use App\Core\Translation\DatabaseMessageSource;
19use App\Core\Translation\LocaleContext;
20use App\Core\Translation\Presentation\Api\TranslationApiController;
21use App\Core\Translation\TwigTranslationExtension;
22use App\Modules\Menu\Infrastructure\Repository\SqlMenuRepository;
23use App\Modules\Menu\Presentation\Api\MenuApiController;
24use App\Modules\Menu\Presentation\Block\SidebarMenuBlock;
25use Nyholm\Psr7\Factory\Psr17Factory;
26use PDO;
27use Psr\Container\ContainerInterface;
28use Twig\Environment as TwigEnvironment;
29use Yiisoft\Translator\CategorySource;
30use Yiisoft\Translator\IntlMessageFormatter;
31use Yiisoft\Translator\Translator;
32use Yiisoft\Translator\TranslatorInterface;
33
34/**
35 * TranslationAndMenuConfigurator.
36 *
37 * Configures translations, i18n message sources, system settings, layout positions, and sidebar menus.
38 *
39 * @package App\Core\Bootstrap\Configurator
40 */
41final readonly class TranslationAndMenuConfigurator
42{
43    public TranslationApiController $translationApiController;
44    public SettingsApiController $settingsApiController;
45    public LayoutApiController $layoutApiController;
46    public CronApiController $cronApiController;
47    public LocaleContext $localeContext;
48    public TranslatorInterface $translator;
49    public MenuApiController $menuApiController;
50
51    /**
52     * @param array{
53     *     metadataRepo?: ?MetadataRepositoryInterface,
54     *     instanceContextManager?: ?InstanceContextManagerInterface,
55     *     appProfile?: string
56     * } $menuOptions Optional menu configuration parameters.
57     */
58    public function __construct(
59        string $basePath,
60        PDO $pdo,
61        string $prefix,
62        TwigEnvironment $twig,
63        Psr17Factory $psr17Factory,
64        array $menuOptions = []
65    ) {
66        $metadataRepo = $menuOptions['metadataRepo'] ?? null;
67        $instanceContextManager = $menuOptions['instanceContextManager'] ?? null;
68        $appProfile = (string) ($menuOptions['appProfile'] ?? 'admin');
69        $this->translationApiController = new TranslationApiController($psr17Factory, $pdo, $prefix);
70        $this->settingsApiController = new SettingsApiController($psr17Factory, $pdo, $prefix);
71        $this->layoutApiController = new LayoutApiController($psr17Factory, $pdo, $prefix);
72        $this->cronApiController = new CronApiController($psr17Factory, $pdo, $prefix);
73
74        $this->localeContext = new LocaleContext($this->translationApiController);
75        $cachePath = $basePath . '/storage/cache/translations';
76        $dbMessageSource = new DatabaseMessageSource($this->translationApiController, $cachePath);
77
78        $categories = array_map(
79            static fn(string $cat): CategorySource => new CategorySource(
80                $cat,
81                $dbMessageSource,
82                new IntlMessageFormatter()
83            ),
84            $this->translationApiController->getDistinctCategories()
85        );
86        $this->translator = new Translator('en', 'en', 'app', null, new IntlMessageFormatter());
87        $this->translator->addCategorySources(...$categories);
88
89        $twig->addExtension(new TwigTranslationExtension($this->translator, $this->localeContext));
90
91        $menuRepository = new SqlMenuRepository($pdo, $prefix, $appProfile);
92        $this->menuApiController = new MenuApiController(
93            $psr17Factory,
94            $menuRepository,
95            $pdo,
96            $twig,
97            $prefix,
98            $metadataRepo,
99            $instanceContextManager,
100            $appProfile
101        );
102        $sidebarMenuBlock = new SidebarMenuBlock($this->menuApiController, $twig);
103
104        $container = $this->createContainer([
105            SidebarMenuBlock::class => $sidebarMenuBlock,
106        ]);
107
108        $positionManager = new PositionManager($this->layoutApiController, $container, $prefix);
109        $twig->addExtension(new TwigPositionExtension($positionManager));
110    }
111
112    /**
113     * @param array<string, object> $services
114     */
115    private function createContainer(array $services): ContainerInterface
116    {
117        return new class($services) implements ContainerInterface {
118            public function __construct(private array $services)
119            {
120            }
121
122            public function get(string $id): mixed
123            {
124                if (!$this->has($id)) {
125                    throw new class("Service not found: {$id}") extends \Exception
126                        implements \Psr\Container\NotFoundExceptionInterface {};
127                }
128                return $this->services[$id];
129            }
130
131            public function has(string $id): bool
132            {
133                return isset($this->services[$id]);
134            }
135        };
136    }
137}