Skip to content

Commit adc6598

Browse files
authored
Merge pull request #8985 from kenjis/feat-spark-filter-check-show-filter-classes
feat: `spark filter:check` shows filter classnames
2 parents b102b3e + 9c8f647 commit adc6598

File tree

9 files changed

+342
-96
lines changed

9 files changed

+342
-96
lines changed

phpstan-baseline.php

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -877,18 +877,6 @@
877877
'count' => 3,
878878
'path' => __DIR__ . '/system/Commands/Utilities/Environment.php',
879879
];
880-
$ignoreErrors[] = [
881-
// identifier: missingType.iterableValue
882-
'message' => '#^Method CodeIgniter\\\\Commands\\\\Utilities\\\\FilterCheck\\:\\:addRequiredFilters\\(\\) has parameter \\$filters with no value type specified in iterable type array\\.$#',
883-
'count' => 1,
884-
'path' => __DIR__ . '/system/Commands/Utilities/FilterCheck.php',
885-
];
886-
$ignoreErrors[] = [
887-
// identifier: missingType.iterableValue
888-
'message' => '#^Method CodeIgniter\\\\Commands\\\\Utilities\\\\FilterCheck\\:\\:addRequiredFilters\\(\\) return type has no value type specified in iterable type array\\.$#',
889-
'count' => 1,
890-
'path' => __DIR__ . '/system/Commands/Utilities/FilterCheck.php',
891-
];
892880
$ignoreErrors[] = [
893881
// identifier: missingType.iterableValue
894882
'message' => '#^Method CodeIgniter\\\\Commands\\\\Utilities\\\\Namespaces\\:\\:outputAllNamespaces\\(\\) has parameter \\$params with no value type specified in iterable type array\\.$#',

system/Commands/Utilities/FilterCheck.php

Lines changed: 76 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,7 @@ class FilterCheck extends BaseCommand
7373
*/
7474
public function run(array $params)
7575
{
76-
$tbody = [];
77-
if (! isset($params[0], $params[1])) {
78-
CLI::error('You must specify a HTTP verb and a route.');
79-
CLI::write(' Usage: ' . $this->usage);
80-
CLI::write('Example: filter:check GET /');
81-
CLI::write(' filter:check PUT products/1');
82-
76+
if (! $this->checkParams($params)) {
8377
return EXIT_ERROR;
8478
}
8579

@@ -107,49 +101,99 @@ public function run(array $params)
107101
return EXIT_ERROR;
108102
}
109103

110-
$filters = $this->addRequiredFilters($filterCollector, $filters);
104+
$this->showTable($filterCollector, $filters, $method, $route);
105+
$this->showFilterClasses($filterCollector, $method, $route);
111106

112-
$tbody[] = [
113-
strtoupper($method),
114-
$route,
115-
implode(' ', $filters['before']),
116-
implode(' ', $filters['after']),
117-
];
107+
return EXIT_SUCCESS;
108+
}
118109

110+
/**
111+
* @param array<int|string, string|null> $params
112+
*/
113+
private function checkParams(array $params): bool
114+
{
115+
if (! isset($params[0], $params[1])) {
116+
CLI::error('You must specify a HTTP verb and a route.');
117+
CLI::write(' Usage: ' . $this->usage);
118+
CLI::write('Example: filter:check GET /');
119+
CLI::write(' filter:check PUT products/1');
120+
121+
return false;
122+
}
123+
124+
return true;
125+
}
126+
127+
/**
128+
* @param array{before: list<string>, after: list<string>} $filters
129+
*/
130+
private function showTable(
131+
FilterCollector $filterCollector,
132+
array $filters,
133+
string $method,
134+
string $route
135+
): void {
119136
$thead = [
120137
'Method',
121138
'Route',
122139
'Before Filters',
123140
'After Filters',
124141
];
125142

126-
CLI::table($tbody, $thead);
143+
$required = $filterCollector->getRequiredFilters();
127144

128-
return EXIT_SUCCESS;
145+
$coloredRequired = $this->colorItems($required);
146+
147+
$before = array_merge($coloredRequired['before'], $filters['before']);
148+
$after = array_merge($filters['after'], $coloredRequired['after']);
149+
150+
$tbody = [];
151+
$tbody[] = [
152+
strtoupper($method),
153+
$route,
154+
implode(' ', $before),
155+
implode(' ', $after),
156+
];
157+
158+
CLI::table($tbody, $thead);
129159
}
130160

131-
private function addRequiredFilters(FilterCollector $filterCollector, array $filters): array
161+
/**
162+
* Color all elements of the array.
163+
*
164+
* @param array<array-key, mixed> $array
165+
*
166+
* @return array<array-key, mixed>
167+
*/
168+
private function colorItems(array $array): array
132169
{
133-
$output = [];
170+
return array_map(function ($item) {
171+
if (is_array($item)) {
172+
return $this->colorItems($item);
173+
}
134174

135-
$required = $filterCollector->getRequiredFilters();
175+
return CLI::color($item, 'yellow');
176+
}, $array);
177+
}
136178

137-
$colored = [];
179+
private function showFilterClasses(
180+
FilterCollector $filterCollector,
181+
string $method,
182+
string $route
183+
): void {
184+
$requiredFilterClasses = $filterCollector->getRequiredFilterClasses();
185+
$filterClasses = $filterCollector->getClasses($method, $route);
138186

139-
foreach ($required['before'] as $filter) {
140-
$filter = CLI::color($filter, 'yellow');
141-
$colored[] = $filter;
142-
}
143-
$output['before'] = array_merge($colored, $filters['before']);
187+
$coloredRequiredFilterClasses = $this->colorItems($requiredFilterClasses);
144188

145-
$colored = [];
189+
$classList = [
190+
'before' => array_merge($coloredRequiredFilterClasses['before'], $filterClasses['before']),
191+
'after' => array_merge($filterClasses['after'], $coloredRequiredFilterClasses['after']),
192+
];
146193

147-
foreach ($required['after'] as $filter) {
148-
$filter = CLI::color($filter, 'yellow');
149-
$colored[] = $filter;
194+
foreach ($classList as $position => $classes) {
195+
CLI::write(ucfirst($position) . ' Filter Classes:', 'cyan');
196+
CLI::write(implode('', $classes));
150197
}
151-
$output['after'] = array_merge($filters['after'], $colored);
152-
153-
return $output;
154198
}
155199
}

system/Commands/Utilities/Routes/FilterCollector.php

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public function __construct(
4343
* @param string $method HTTP verb like `GET`,`POST` or `CLI`.
4444
* @param string $uri URI path to find filters for
4545
*
46-
* @return array{before: list<string>, after: list<string>} array of filter alias or classname
46+
* @return array{before: list<string>, after: list<string>} array of alias/classname:args
4747
*/
4848
public function get(string $method, string $uri): array
4949
{
@@ -79,10 +79,52 @@ public function get(string $method, string $uri): array
7979
return $finder->find($uri);
8080
}
8181

82+
/**
83+
* Returns filter classes for the URI
84+
*
85+
* @param string $method HTTP verb like `GET`,`POST` or `CLI`.
86+
* @param string $uri URI path to find filters for
87+
*
88+
* @return array{before: list<string>, after: list<string>} array of classname:args
89+
*/
90+
public function getClasses(string $method, string $uri): array
91+
{
92+
if ($method === strtolower($method)) {
93+
@trigger_error(
94+
'Passing lowercase HTTP method "' . $method . '" is deprecated.'
95+
. ' Use uppercase HTTP method like "' . strtoupper($method) . '".',
96+
E_USER_DEPRECATED
97+
);
98+
}
99+
100+
/**
101+
* @deprecated 4.5.0
102+
* @TODO Remove this in the future.
103+
*/
104+
$method = strtoupper($method);
105+
106+
if ($method === 'CLI') {
107+
return [
108+
'before' => [],
109+
'after' => [],
110+
];
111+
}
112+
113+
$request = Services::incomingrequest(null, false);
114+
$request->setMethod($method);
115+
116+
$router = $this->createRouter($request);
117+
$filters = $this->createFilters($request);
118+
119+
$finder = new FilterFinder($router, $filters);
120+
121+
return $finder->findClasses($uri);
122+
}
123+
82124
/**
83125
* Returns Required Filters
84126
*
85-
* @return array{before: list<string>, after: list<string>} array of filter alias or classname
127+
* @return array{before: list<string>, after: list<string>} array of aliases
86128
*/
87129
public function getRequiredFilters(): array
88130
{
@@ -97,6 +139,24 @@ public function getRequiredFilters(): array
97139
return $finder->getRequiredFilters();
98140
}
99141

142+
/**
143+
* Returns Required Filter class list
144+
*
145+
* @return array{before: list<string>, after: list<string>} array of classnames
146+
*/
147+
public function getRequiredFilterClasses(): array
148+
{
149+
$request = Services::incomingrequest(null, false);
150+
$request->setMethod(Method::GET);
151+
152+
$router = $this->createRouter($request);
153+
$filters = $this->createFilters($request);
154+
155+
$finder = new FilterFinder($router, $filters);
156+
157+
return $finder->getRequiredFilterClasses();
158+
}
159+
100160
private function createRouter(Request $request): Router
101161
{
102162
$routes = service('routes');

system/Commands/Utilities/Routes/FilterFinder.php

Lines changed: 86 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,23 +46,20 @@ private function getRouteFilters(string $uri): array
4646
/**
4747
* @param string $uri URI path to find filters for
4848
*
49-
* @return array{before: list<string>, after: list<string>} array of filter alias or classname
49+
* @return array{before: list<string>, after: list<string>} array of alias/classname:args
5050
*/
5151
public function find(string $uri): array
5252
{
5353
$this->filters->reset();
5454

55-
// Add route filters
5655
try {
56+
// Add route filters
5757
$routeFilters = $this->getRouteFilters($uri);
58-
5958
$this->filters->enableFilters($routeFilters, 'before');
60-
6159
$oldFilterOrder = config(Feature::class)->oldFilterOrder ?? false;
6260
if (! $oldFilterOrder) {
6361
$routeFilters = array_reverse($routeFilters);
6462
}
65-
6663
$this->filters->enableFilters($routeFilters, 'after');
6764

6865
$this->filters->initialize($uri);
@@ -81,10 +78,66 @@ public function find(string $uri): array
8178
}
8279
}
8380

81+
/**
82+
* @param string $uri URI path to find filters for
83+
*
84+
* @return array{before: list<string>, after: list<string>} array of classname:args
85+
*/
86+
public function findClasses(string $uri): array
87+
{
88+
$this->filters->reset();
89+
90+
try {
91+
// Add route filters
92+
$routeFilters = $this->getRouteFilters($uri);
93+
$this->filters->enableFilters($routeFilters, 'before');
94+
$oldFilterOrder = config(Feature::class)->oldFilterOrder ?? false;
95+
if (! $oldFilterOrder) {
96+
$routeFilters = array_reverse($routeFilters);
97+
}
98+
$this->filters->enableFilters($routeFilters, 'after');
99+
100+
$this->filters->initialize($uri);
101+
102+
$filterClassList = $this->filters->getFiltersClass();
103+
104+
$filterClasses = [
105+
'before' => [],
106+
'after' => [],
107+
];
108+
109+
foreach ($filterClassList['before'] as $classInfo) {
110+
$classWithArguments = ($classInfo[1] === []) ? $classInfo[0]
111+
: $classInfo[0] . ':' . implode(',', $classInfo[1]);
112+
113+
$filterClasses['before'][] = $classWithArguments;
114+
}
115+
116+
foreach ($filterClassList['after'] as $classInfo) {
117+
$classWithArguments = ($classInfo[1] === []) ? $classInfo[0]
118+
: $classInfo[0] . ':' . implode(',', $classInfo[1]);
119+
120+
$filterClasses['after'][] = $classWithArguments;
121+
}
122+
123+
return $filterClasses;
124+
} catch (RedirectException) {
125+
return [
126+
'before' => [],
127+
'after' => [],
128+
];
129+
} catch (BadRequestException|PageNotFoundException) {
130+
return [
131+
'before' => ['<unknown>'],
132+
'after' => ['<unknown>'],
133+
];
134+
}
135+
}
136+
84137
/**
85138
* Returns Required Filters
86139
*
87-
* @return array{before: list<string>, after:list<string>}
140+
* @return array{before: list<string>, after:list<string>} array of aliases
88141
*/
89142
public function getRequiredFilters(): array
90143
{
@@ -96,4 +149,31 @@ public function getRequiredFilters(): array
96149
'after' => $requiredAfter,
97150
];
98151
}
152+
153+
/**
154+
* Returns Required Filter classes
155+
*
156+
* @return array{before: list<string>, after:list<string>}
157+
*/
158+
public function getRequiredFilterClasses(): array
159+
{
160+
$before = $this->filters->getRequiredClasses('before');
161+
$after = $this->filters->getRequiredClasses('after');
162+
163+
$requiredBefore = [];
164+
$requiredAfter = [];
165+
166+
foreach ($before as $classInfo) {
167+
$requiredBefore[] = $classInfo[0];
168+
}
169+
170+
foreach ($after as $classInfo) {
171+
$requiredAfter[] = $classInfo[0];
172+
}
173+
174+
return [
175+
'before' => $requiredBefore,
176+
'after' => $requiredAfter,
177+
];
178+
}
99179
}

0 commit comments

Comments
 (0)