Skip to content

Commit aaa1fbf

Browse files
committed
feat(Config): ajout de la commande config:list pour l'affichage des fichiers de configuration et de leur statut
fix(ConfigPublish): mise à jour du groupe de la commande et ajout d'options pour ignorer les fichiers manquants
1 parent b083344 commit aaa1fbf

3 files changed

Lines changed: 355 additions & 28 deletions

File tree

src/Cli/Commands/Config/ConfigCheck.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
*/
2222
class ConfigCheck extends Command
2323
{
24-
protected string $group = 'BlitzPHP';
24+
protected string $group = 'Configuration';
2525
protected string $service = 'Service de configuration';
2626
protected string $name = 'config:check';
2727
protected string $description = 'Vérifie les valeurs d\'un fichier de configuration.';
Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
<?php
2+
3+
/**
4+
* This file is part of Blitz PHP framework.
5+
*
6+
* (c) 2022 Dimitri Sitchet Tomkeu <devcode.dst@gmail.com>
7+
*
8+
* For the full copyright and license information, please view
9+
* the LICENSE file that was distributed with this source code.
10+
*/
11+
12+
namespace BlitzPHP\Cli\Commands\Config;
13+
14+
use Ahc\Cli\Output\Color;
15+
use BlitzPHP\Cli\Console\Command;
16+
17+
class ConfigList extends Command
18+
{
19+
protected string $group = 'Configuration';
20+
protected string $service = 'Service de configuration';
21+
protected string $name = 'config:list';
22+
protected string $description = 'Liste les fichiers de configuration disponibles et leur statut de publication.';
23+
protected array $options = [
24+
'--only-available' => ['Affiche uniquement les configurations disponibles (non publiées).'],
25+
'--only-published' => ['Affiche uniquement les configurations publiées.'],
26+
'--namespace' => ['Filtre par namespace racine (ex: --namespace=BlitzPHP\\\\Database).'],
27+
];
28+
29+
/**
30+
* {@inheritDoc}
31+
*/
32+
public function handle()
33+
{
34+
$configs = $this->getAvailableConfigurations();
35+
36+
if ($configs === []) {
37+
$this->badge()->info('Aucune configuration disponible à afficher.');
38+
return EXIT_SUCCESS;
39+
}
40+
41+
// Filtrag
42+
$onlyAvailable = (bool) $this->option('only-available');
43+
$onlyPublished = (bool) $this->option('only-published');
44+
$namespaceFilter = $this->option('namespace');
45+
46+
// Application des filtres
47+
$filteredConfigs = $configs;
48+
49+
if ($onlyAvailable) {
50+
$filteredConfigs = array_filter($filteredConfigs, fn($c) => !$c['published']);
51+
}
52+
if ($onlyPublished) {
53+
$filteredConfigs = array_filter($filteredConfigs, fn($c) => $c['published']);
54+
}
55+
if ($namespaceFilter) {
56+
$filteredConfigs = array_filter($filteredConfigs, function($c) use ($namespaceFilter) {
57+
return stripos($c['namespace'], $namespaceFilter) !== false;
58+
});
59+
}
60+
61+
if ($filteredConfigs === []) {
62+
$this->badge()->info('Aucune configuration ne correspond aux critères.');
63+
return EXIT_SUCCESS;
64+
}
65+
66+
$this->displayAsTable($filteredConfigs);
67+
$this->resume($configs, count($filteredConfigs));
68+
69+
return EXIT_SUCCESS;
70+
}
71+
72+
/**
73+
* Affiche les configurations sous forme de tableau
74+
*/
75+
protected function displayAsTable(array $configs): void
76+
{
77+
// Construction des données du tableau
78+
$rows = [];
79+
80+
foreach ($configs as $config) {
81+
$status = $config['published']
82+
? $this->color->ok('Publié')
83+
: $this->color->error('Non publié');
84+
85+
$namespace = $config['namespace'];
86+
$sourcePath = $this->shortenPath($config['path'], 40);
87+
88+
$rows[] = [$config['name'], $status, $namespace, $sourcePath];
89+
90+
// Ajouter une ligne supplémentaire pour le chemin de publication si publié
91+
if ($config['published'] && isset($config['published_path'])) {
92+
$pubPath = $this->shortenPath($config['published_path'], 60);
93+
$rows[] = ['', '', $this->color->comment('└─ Publié vers :'), $pubPath];
94+
}
95+
96+
// Ajouter une ligne pour l'override si présent
97+
if (isset($config['namespace_override'])) {
98+
$override = $config['namespace_override'];
99+
$rows[] = ['', '', $this->color->comment('└─ Surchargé par :'), $override];
100+
}
101+
}
102+
103+
$this->table(
104+
['Configuration', 'Statut', 'Namespace', 'Source'],
105+
$rows,
106+
['head' => 'boldCyan']
107+
);
108+
}
109+
110+
/**
111+
* Affichage du resumé de la configuration
112+
*/
113+
protected function resume(array $configs, int $displayed): void
114+
{
115+
$total = count($configs);
116+
$published = count(array_filter($configs, fn($c) => $c['published']));
117+
$available = $total - $published;
118+
119+
$this->border();
120+
$this->justify('Total', (string) $total);
121+
$this->justify('Affichées', (string) $displayed, [
122+
'second' => ['fg' => Color::CYAN, 'bold' => true],
123+
]);
124+
$this->justify('Publiées', (string) $published, [
125+
'second' => ['fg' => Color::GREEN, 'bold' => true],
126+
]);
127+
$this->justify('Non publiées', (string) $available, [
128+
'second' => ['fg' => Color::RED, 'bold' => true],
129+
]);
130+
}
131+
132+
/**
133+
* Récupère toutes les configurations disponibles avec leur statut
134+
*/
135+
protected function getAvailableConfigurations(): array
136+
{
137+
$configs = [];
138+
139+
// 1. Configurations du framework (stubs)
140+
foreach ($this->getFrameworkConfigurations() as $name => $path) {
141+
$configs[$name] = [
142+
'name' => $name,
143+
'source' => 'Framework',
144+
'namespace' => 'BlitzPHP',
145+
'path' => $path,
146+
'published' => $this->isPublished($name),
147+
'published_path' => $this->getPublishedPath($name),
148+
];
149+
}
150+
151+
// 2. Configurations des packages (registrars)
152+
$registrars = $this->getPackageConfigurations();
153+
foreach ($registrars as $namespace => $items) {
154+
foreach ($items as $name => $data) {
155+
// Éviter les doublons (si un package surcharge une config framework)
156+
if (isset($configs[$name]) && $configs[$name]['source'] === 'Framework') {
157+
$configs[$name]['source'] = 'Framework (surchargé)';
158+
$configs[$name]['namespace_override'] = $namespace;
159+
$configs[$name]['package_path'] = $data['path'];
160+
} else {
161+
$configs[$name] = [
162+
'name' => $name,
163+
'source' => 'Package',
164+
'namespace' => $namespace,
165+
'path' => $data['path'],
166+
'published' => $this->isPublished($name),
167+
'published_path' => $this->getPublishedPath($name),
168+
];
169+
}
170+
}
171+
}
172+
173+
// Trier par nom
174+
ksort($configs);
175+
176+
return $configs;
177+
}
178+
179+
/**
180+
* Récupère les configurations du framework (stubs)
181+
*/
182+
protected function getFrameworkConfigurations(): array
183+
{
184+
$configs = [];
185+
$stubsPath = SYST_PATH . 'Config/stubs';
186+
187+
if (is_dir($stubsPath)) {
188+
foreach (glob($stubsPath . '/*.php') as $file) {
189+
$name = basename($file, '.php');
190+
$configs[$name] = $file;
191+
}
192+
}
193+
194+
return $configs;
195+
}
196+
197+
/**
198+
* Récupère les configurations des packages via les registrars
199+
*/
200+
protected function getPackageConfigurations(): array
201+
{
202+
$configs = [];
203+
204+
// Récupérer les registrars depuis le système
205+
$registrarPaths = config()->registrar('config');
206+
207+
foreach ($registrarPaths as $file => $configNames) {
208+
$namespace = $this->extractRootNamespace($file);
209+
$rootpath = dirname($file);
210+
211+
if ($namespace === null) {
212+
continue;
213+
}
214+
215+
foreach ($configNames as $configName) {
216+
if (! isset($configs[$namespace])) {
217+
$configs[$namespace] = [];
218+
}
219+
220+
$configs[$namespace][$configName] = [
221+
'path' => $rootpath . DIRECTORY_SEPARATOR . $configName . '.php',
222+
'file' => $file,
223+
];
224+
}
225+
}
226+
227+
return $configs;
228+
}
229+
230+
/**
231+
* Extrait le namespace racine à partir du chemin du fichier Registrar
232+
*/
233+
protected function extractRootNamespace(string $file): ?string
234+
{
235+
$locator = service('locator');
236+
$className = $locator->findQualifiedNameFromPath($file);
237+
238+
if ($className === false) {
239+
return null;
240+
}
241+
242+
// Extraire le namespace racine (jusqu'au premier segment après le vendor ou app)
243+
$parts = explode('\\', $className);
244+
245+
// Si c'est un package du framework BlitzPHP
246+
if ($parts[0] === 'BlitzPHP') {
247+
return $parts[0] . '\\' . ($parts[1] ?? '');
248+
}
249+
250+
// Si c'est un package dans l'application (App namespace)
251+
if ($parts[0] === APP_NAMESPACE) {
252+
return implode('\\', array_slice($parts, 0, -2));
253+
}
254+
255+
// Pour les packages tiers, prendre les deux premiers segments
256+
return $parts[0] . '\\' . ($parts[1] ?? '');
257+
}
258+
259+
/**
260+
* Vérifie si une configuration a été publiée
261+
*/
262+
protected function isPublished(string $name): bool
263+
{
264+
return file_exists($this->getPublishedPath($name));
265+
}
266+
267+
/**
268+
* Récupère le chemin où la configuration devrait être publiée
269+
*/
270+
protected function getPublishedPath(string $name): string
271+
{
272+
return config_path($name . '.php');
273+
}
274+
275+
/**
276+
* Raccourcit un chemin si trop long
277+
*/
278+
protected function shortenPath(string $path, int $maxLength): string
279+
{
280+
$path = str_replace('/', DIRECTORY_SEPARATOR, $path);
281+
282+
if (strlen($path) <= $maxLength) {
283+
return $path;
284+
}
285+
286+
$parts = explode(DIRECTORY_SEPARATOR, $path);
287+
$shortened = [];
288+
289+
// Garder les 2 premiers dossiers et les 2 derniers
290+
$keepStart = 2;
291+
$keepEnd = 2;
292+
293+
if (count($parts) > ($keepStart + $keepEnd)) {
294+
$shortened = array_merge(
295+
array_slice($parts, 0, $keepStart),
296+
['...'],
297+
array_slice($parts, -$keepEnd)
298+
);
299+
return implode(DIRECTORY_SEPARATOR, $shortened);
300+
}
301+
302+
return $path;
303+
}
304+
}

0 commit comments

Comments
 (0)