-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathPresetContext.php
More file actions
117 lines (104 loc) · 3.85 KB
/
Copy pathPresetContext.php
File metadata and controls
117 lines (104 loc) · 3.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
<?php
declare(strict_types=1);
namespace Crustum\StructArmed\Cake\Preset;
use Crustum\StructArmed\Cake\CakeLayer;
use function array_unique;
use function array_values;
use function count;
use function sprintf;
use function str_replace;
/**
* Immutable configuration bag shared by the rule groups.
*
* Owns the layer-name resolution (`layerMap`), the per-root-namespace regex
* building (app + plugin roots) and the suffix-rule exclusion resolution.
*/
final readonly class PresetContext
{
/**
* Constructor.
*
* @param string $namespace Root namespace of the application (no trailing `\`)
* @param list<string> $pluginNamespaces Plugin root namespaces (no trailing `\`)
* @param array<string, string> $layerMap Canonical Cake layer name => host layer name
* @param array<string, list<string>> $superglobalAllowlist Resolved layer name => exempt FQCNs
* @param array<string, list<string>> $pluginAppAccess Plugin root => allowed app namespaces
* @param string $pluginLayerPrefix Owner-layer name prefix, e.g. `Plugin` → `PluginBilling`
*/
public function __construct(
public string $namespace,
public array $pluginNamespaces = [],
public array $layerMap = [],
public array $superglobalAllowlist = [],
public array $pluginAppAccess = [],
public string $pluginLayerPrefix = 'Plugin',
public int $controllerMaxComplexity = 5,
public int $controllerMaxMethodLength = 20,
public int $controllerMaxDependencies = 5,
public int $viewMaxComplexity = 3,
) {
}
/**
* Resolve the host layer name for a canonical Cake layer.
*/
public function resolved(CakeLayer $layer): string
{
return $this->layerMap[$layer->value] ?? $layer->value;
}
/**
* Owner layer name for a plugin root namespace, e.g. `PluginBilling`.
*/
public function ownerLayer(string $plugin): string
{
return $this->pluginLayerPrefix . $plugin;
}
/**
* Build a namespace regex for a single root namespace.
*
* `$suffix` is the layer path in regex form and fully controls the match,
* e.g. `Model\\\\Table.*` for tables or `Controller[^\\\\]+` for direct
* controller children only.
*/
public function patternFor(string $root, string $suffix): string
{
$escaped = str_replace('\\', '\\\\', $root);
return sprintf('/^%s\\\\%s$/', $escaped, $suffix);
}
/**
* Regex pattern for a layer suffix across the app and all plugin roots.
*
* @return list<string>|string A single regex when there is one root, else a list
*/
public function patterns(string $suffix): string|array
{
$roots = [$this->namespace, ...$this->pluginNamespaces];
$patterns = [];
foreach ($roots as $root) {
$patterns[] = $this->patternFor($root, $suffix);
}
return count($patterns) === 1 ? $patterns[0] : $patterns;
}
/**
* Build the excluded-layer list for a suffix rule.
*
* Nested Cake layers that live under the rule's layer namespace (e.g.
* Component under Controller) must not be forced into the parent's suffix.
* Resolved layers that equal the rule's own layer are dropped so a mapped
* setup (e.g. Component mapped onto Controller) cannot neuter the rule.
*
* @param list<\Crustum\StructArmed\Cake\CakeLayer> $nested Canonical nested layers to exclude
* @return list<string>
*/
public function excludedLayers(CakeLayer $layer, array $nested): array
{
$own = $this->resolved($layer);
$excluded = [];
foreach ($nested as $nestedLayer) {
$resolved = $this->resolved($nestedLayer);
if ($resolved !== $own) {
$excluded[] = $resolved;
}
}
return array_values(array_unique($excluded));
}
}