From 5214050d4df2ad3a668c51d44410979bcd9cef13 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Tue, 30 Jun 2026 21:32:16 +0800 Subject: [PATCH] refactor: migrate `filter:check` as a modern command --- system/Commands/Utilities/FilterCheck.php | 206 +++++++----------- .../Commands/Utilities/FilterCheckTest.php | 1 + 2 files changed, 78 insertions(+), 129 deletions(-) diff --git a/system/Commands/Utilities/FilterCheck.php b/system/Commands/Utilities/FilterCheck.php index e2043fe9a3a4..fdfa14def791 100644 --- a/system/Commands/Utilities/FilterCheck.php +++ b/system/Commands/Utilities/FilterCheck.php @@ -13,74 +13,41 @@ namespace CodeIgniter\Commands\Utilities; -use CodeIgniter\CLI\BaseCommand; +use CodeIgniter\CLI\AbstractCommand; +use CodeIgniter\CLI\Attributes\Command; use CodeIgniter\CLI\CLI; +use CodeIgniter\CLI\Input\Argument; use CodeIgniter\Commands\Utilities\Routes\FilterCollector; /** * Check filters for a route. */ -class FilterCheck extends BaseCommand +#[Command(name: 'filter:check', description: 'Check filters for a route.', group: 'CodeIgniter')] +class FilterCheck extends AbstractCommand { - /** - * The group the command is lumped under - * when listing commands. - * - * @var string - */ - protected $group = 'CodeIgniter'; - - /** - * The Command's name - * - * @var string - */ - protected $name = 'filter:check'; - - /** - * the Command's short description - * - * @var string - */ - protected $description = 'Check filters for a route.'; - - /** - * the Command's usage - * - * @var string - */ - protected $usage = 'filter:check '; - - /** - * the Command's Arguments - * - * @var array - */ - protected $arguments = [ - 'method' => 'The HTTP method. GET, POST, PUT, etc.', - 'route' => 'The route (URI path) to check filters.', - ]; - - /** - * the Command's Options - * - * @var array - */ - protected $options = []; + protected function configure(): void + { + $this + ->addArgument(new Argument( + name: 'method', + description: 'The HTTP method. GET, POST, PUT, etc.', + required: true, + )) + ->addArgument(new Argument( + name: 'route', + description: 'The route (URI path) to check filters.', + required: true, + )); + } - /** - * @return int exit code - */ - public function run(array $params) + protected function execute(array $arguments, array $options): int { - if (! $this->checkParams($params)) { - return EXIT_ERROR; - } + $method = $arguments['method']; + assert(is_string($method)); - $method = $params[0]; - $route = $params[1]; + $route = $arguments['route']; + assert(is_string($route)); - // Load Routes service('routes')->loadRoutes(); $filterCollector = new FilterCollector(); @@ -89,14 +56,10 @@ public function run(array $params) // PageNotFoundException if ($filters['before'] === ['']) { - CLI::error( - "Can't find a route: " . - CLI::color( - '"' . strtoupper($method) . ' ' . $route . '"', - 'black', - 'light_gray', - ), - ); + CLI::error(sprintf( + "Can't find a route: %s", + CLI::color(sprintf('"%s %s"', strtoupper($method), $route), 'black', 'light_gray'), + )); return EXIT_ERROR; } @@ -107,23 +70,6 @@ public function run(array $params) return EXIT_SUCCESS; } - /** - * @param array $params - */ - private function checkParams(array $params): bool - { - if (! isset($params[0], $params[1])) { - CLI::error('You must specify a HTTP verb and a route.'); - CLI::write(' Usage: ' . $this->usage); - CLI::write('Example: filter:check GET /'); - CLI::write(' filter:check PUT products/1'); - - return false; - } - - return true; - } - /** * @param array{before: list, after: list} $filters */ @@ -133,67 +79,69 @@ private function showTable( string $method, string $route, ): void { - $thead = [ - 'Method', - 'Route', - 'Before Filters', - 'After Filters', + $merged = $this->mergeFilters($filterCollector->getRequiredFilters(), $filters); + + $thead = ['Method', 'Route', 'Before Filters', 'After Filters']; + $tbody = [ + [ + strtoupper($method), + $route, + implode(' ', $merged['before']), + implode(' ', $merged['after']), + ], ]; - $required = $filterCollector->getRequiredFilters(); + CLI::table($tbody, $thead); + } - $coloredRequired = $this->colorItems($required); + private function showFilterClasses( + FilterCollector $filterCollector, + string $method, + string $route, + ): void { + $merged = $this->mergeFilters( + $filterCollector->getRequiredFilterClasses(), + $filterCollector->getClasses($method, $route), + ); - $before = array_merge($coloredRequired['before'], $filters['before']); - $after = array_merge($filters['after'], $coloredRequired['after']); + $lastPosition = array_key_last($merged); - $tbody = []; - $tbody[] = [ - strtoupper($method), - $route, - implode(' ', $before), - implode(' ', $after), - ]; + foreach ($merged as $position => $classes) { + CLI::write(sprintf('%s Filter Classes:', ucfirst($position)), 'cyan'); + CLI::write(implode(' → ', $classes)); - CLI::table($tbody, $thead); + if ($position !== $lastPosition) { + CLI::newLine(); + } + } } /** - * Color all elements of the array. + * Merges the required filters (highlighted) with the route's filters, + * keeping required-before filters first and required-after filters last. * - * @param array $array + * @param array{before: list, after: list} $required + * @param array{before: list, after: list} $filters * - * @return array + * @return array{before: list, after: list} */ - private function colorItems(array $array): array + private function mergeFilters(array $required, array $filters): array { - return array_map(function ($item): array|string { - if (is_array($item)) { - return $this->colorItems($item); - } - - return CLI::color($item, 'yellow'); - }, $array); - } - - private function showFilterClasses( - FilterCollector $filterCollector, - string $method, - string $route, - ): void { - $requiredFilterClasses = $filterCollector->getRequiredFilterClasses(); - $filterClasses = $filterCollector->getClasses($method, $route); - - $coloredRequiredFilterClasses = $this->colorItems($requiredFilterClasses); - - $classList = [ - 'before' => array_merge($coloredRequiredFilterClasses['before'], $filterClasses['before']), - 'after' => array_merge($filterClasses['after'], $coloredRequiredFilterClasses['after']), + return [ + 'before' => array_merge($this->highlight($required['before']), $filters['before']), + 'after' => array_merge($filters['after'], $this->highlight($required['after'])), ]; + } - foreach ($classList as $position => $classes) { - CLI::write(ucfirst($position) . ' Filter Classes:', 'cyan'); - CLI::write(implode(' → ', $classes)); - } + /** + * Applies the highlight color to the given filter names. + * + * @param list $items + * + * @return list + */ + private function highlight(array $items): array + { + return array_map(static fn (string $item): string => CLI::color($item, 'yellow'), $items); } } diff --git a/tests/system/Commands/Utilities/FilterCheckTest.php b/tests/system/Commands/Utilities/FilterCheckTest.php index b2f0d3b8144d..bb6c7759cbd5 100644 --- a/tests/system/Commands/Utilities/FilterCheckTest.php +++ b/tests/system/Commands/Utilities/FilterCheckTest.php @@ -53,6 +53,7 @@ public function testFilterCheckDefinedRoute(): void $this->assertStringContainsString( 'Before Filter Classes: CodeIgniter\Filters\ForceHTTPS → CodeIgniter\Filters\PageCache + After Filter Classes: CodeIgniter\Filters\PageCache → CodeIgniter\Filters\PerformanceMetrics → CodeIgniter\Filters\DebugToolbar', (string) preg_replace('/\033\[.+?m/u', '', $this->getBuffer()),