Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
88.89% covered (warning)
88.89%
24 / 27
50.00% covered (danger)
50.00%
2 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
PolicyRegistry
88.89% covered (warning)
88.89%
24 / 27
50.00% covered (danger)
50.00%
2 / 4
13.23
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
4
 get
86.67% covered (warning)
86.67%
13 / 15
0.00% covered (danger)
0.00%
0 / 1
6.09
 getAllPolicyKeys
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 normalizePolicyKey
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/**
5 * SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
6 * SPDX-License-Identifier: AGPL-3.0-or-later
7 */
8
9namespace OCA\Libresign\Service\Policy\Runtime;
10
11use OCA\Libresign\Service\Policy\Contract\IPolicyDefinition;
12use OCA\Libresign\Service\Policy\Contract\IPolicyDefinitionProvider;
13use OCA\Libresign\Service\Policy\Provider\PolicyProviders;
14use Psr\Container\ContainerInterface;
15
16final class PolicyRegistry {
17    /** @var array<string, class-string<IPolicyDefinitionProvider>> */
18    private array $keyToProviderClass = [];
19    /** @var array<string, IPolicyDefinitionProvider> */
20    private array $providerInstances = [];
21    /** @var array<string, IPolicyDefinition> */
22    private array $definitions = [];
23
24    /**
25     * @param list<class-string<IPolicyDefinitionProvider>> $providerClasses
26     */
27    public function __construct(
28        private ContainerInterface $container,
29        array $providerClasses = [],
30    ) {
31        if ($providerClasses === []) {
32            $this->keyToProviderClass = PolicyProviders::BY_KEY;
33            return;
34        }
35
36        $allowedProviders = array_fill_keys($providerClasses, true);
37        foreach (PolicyProviders::BY_KEY as $key => $providerClass) {
38            if (!isset($allowedProviders[$providerClass])) {
39                continue;
40            }
41
42            $this->keyToProviderClass[$key] = $providerClass;
43        }
44    }
45
46    public function get(string|\BackedEnum $policyKey): IPolicyDefinition {
47        $policyKeyValue = $this->normalizePolicyKey($policyKey);
48        $definition = $this->definitions[$policyKeyValue] ?? null;
49        if ($definition instanceof IPolicyDefinition) {
50            return $definition;
51        }
52
53        $providerClass = $this->keyToProviderClass[$policyKeyValue] ?? null;
54        if (!is_string($providerClass) || $providerClass === '') {
55            throw new \InvalidArgumentException('Unknown policy key: ' . $policyKeyValue);
56        }
57
58        $provider = $this->providerInstances[$providerClass] ?? $this->container->get($providerClass);
59        if (!$provider instanceof IPolicyDefinitionProvider) {
60            throw new \UnexpectedValueException('Invalid policy provider: ' . $providerClass);
61        }
62
63        $this->providerInstances[$providerClass] = $provider;
64
65        $definition = $provider->get($policyKeyValue);
66        if ($definition->key() !== $policyKeyValue) {
67            throw new \InvalidArgumentException('Policy provider returned mismatched key: ' . $definition->key());
68        }
69
70        return $this->definitions[$policyKeyValue] = $definition;
71    }
72
73    /** @return list<string> */
74    public function getAllPolicyKeys(): array {
75        return array_keys($this->keyToProviderClass);
76    }
77
78    private function normalizePolicyKey(string|\BackedEnum $policyKey): string {
79        if ($policyKey instanceof \BackedEnum) {
80            return (string)$policyKey->value;
81        }
82
83        return $policyKey;
84    }
85}