Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: spark filter:check shows filter classnames #8985

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions phpstan-baseline.php
Original file line number Diff line number Diff line change
Expand Up @@ -877,18 +877,6 @@
'count' => 3,
'path' => __DIR__ . '/system/Commands/Utilities/Environment.php',
];
$ignoreErrors[] = [
// identifier: missingType.iterableValue
'message' => '#^Method CodeIgniter\\\\Commands\\\\Utilities\\\\FilterCheck\\:\\:addRequiredFilters\\(\\) has parameter \\$filters with no value type specified in iterable type array\\.$#',
'count' => 1,
'path' => __DIR__ . '/system/Commands/Utilities/FilterCheck.php',
];
$ignoreErrors[] = [
// identifier: missingType.iterableValue
'message' => '#^Method CodeIgniter\\\\Commands\\\\Utilities\\\\FilterCheck\\:\\:addRequiredFilters\\(\\) return type has no value type specified in iterable type array\\.$#',
'count' => 1,
'path' => __DIR__ . '/system/Commands/Utilities/FilterCheck.php',
];
$ignoreErrors[] = [
// identifier: missingType.iterableValue
'message' => '#^Method CodeIgniter\\\\Commands\\\\Utilities\\\\Namespaces\\:\\:outputAllNamespaces\\(\\) has parameter \\$params with no value type specified in iterable type array\\.$#',
Expand Down
108 changes: 76 additions & 32 deletions system/Commands/Utilities/FilterCheck.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,7 @@ class FilterCheck extends BaseCommand
*/
public function run(array $params)
{
$tbody = [];
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');

if (! $this->checkParams($params)) {
return EXIT_ERROR;
}

Expand Down Expand Up @@ -107,49 +101,99 @@ public function run(array $params)
return EXIT_ERROR;
}

$filters = $this->addRequiredFilters($filterCollector, $filters);
$this->showTable($filterCollector, $filters, $method, $route);
$this->showFilterClasses($filterCollector, $method, $route);

$tbody[] = [
strtoupper($method),
$route,
implode(' ', $filters['before']),
implode(' ', $filters['after']),
];
return EXIT_SUCCESS;
}

/**
* @param array<int|string, string|null> $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<string>, after: list<string>} $filters
*/
private function showTable(
FilterCollector $filterCollector,
array $filters,
string $method,
string $route
): void {
$thead = [
'Method',
'Route',
'Before Filters',
'After Filters',
];

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

return EXIT_SUCCESS;
$coloredRequired = $this->colorItems($required);

$before = array_merge($coloredRequired['before'], $filters['before']);
$after = array_merge($filters['after'], $coloredRequired['after']);

$tbody = [];
$tbody[] = [
strtoupper($method),
$route,
implode(' ', $before),
implode(' ', $after),
];

CLI::table($tbody, $thead);
}

private function addRequiredFilters(FilterCollector $filterCollector, array $filters): array
/**
* Color all elements of the array.
*
* @param array<array-key, mixed> $array
*
* @return array<array-key, mixed>
*/
private function colorItems(array $array): array
{
$output = [];
return array_map(function ($item) {
if (is_array($item)) {
return $this->colorItems($item);
}

$required = $filterCollector->getRequiredFilters();
return CLI::color($item, 'yellow');
}, $array);
}

