p59d
This commit is contained in:
@@ -65,6 +65,7 @@ final class ConfigSourceAuditCommand extends Command
|
||||
['constructor_defaults' => (string) ($summary['constructor_defaults'] ?? 0)],
|
||||
['constructor_defaults_without_yaml_mapping' => (string) ($summary['constructor_defaults_without_yaml_mapping'] ?? 0)],
|
||||
['genre_value_paths_with_source_paths' => (string) ($summary['genre_value_paths_with_source_paths'] ?? 0)],
|
||||
['genre_review_path_groups_with_source_paths' => (string) ($summary['genre_review_path_groups_with_source_paths'] ?? 0)],
|
||||
['genre_declared_source_paths' => (string) ($summary['genre_declared_source_paths'] ?? 0)],
|
||||
['genre_source_of_truth_violations' => (string) ($summary['genre_source_of_truth_violations'] ?? 0)],
|
||||
['genre_source_of_truth_fallback_empty' => (string) ($summary['genre_source_of_truth_fallback_empty'] ?? 0)],
|
||||
@@ -128,8 +129,8 @@ final class ConfigSourceAuditCommand extends Command
|
||||
}
|
||||
|
||||
if ($genreSourceRows !== []) {
|
||||
$io->section('Single-genre configuration source paths');
|
||||
$io->table(['Genre value path', 'Legacy/effective source path'], $genreSourceRows);
|
||||
$io->section('Single-genre declared source paths');
|
||||
$io->table(['Genre metadata path', 'Legacy/effective source path'], $genreSourceRows);
|
||||
}
|
||||
|
||||
|
||||
@@ -150,7 +151,7 @@ final class ConfigSourceAuditCommand extends Command
|
||||
|
||||
if ($sourceOfTruthRows !== []) {
|
||||
$io->section('Genre source-of-truth guard');
|
||||
$io->table(['Genre value path', 'Legacy/effective source path', 'State', 'Hash'], $sourceOfTruthRows);
|
||||
$io->table(['Genre metadata path', 'Legacy/effective source path', 'State', 'Hash'], $sourceOfTruthRows);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,9 @@ final readonly class ConfigSourceAuditProvider
|
||||
public function audit(): array
|
||||
{
|
||||
$yamlPaths = $this->collectYamlParameterPaths();
|
||||
$genreSourcePaths = $this->collectGenreConfigurationSourcePaths();
|
||||
$genreConfigurationValueSourcePaths = $this->collectGenreConfigurationValueSourcePaths();
|
||||
$genreReviewSourcePaths = $this->collectGenreReviewSourcePaths();
|
||||
$genreSourcePaths = array_replace($genreConfigurationValueSourcePaths, $genreReviewSourcePaths);
|
||||
$genreSourceOfTruth = $this->genreSourceOfTruthGuard->auditFromFiles();
|
||||
$fallbackAccessors = [];
|
||||
$constructorDefaults = [];
|
||||
@@ -142,7 +144,8 @@ final readonly class ConfigSourceAuditProvider
|
||||
'fallback_accessors_missing_yaml' => count($missingYamlFallbacks),
|
||||
'constructor_defaults' => count($constructorDefaults),
|
||||
'constructor_defaults_without_yaml_mapping' => count($constructorPhpDefaults),
|
||||
'genre_value_paths_with_source_paths' => count($genreSourcePaths),
|
||||
'genre_value_paths_with_source_paths' => count($genreConfigurationValueSourcePaths),
|
||||
'genre_review_path_groups_with_source_paths' => count($genreReviewSourcePaths),
|
||||
'genre_declared_source_paths' => $this->countGenreDeclaredSourcePaths($genreSourcePaths),
|
||||
'genre_source_of_truth_violations' => (int) (($genreSourceOfTruth['summary']['violations'] ?? 0)),
|
||||
'genre_source_of_truth_fallback_empty' => (int) (($genreSourceOfTruth['summary']['legacy_fallback_empty'] ?? 0)),
|
||||
@@ -157,6 +160,8 @@ final readonly class ConfigSourceAuditProvider
|
||||
'constructor_defaults' => $constructorDefaults,
|
||||
'php_constants' => $phpConstants,
|
||||
'genre_configuration_source_paths' => $genreSourcePaths,
|
||||
'genre_configuration_value_source_paths' => $genreConfigurationValueSourcePaths,
|
||||
'genre_review_source_paths' => $genreReviewSourcePaths,
|
||||
'genre_source_of_truth' => $genreSourceOfTruth,
|
||||
];
|
||||
}
|
||||
@@ -193,7 +198,90 @@ final readonly class ConfigSourceAuditProvider
|
||||
/**
|
||||
* @return array<string, string[]>
|
||||
*/
|
||||
private function collectGenreConfigurationSourcePaths(): array
|
||||
private function collectGenreConfigurationValueSourcePaths(): array
|
||||
{
|
||||
$genreConfig = $this->loadGenreConfig();
|
||||
$configurationValues = $genreConfig['configuration_values'] ?? [];
|
||||
if (!is_array($configurationValues)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$out = [];
|
||||
$this->collectGenreSourcePathsRecursive($configurationValues, '', $out);
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string[]>
|
||||
*/
|
||||
private function collectGenreReviewSourcePaths(): array
|
||||
{
|
||||
$genreConfig = $this->loadGenreConfig();
|
||||
$adaptationSurface = $genreConfig['adaptation_surface'] ?? [];
|
||||
if (!is_array($adaptationSurface)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$out = [];
|
||||
foreach ($adaptationSurface as $group => $definition) {
|
||||
if (!is_string($group) || trim($group) === '' || !is_array($definition)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$reviewPathGroups = $definition['review_path_groups'] ?? null;
|
||||
if (!is_array($reviewPathGroups)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($reviewPathGroups as $reviewGroup => $reviewDefinition) {
|
||||
if (!is_string($reviewGroup) || trim($reviewGroup) === '' || !is_array($reviewDefinition)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$paths = $reviewDefinition['paths'] ?? null;
|
||||
if (!is_array($paths)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$clean = $this->cleanStringList($paths);
|
||||
if ($clean !== []) {
|
||||
$out[sprintf('adaptation_surface.%s.review_path_groups.%s', $group, $reviewGroup)] = $clean;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $value
|
||||
* @param array<string, string[]> $out
|
||||
*/
|
||||
private function collectGenreSourcePathsRecursive(array $value, string $path, array &$out): void
|
||||
{
|
||||
$sourcePaths = $value['source_paths'] ?? null;
|
||||
if (is_array($sourcePaths)) {
|
||||
$clean = $this->cleanStringList($sourcePaths);
|
||||
if ($clean !== [] && $path !== '') {
|
||||
$out[$path] = $clean;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($value as $key => $child) {
|
||||
if ($key === 'source_paths' || !is_string($key) || !is_array($child)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$childPath = $path === '' ? $key : $path . '.' . $key;
|
||||
$this->collectGenreSourcePathsRecursive($child, $childPath, $out);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function loadGenreConfig(): array
|
||||
{
|
||||
$file = $this->projectDir . '/config/retriex/genre.yaml';
|
||||
if (!is_file($file)) {
|
||||
@@ -211,54 +299,28 @@ final readonly class ConfigSourceAuditProvider
|
||||
}
|
||||
|
||||
$genreConfig = $parameters['retriex.genre.config'] ?? [];
|
||||
if (!is_array($genreConfig)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$configurationValues = $genreConfig['configuration_values'] ?? [];
|
||||
if (!is_array($configurationValues)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$out = [];
|
||||
$this->collectGenreSourcePathsRecursive($configurationValues, '', $out);
|
||||
|
||||
return $out;
|
||||
return is_array($genreConfig) ? $genreConfig : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int|string, mixed> $value
|
||||
* @param array<string, string[]> $out
|
||||
* @return string[]
|
||||
*/
|
||||
private function collectGenreSourcePathsRecursive(array $value, string $path, array &$out): void
|
||||
private function cleanStringList(array $values): array
|
||||
{
|
||||
$sourcePaths = $value['source_paths'] ?? null;
|
||||
if (is_array($sourcePaths)) {
|
||||
$clean = [];
|
||||
foreach ($sourcePaths as $sourcePath) {
|
||||
if (!is_string($sourcePath) || trim($sourcePath) === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$sourcePath = trim($sourcePath);
|
||||
if (!in_array($sourcePath, $clean, true)) {
|
||||
$clean[] = $sourcePath;
|
||||
}
|
||||
}
|
||||
|
||||
if ($clean !== [] && $path !== '') {
|
||||
$out[$path] = $clean;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($value as $key => $child) {
|
||||
if ($key === 'source_paths' || !is_string($key) || !is_array($child)) {
|
||||
$clean = [];
|
||||
foreach ($values as $value) {
|
||||
if (!is_string($value) || trim($value) === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$childPath = $path === '' ? $key : $path . '.' . $key;
|
||||
$this->collectGenreSourcePathsRecursive($child, $childPath, $out);
|
||||
$value = trim($value);
|
||||
if (!in_array($value, $clean, true)) {
|
||||
$clean[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $clean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -97,7 +97,9 @@ final readonly class GenreSourceOfTruthGuard
|
||||
array_push($errors, ...$coverageErrors);
|
||||
|
||||
$nativeValueNodes = $this->countGenreNativeValueNodes($configurationValues);
|
||||
$declaredSourcePaths = $this->collectSourcePaths($configurationValues);
|
||||
$configurationValueSourcePaths = $this->collectConfigurationValueSourcePaths($configurationValues);
|
||||
$reviewSourcePaths = $this->collectReviewPathGroupSourcePaths(is_array($adaptationSurface) ? $adaptationSurface : []);
|
||||
$declaredSourcePaths = array_replace($configurationValueSourcePaths, $reviewSourcePaths);
|
||||
$uniqueSourcePaths = [];
|
||||
foreach ($declaredSourcePaths as $valuePath => $sourcePaths) {
|
||||
foreach ($sourcePaths as $sourcePath) {
|
||||
@@ -159,7 +161,9 @@ final readonly class GenreSourceOfTruthGuard
|
||||
$summary = $this->summarizeRows($rows);
|
||||
$summary['configuration_value_groups'] = count($configurationValues);
|
||||
$summary['genre_native_value_nodes'] = $nativeValueNodes;
|
||||
$summary['source_path_value_nodes'] = count($declaredSourcePaths);
|
||||
$summary['source_path_value_nodes'] = count($configurationValueSourcePaths);
|
||||
$summary['review_path_group_nodes'] = count($reviewSourcePaths);
|
||||
$summary['declared_source_path_nodes'] = count($declaredSourcePaths);
|
||||
$summary['declared_source_paths'] = count($uniqueSourcePaths);
|
||||
$summary['violations'] = count($errors);
|
||||
|
||||
@@ -289,9 +293,25 @@ final readonly class GenreSourceOfTruthGuard
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $configurationValues
|
||||
* @param array<string, mixed> $adaptationSurface
|
||||
* @return array<string, string[]>
|
||||
*/
|
||||
private function collectSourcePaths(array $configurationValues): array
|
||||
private function collectDeclaredSourcePaths(array $configurationValues, array $adaptationSurface): array
|
||||
{
|
||||
$out = $this->collectConfigurationValueSourcePaths($configurationValues);
|
||||
|
||||
foreach ($this->collectReviewPathGroupSourcePaths($adaptationSurface) as $path => $sourcePaths) {
|
||||
$out[$path] = $sourcePaths;
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $configurationValues
|
||||
* @return array<string, string[]>
|
||||
*/
|
||||
private function collectConfigurationValueSourcePaths(array $configurationValues): array
|
||||
{
|
||||
$out = [];
|
||||
$this->collectSourcePathsRecursive($configurationValues, '', $out);
|
||||
@@ -307,16 +327,7 @@ final readonly class GenreSourceOfTruthGuard
|
||||
{
|
||||
$sourcePaths = $value['source_paths'] ?? null;
|
||||
if (is_array($sourcePaths) && $path !== '') {
|
||||
$clean = [];
|
||||
foreach ($sourcePaths as $sourcePath) {
|
||||
if (!is_string($sourcePath) || trim($sourcePath) === '') {
|
||||
continue;
|
||||
}
|
||||
$sourcePath = trim($sourcePath);
|
||||
if (!in_array($sourcePath, $clean, true)) {
|
||||
$clean[] = $sourcePath;
|
||||
}
|
||||
}
|
||||
$clean = $this->cleanStringList($sourcePaths);
|
||||
if ($clean !== []) {
|
||||
$out[$path] = $clean;
|
||||
}
|
||||
@@ -331,6 +342,64 @@ final readonly class GenreSourceOfTruthGuard
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $adaptationSurface
|
||||
* @return array<string, string[]>
|
||||
*/
|
||||
private function collectReviewPathGroupSourcePaths(array $adaptationSurface): array
|
||||
{
|
||||
$out = [];
|
||||
|
||||
foreach ($adaptationSurface as $group => $definition) {
|
||||
if (!is_string($group) || trim($group) === '' || !is_array($definition)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$reviewPathGroups = $definition['review_path_groups'] ?? null;
|
||||
if (!is_array($reviewPathGroups)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($reviewPathGroups as $reviewGroup => $reviewDefinition) {
|
||||
if (!is_string($reviewGroup) || trim($reviewGroup) === '' || !is_array($reviewDefinition)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$paths = $reviewDefinition['paths'] ?? null;
|
||||
if (!is_array($paths)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$clean = $this->cleanStringList($paths);
|
||||
if ($clean !== []) {
|
||||
$out[sprintf('adaptation_surface.%s.review_path_groups.%s', $group, $reviewGroup)] = $clean;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function cleanStringList(array $values): array
|
||||
{
|
||||
$clean = [];
|
||||
foreach ($values as $value) {
|
||||
if (!is_string($value) || trim($value) === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = trim($value);
|
||||
if (!in_array($value, $clean, true)) {
|
||||
$clean[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $clean;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $guardConfig
|
||||
* @return array<string, string>
|
||||
@@ -530,6 +599,8 @@ final readonly class GenreSourceOfTruthGuard
|
||||
return [
|
||||
'configuration_value_groups' => 0,
|
||||
'source_path_value_nodes' => 0,
|
||||
'review_path_group_nodes' => 0,
|
||||
'declared_source_path_nodes' => 0,
|
||||
'declared_source_paths' => 0,
|
||||
'genre_native_value_nodes' => 0,
|
||||
'legacy_fallback_empty' => 0,
|
||||
|
||||
Reference in New Issue
Block a user