Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
232 / 232
100.00% covered (success)
100.00%
8 / 8
CRAP
100.00% covered (success)
100.00%
1 / 1
CommerceBootstrapProvider
100.00% covered (success)
100.00%
231 / 231
100.00% covered (success)
100.00%
8 / 8
8
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 registerAll
100.00% covered (success)
100.00%
67 / 67
100.00% covered (success)
100.00%
1 / 1
1
 initializeTaxControllers
100.00% covered (success)
100.00%
27 / 27
100.00% covered (success)
100.00%
1 / 1
1
 initializeDiscountControllers
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
1
 initializeInventoryControllers
100.00% covered (success)
100.00%
53 / 53
100.00% covered (success)
100.00%
1 / 1
1
 initializeDataMappingControllers
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
1 / 1
1
 initializeQuotesControllers
100.00% covered (success)
100.00%
20 / 20
100.00% covered (success)
100.00%
1 / 1
1
 initializeCurrenciesControllers
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
1 / 1
1
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\Provider;
8
9defined('AMMONLY_APP') || exit('Direct script access is forbidden.');
10
11use App\Core\Engine\Application\Security\PermissionContextFactory;
12use App\Core\Engine\Application\Service\InventoryApplicationService;
13use App\Core\Engine\Application\Service\UniversalCrudServiceInterface;
14use App\Core\Engine\Domain\Repository\MetadataRepositoryInterface;
15use App\Core\Engine\Infrastructure\Repository\SqlInventoryFieldRepository;
16use App\Core\Engine\Infrastructure\Repository\SqlInventoryRecordRepository;
17use App\Core\Engine\Application\Service\InventorySchemaEngine;
18use App\Core\Engine\Presentation\Api\InventoryFieldsApiController;
19use App\Core\Instance\Application\Service\InstanceContextManagerInterface;
20use App\Core\Bootstrap\Configurator\SecurityAndTemplateConfigurator;
21use App\Core\Engine\Application\Service\DataMappingApplicationService;
22use App\Core\Engine\Infrastructure\Repository\SqlDataMappingRepository;
23use App\Modules\DataMapping\Presentation\Htmx\DataMappingHtmxController;
24use App\Modules\DataMapping\Presentation\Web\DataMappingWebController;
25use App\Modules\Discount\Application\Service\DiscountApplicationService;
26use App\Modules\Discount\Infrastructure\Repository\SqlDiscountRepository;
27use App\Modules\Discount\Presentation\Api\DiscountRatesApiController;
28use App\Modules\Discount\Presentation\Htmx\DiscountHtmxController;
29use App\Core\Engine\Application\Service\InventoryCalculationService;
30use App\Core\Instance\Application\Service\RemoteInstanceEngineGatewayInterface;
31use App\Modules\Discount\Presentation\Web\DiscountSettingsWebController;
32use App\Modules\Inventory\Presentation\Api\InventoryItemsApiController;
33use App\Modules\Inventory\Presentation\Htmx\InventoryItemsHtmxController;
34use App\Modules\Inventory\Presentation\Htmx\InventorySettingsHtmxController;
35use App\Modules\Inventory\Presentation\Web\InventorySettingsWebController;
36use App\Modules\Currencies\Application\DataSource\CurrenciesDynamicDataProvider;
37use App\Modules\Currencies\Application\Service\CurrencySyncService;
38use App\Modules\Currencies\Domain\Repository\CurrencyRepositoryInterface;
39use App\Modules\Currencies\Infrastructure\Repository\SqlCurrencyRepository;
40use App\Modules\Currencies\Presentation\Api\CurrenciesApiController;
41use App\Modules\Currencies\Presentation\Web\CurrenciesWebController;
42use App\Modules\Integrations\Infrastructure\Currency\NbpExchangeRatesClient;
43use App\Modules\Quotes\Application\Service\QuoteConversionApplicationService;
44use App\Modules\Quotes\Presentation\Web\QuoteConversionWebController;
45use App\Modules\Tax\Application\Service\TaxApplicationService;
46use App\Modules\Tax\Domain\Service\TaxDeterminationMatrix;
47use App\Modules\Tax\Domain\Service\TaxEngine;
48use App\Modules\Tax\Infrastructure\Repository\SqlTaxGroupRepository;
49use App\Modules\Tax\Infrastructure\Repository\SqlTaxRateRepository;
50use App\Modules\Tax\Infrastructure\Repository\SqlTaxRuleRepository;
51use App\Modules\Tax\Presentation\Api\TaxCalculateApiController;
52use App\Modules\Tax\Presentation\Api\TaxGroupsApiController;
53use App\Modules\Tax\Presentation\Api\TaxRatesApiController;
54use App\Modules\Tax\Presentation\Api\TaxRulesApiController;
55use App\Modules\Tax\Presentation\Htmx\TaxHtmxController;
56use App\Modules\Tax\Presentation\Web\TaxSettingsWebController;
57use Nyholm\Psr7\Factory\Psr17Factory;
58use PDO;
59
60/**
61 * Bootstrap provider encapsulating instantiations of all Commerce subsystems:
62 * Taxes, Discounts, Currencies, Dynamic Inventory Tables, Data Mapping and Quotes conversion.
63 */
64final readonly class CommerceBootstrapProvider
65{
66    public function __construct(
67        private Psr17Factory $psr17Factory
68    ) {
69    }
70
71    /**
72     * Initializes all commerce domain services, repositories, and controllers.
73     *
74     * @param array{
75     *     instanceContextManager?: ?InstanceContextManagerInterface,
76     *     clientPdo?: ?PDO,
77     *     remoteGateway?: ?RemoteInstanceEngineGatewayInterface
78     * } $options Optional context dependencies.
79     * @return array<string, mixed>
80     */
81    public function registerAll(
82        ?PDO $pdo,
83        string $prefix,
84        SecurityAndTemplateConfigurator $sec,
85        MetadataRepositoryInterface $metadataRepo,
86        UniversalCrudServiceInterface $crudService,
87        PermissionContextFactory $contextFactory,
88        array $options = []
89    ): array {
90        $instanceContextManager = $options['instanceContextManager'] ?? null;
91        $clientPdo = $options['clientPdo'] ?? null;
92        $remoteGateway = $options['remoteGateway'] ?? null;
93
94        $tax = $this->initializeTaxControllers($pdo, $prefix, $sec, $instanceContextManager, $clientPdo);
95        $discount = $this->initializeDiscountControllers($pdo, $prefix, $sec, $instanceContextManager, $clientPdo);
96        $currencies = $this->initializeCurrenciesControllers(
97            $pdo,
98            $prefix,
99            $sec,
100            $instanceContextManager,
101            $clientPdo
102        );
103        $inventory = $this->initializeInventoryControllers(
104            $pdo,
105            $prefix,
106            $sec,
107            $metadataRepo,
108            [
109                'instanceContextManager' => $instanceContextManager,
110                'clientPdo'              => $clientPdo,
111                'currencyRepo'           => $currencies['currency_repo'] ?? null,
112                'remoteGateway'          => $remoteGateway,
113            ]
114        );
115        $mapping = $this->initializeDataMappingControllers(
116            $pdo,
117            $prefix,
118            $sec,
119            $metadataRepo,
120            $instanceContextManager,
121            $clientPdo
122        );
123        $quotes = $this->initializeQuotesControllers(
124            $crudService,
125            $metadataRepo,
126            $mapping['mapping_service'],
127            $inventory['inventory_service'],
128            $contextFactory,
129            [
130                'pdo'                    => $pdo,
131                'instanceContextManager' => $instanceContextManager,
132                'clientPdo'              => $clientPdo,
133            ]
134        );
135
136        return [
137            'apis' => array_merge(
138                $tax['apis'],
139                $discount['apis'],
140                $currencies['apis'],
141                $inventory['apis']
142            ),
143            'tax_web' => $tax['tax_web'],
144            'tax_htmx' => $tax['tax_htmx'],
145            'discount_web' => $discount['discount_web'],
146            'discount_htmx' => $discount['discount_htmx'],
147            'currencies_web' => $currencies['currencies_web'],
148            'currencies_api' => $currencies['currencies_api'],
149            'currencies_data_provider' => $currencies['currencies_data_provider'],
150            'inventory_service' => $inventory['inventory_service'],
151            'inventory_web' => $inventory['inventory_web'],
152            'inventory_htmx' => $inventory['inventory_htmx'],
153            'inventory_items_htmx' => $inventory['inventory_items_htmx'],
154            'mapping_service' => $mapping['mapping_service'],
155            'mapping_web' => $mapping['mapping_web'],
156            'mapping_htmx' => $mapping['mapping_htmx'],
157            'quote_conversion_web' => $quotes['quote_conversion_web'],
158        ];
159    }
160
161    /**
162     * @return array{
163     *     apis: array<string, object>,
164     *     tax_web: TaxSettingsWebController,
165     *     tax_htmx: TaxHtmxController
166     * }
167     */
168    public function initializeTaxControllers(
169        ?PDO $pdo,
170        string $prefix,
171        SecurityAndTemplateConfigurator $sec,
172        ?InstanceContextManagerInterface $instanceContextManager = null,
173        ?PDO $clientPdo = null
174    ): array {
175        $rateRepo = new SqlTaxRateRepository($pdo, $prefix, $instanceContextManager, $clientPdo);
176        $groupRepo = new SqlTaxGroupRepository($pdo, $rateRepo, $prefix, $instanceContextManager, $clientPdo);
177        $ruleRepo = new SqlTaxRuleRepository($pdo, $rateRepo, $prefix, $instanceContextManager, $clientPdo);
178
179        $taxEngine = new TaxEngine();
180        $matrix = new TaxDeterminationMatrix();
181        $taxService = new TaxApplicationService($rateRepo, $groupRepo, $ruleRepo, $taxEngine, $matrix);
182
183        $taxSettingsWeb = new TaxSettingsWebController(
184            $taxService,
185            $sec->twig,
186            $this->psr17Factory,
187            $instanceContextManager
188        );
189        $taxHtmx = new TaxHtmxController($taxService, $sec->twig, $this->psr17Factory);
190
191        $ratesApi = new TaxRatesApiController($taxService, $this->psr17Factory);
192        $groupsApi = new TaxGroupsApiController($taxService, $this->psr17Factory);
193        $rulesApi = new TaxRulesApiController($taxService, $this->psr17Factory);
194        $calcApi = new TaxCalculateApiController($taxService, $this->psr17Factory);
195
196        return [
197            'apis' => [
198                'tax_rates' => $ratesApi,
199                'tax_groups' => $groupsApi,
200                'tax_rules' => $rulesApi,
201                'tax_calculate' => $calcApi,
202            ],
203            'tax_web' => $taxSettingsWeb,
204            'tax_htmx' => $taxHtmx,
205        ];
206    }
207
208    /**
209     * @return array{
210     *     apis: array<string, object>,
211     *     discount_web: DiscountSettingsWebController,
212     *     discount_htmx: DiscountHtmxController
213     * }
214     */
215    public function initializeDiscountControllers(
216        ?PDO $pdo,
217        string $prefix,
218        SecurityAndTemplateConfigurator $sec,
219        ?InstanceContextManagerInterface $instanceContextManager = null,
220        ?PDO $clientPdo = null
221    ): array {
222        $discountRepo = new SqlDiscountRepository($pdo, $prefix, $instanceContextManager, $clientPdo);
223        $discountService = new DiscountApplicationService($discountRepo);
224
225        $discountWeb = new DiscountSettingsWebController(
226            $discountService,
227            $sec->twig,
228            $this->psr17Factory,
229            $instanceContextManager,
230            $sec->activeProfile->name
231        );
232        $discountHtmx = new DiscountHtmxController($discountService, $sec->twig, $this->psr17Factory);
233        $discountApi = new DiscountRatesApiController($discountService, $this->psr17Factory);
234
235        return [
236            'apis' => [
237                'discounts' => $discountApi,
238            ],
239            'discount_web' => $discountWeb,
240            'discount_htmx' => $discountHtmx,
241        ];
242    }
243
244    /**
245     * @param array{
246     *     instanceContextManager?: ?InstanceContextManagerInterface,
247     *     clientPdo?: ?PDO,
248     *     currencyRepo?: ?CurrencyRepositoryInterface,
249     *     remoteGateway?: ?RemoteInstanceEngineGatewayInterface
250     * } $options
251     * @return array{
252     *     apis: array<string, object>,
253     *     inventory_service: InventoryApplicationService,
254     *     inventory_web: InventorySettingsWebController,
255     *     inventory_htmx: InventorySettingsHtmxController,
256     *     inventory_items_htmx: InventoryItemsHtmxController
257     * }
258     */
259    public function initializeInventoryControllers(
260        ?PDO $pdo,
261        string $prefix,
262        SecurityAndTemplateConfigurator $sec,
263        MetadataRepositoryInterface $metadataRepo,
264        array $options = []
265    ): array {
266        $instanceContextManager = $options['instanceContextManager'] ?? null;
267        $clientPdo = $options['clientPdo'] ?? null;
268        $currencyRepo = $options['currencyRepo'] ?? null;
269        $remoteGateway = $options['remoteGateway'] ?? null;
270        $fieldRepo = new SqlInventoryFieldRepository($pdo, $prefix, $instanceContextManager, $clientPdo);
271        $recordRepo = new SqlInventoryRecordRepository($pdo, $instanceContextManager, $clientPdo);
272        $schemaEngine = new InventorySchemaEngine($pdo, $instanceContextManager, $clientPdo);
273        $inventoryService = new InventoryApplicationService($fieldRepo, $metadataRepo, $schemaEngine, $recordRepo);
274        $calculationService = new InventoryCalculationService();
275
276        $inventoryWeb = new InventorySettingsWebController(
277            $inventoryService,
278            $metadataRepo,
279            $sec->twig,
280            $this->psr17Factory,
281            $instanceContextManager,
282            $sec->activeProfile->name
283        );
284        $inventoryHtmx = new InventorySettingsHtmxController(
285            $inventoryService,
286            $metadataRepo,
287            $sec->twig,
288            $this->psr17Factory
289        );
290        $inventoryItemsHtmx = new InventoryItemsHtmxController(
291            $inventoryService,
292            $metadataRepo,
293            $sec->twig,
294            $this->psr17Factory,
295            $currencyRepo,
296            $pdo,
297            $calculationService,
298            $instanceContextManager,
299            $remoteGateway
300        );
301        $inventoryApi = new InventoryFieldsApiController($fieldRepo, $inventoryService, $this->psr17Factory);
302        $inventoryItemsApi = new InventoryItemsApiController(
303            $inventoryService,
304            $metadataRepo,
305            $calculationService,
306            $this->psr17Factory,
307            $instanceContextManager,
308            $remoteGateway
309        );
310
311        return [
312            'apis' => [
313                'inventory_fields' => $inventoryApi,
314                'inventory_items' => $inventoryItemsApi,
315            ],
316            'inventory_service' => $inventoryService,
317            'inventory_web' => $inventoryWeb,
318            'inventory_htmx' => $inventoryHtmx,
319            'inventory_items_htmx' => $inventoryItemsHtmx,
320        ];
321    }
322
323    /**
324     * @return array{
325     *     mapping_service: DataMappingApplicationService,
326     *     mapping_web: DataMappingWebController,
327     *     mapping_htmx: DataMappingHtmxController
328     * }
329     */
330    public function initializeDataMappingControllers(
331        ?PDO $pdo,
332        string $prefix,
333        SecurityAndTemplateConfigurator $sec,
334        MetadataRepositoryInterface $metadataRepo,
335        ?InstanceContextManagerInterface $instanceContextManager = null,
336        ?PDO $clientPdo = null
337    ): array {
338        $mappingRepo = new SqlDataMappingRepository($pdo, $prefix, $instanceContextManager, $clientPdo);
339        $mappingService = new DataMappingApplicationService($mappingRepo);
340
341        $dataMappingWeb = new DataMappingWebController(
342            $mappingService,
343            $metadataRepo,
344            $sec->twig,
345            $this->psr17Factory,
346            $instanceContextManager,
347            $sec->activeProfile->name
348        );
349        $dataMappingHtmx = new DataMappingHtmxController(
350            $mappingService,
351            $metadataRepo,
352            $sec->twig,
353            $this->psr17Factory
354        );
355
356        return [
357            'mapping_service' => $mappingService,
358            'mapping_web' => $dataMappingWeb,
359            'mapping_htmx' => $dataMappingHtmx,
360        ];
361    }
362
363    /**
364     * @param array{
365     *     pdo?: ?PDO,
366     *     instanceContextManager?: ?InstanceContextManagerInterface,
367     *     clientPdo?: ?PDO
368     * } $options
369     * @return array{
370     *     quote_conversion_web: QuoteConversionWebController
371     * }
372     */
373    public function initializeQuotesControllers(
374        UniversalCrudServiceInterface $crudService,
375        MetadataRepositoryInterface $metadataRepo,
376        DataMappingApplicationService $mappingService,
377        InventoryApplicationService $inventoryService,
378        PermissionContextFactory $contextFactory,
379        array $options = []
380    ): array {
381        $pdo = $options['pdo'] ?? null;
382        $instanceContextManager = $options['instanceContextManager'] ?? null;
383        $clientPdo = $options['clientPdo'] ?? null;
384
385        $conversionService = new QuoteConversionApplicationService(
386            $crudService,
387            $metadataRepo,
388            $mappingService,
389            $inventoryService,
390            $pdo,
391            $instanceContextManager,
392            $clientPdo
393        );
394
395        $quoteConversionWeb = new QuoteConversionWebController(
396            $conversionService,
397            $contextFactory,
398            $this->psr17Factory
399        );
400
401        return [
402            'quote_conversion_web' => $quoteConversionWeb,
403        ];
404    }
405
406    /**
407     * @return array{
408     *     apis: array<string, object>,
409     *     currencies_web: CurrenciesWebController,
410     *     currencies_api: CurrenciesApiController,
411     *     currencies_data_provider: CurrenciesDynamicDataProvider
412     * }
413     */
414    public function initializeCurrenciesControllers(
415        ?PDO $pdo,
416        string $prefix,
417        SecurityAndTemplateConfigurator $sec,
418        ?InstanceContextManagerInterface $instanceContextManager = null,
419        ?PDO $clientPdo = null
420    ): array {
421        $currencyRepo = new SqlCurrencyRepository($pdo, $prefix, $instanceContextManager, $clientPdo);
422        $nbpClient = new NbpExchangeRatesClient();
423        $syncService = new CurrencySyncService($nbpClient, $currencyRepo);
424
425        $currenciesWeb = new CurrenciesWebController(
426            $currencyRepo,
427            $sec->twig,
428            $this->psr17Factory,
429            $instanceContextManager
430        );
431        $currenciesApi = new CurrenciesApiController(
432            $currencyRepo,
433            $syncService,
434            $this->psr17Factory
435        );
436        $currenciesDataProvider = new CurrenciesDynamicDataProvider($currencyRepo);
437
438        return [
439            'apis' => [
440                'currencies' => $currenciesApi,
441            ],
442            'currencies_web' => $currenciesWeb,
443            'currencies_api' => $currenciesApi,
444            'currencies_data_provider' => $currenciesDataProvider,
445            'currency_repo' => $currencyRepo,
446        ];
447    }
448}