$colored = [];
private function showFilterClasses(
FilterCollector $filterCollector,
string $method,
string $route
): void {
$requiredFilterClasses = $filterCollector->getRequiredFilterClasses();
$filterClasses = $filterCollector->getClasses($method, $route);

foreach ($required['before'] as $filter) {
$filter = CLI::color($filter, 'yellow');
$colored[] = $filter;
}
$output['before'] = array_merge($colored, $filters['before']);
$coloredRequiredFilterClasses = $this->colorItems($requiredFilterClasses);

$colored = [];
$classList = [
'before' => array_merge($coloredRequiredFilterClasses['before'], $filterClasses['before']),
'after' => array_merge($filterClasses['after'], $coloredRequiredFilterClasses['after']),
];

foreach ($required['after'] as $filter) {
$filter = CLI::color($filter, 'yellow');
$colored[] = $filter;
foreach ($classList as $position => $classes) {
CLI::write(ucfirst($position) . ' Filter Classes:', 'cyan');
CLI::write(implode(' → ', $classes));
}
$output['after'] = array_merge($filters['after'], $colored);

return $output;
}
}
64 changes: 62 additions & 2 deletions system/Commands/Utilities/Routes/FilterCollector.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public function __construct(
* @param string $method HTTP verb like `GET`,`POST` or `CLI`.
* @param string $uri URI path to find filters for
*
* @return array{before: list<string>, after: list<string>} array of filter alias or classname
* @return array{before: list<string>, after: list<string>} array of alias/classname:args
*/
public function get(string $method, string $uri): array
{
Expand Down Expand Up @@ -79,10 +79,52 @@ public function get(string $method, string $uri): array
return $finder->find($uri);
}

/**
* Returns filter classes for the URI
*
* @param string $method HTTP verb like `GET`,`POST` or `CLI`.
* @param string $uri URI path to find filters for
*
* @return array{before: list<string>, after: list<string>} array of classname:args
*/
public function getClasses(string $method, string $uri): array
{
if ($method === strtolower($method)) {
@trigger_error(
'Passing lowercase HTTP method "' . $method . '" is deprecated.'
. ' Use uppercase HTTP method like "' . strtoupper($method) . '".',
E_USER_DEPRECATED
);
}

/**
* @deprecated 4.5.0
* @TODO Remove this in the future.
*/
$method = strtoupper($method);

if ($method === 'CLI') {
return [
'before' => [],
'after' => [],
];
}

$request = Services::incomingrequest(null, false);
$request->setMethod($method);

$router = $this->createRouter($request);
$filters = $this->createFilters($request);

$finder = new FilterFinder($router, $filters);

return $finder->findClasses($uri);
}

/**
* Returns Required Filters
*
* @return array{before: list<string>, after: list<string>} array of filter alias or classname
* @return array{before: list<string>, after: list<string>} array of aliases
*/
public function getRequiredFilters(): array
{
Expand All @@ -97,6 +139,24 @@ public function getRequiredFilters(): array
return $finder->getRequiredFilters();
}

/**
* Returns Required Filter class list
*
* @return array{before: list<string>, after: list<string>} array of classnames
*/
public function getRequiredFilterClasses(): array
{
$request = Services::incomingrequest(null, false);
$request->setMethod(Method::GET);

$router = $this->createRouter($request);
$filters = $this->createFilters($request);

$finder = new FilterFinder($router, $filters);

return $finder->getRequiredFilterClasses();
}

private function createRouter(Request $request): Router
{
$routes = service('routes');
Expand Down
92 changes: 86 additions & 6 deletions system/Commands/Utilities/Routes/FilterFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,23 +46,20 @@ private function getRouteFilters(string $uri): array
/**
* @param string $uri URI path to find filters for
*
* @return array{before: list<string>, after: list<string>} array of filter alias or classname
* @return array{before: list<string>, after: list<string>} array of alias/classname:args
*/
public function find(string $uri): array
{
$this->filters->reset();

// Add route filters
try {
// Add route filters
$routeFilters = $this->getRouteFilters($uri);

$this->filters->enableFilters($routeFilters, 'before');

$oldFilterOrder = config(Feature::class)->oldFilterOrder ?? false;
if (! $oldFilterOrder) {
$routeFilters = array_reverse($routeFilters);
}

$this->filters->enableFilters($routeFilters, 'after');

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

/**
* @param string $uri URI path to find filters for
*
* @return array{before: list<string>, after: list<string>} array of classname:args
*/
public function findClasses(string $uri): array
{
$this->filters->reset();

try {
// Add route filters
$routeFilters = $this->getRouteFilters($uri);
$this->filters->enableFilters($routeFilters, 'before');
$oldFilterOrder = config(Feature::class)->oldFilterOrder ?? false;
if (! $oldFilterOrder) {
$routeFilters = array_reverse($routeFilters);
}
$this->filters->enableFilters($routeFilters, 'after');

$this->filters->initialize($uri);

$filterClassList = $this->filters->getFiltersClass();

$filterClasses = [
'before' => [],
'after' => [],
];

foreach ($filterClassList['before'] as $classInfo) {
$classWithArguments = ($classInfo[1] === []) ? $classInfo[0]
: $classInfo[0] . ':' . implode(',', $classInfo[1]);

$filterClasses['before'][] = $classWithArguments;
}

foreach ($filterClassList['after'] as $classInfo) {
$classWithArguments = ($classInfo[1] === []) ? $classInfo[0]
: $classInfo[0] . ':' . implode(',', $classInfo[1]);

$filterClasses['after'][] = $classWithArguments;
}

return $filterClasses;
} catch (RedirectException) {
return [
'before' => [],
'after' => [],
];
} catch (BadRequestException|PageNotFoundException) {
return [
'before' => ['<unknown>'],
'after' => ['<unknown>'],
];
}
}

/**
* Returns Required Filters
*
* @return array{before: list<string>, after:list<string>}
* @return array{before: list<string>, after:list<string>} array of aliases
*/
public function getRequiredFilters(): array
{
Expand All @@ -96,4 +149,31 @@ public function getRequiredFilters(): array
'after' => $requiredAfter,
];
}

/**
* Returns Required Filter classes
*
* @return array{before: list<string>, after:list<string>}
*/
public function getRequiredFilterClasses(): array
{
$before = $this->filters->getRequiredClasses('before');
$after = $this->filters->getRequiredClasses('after');

$requiredBefore = [];
$requiredAfter = [];

foreach ($before as $classInfo) {
$requiredBefore[] = $classInfo[0];
}

foreach ($after as $classInfo) {
$requiredAfter[] = $classInfo[0];
}

return [
'before' => $requiredBefore,
'after' => $requiredAfter,
];
}
}
Loading
Loading