Skip to content
This repository has been archived by the owner on Dec 11, 2021. It is now read-only.

Commit

Permalink
Merge pull request #10 from shochdoerfer/feature/filter_routes
Browse files Browse the repository at this point in the history
Add route url filtering via --route flag
  • Loading branch information
shochdoerfer authored Aug 12, 2018
2 parents e6bb539 + c174cb0 commit df9ed18
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 56 deletions.
18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,32 @@ composer.phar require --dev bitexpert/magerun2-list-api-endpoints
This plugin adds the `api:list:endpoints` command to magerun2.

You are able to filter routes by their respective HTTP methods. To only
see GET routes, run magerun2 like this:
see `GET` routes, run magerun2 like this:

```
magerun2 api:list:endpoints --method=get
```

To list all GET and POST routes, pass a comma-separated list as method argument:
To list all `GET` and `POST` routes, pass a comma-separated list as method argument:

```
magerun2 api:list:endpoints --method=get,post
```

You are able to filter routes by their url. To only see `customers` routes,
run magerun2 like this:

```
magerun2 api:list:endpoints --route=customers
```

Both filters can be combined, to show only `customers` routes with the `GET`
method, run magerun2 like this:

```
magerun2 api:list:endpoints --route=customers --method=get
```

## Contribute

Please feel free to fork and extend existing or add new features and send
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class ListApiEndpoints extends AbstractMagentoCommand
{
const OPTION_OUTPUT_FORMAT = 'output-format';
const OPTION_FILTER_METHOD = 'method';
const OPTION_FILTER_ROUTE = 'route';

/**
* {@inheritdoc}
Expand All @@ -45,6 +46,13 @@ protected function configure()
InputOption::VALUE_OPTIONAL,
'Filters routes for given method. Pass multiple methods as comma-separated list',
''
)
->addOption(
self::OPTION_FILTER_ROUTE,
'r',
InputOption::VALUE_OPTIONAL,
'Filters routes by given part',
''
);
}

Expand All @@ -56,7 +64,9 @@ protected function execute(InputInterface $input, OutputInterface $output)
$this->detectMagento($output);
if ($this->initMagento()) {
$methodFilter = $input->getOption(self::OPTION_FILTER_METHOD);
$services = $this->filterServices($this->getDefinedServices(), $methodFilter);
$routeFilter = $input->getOption(self::OPTION_FILTER_ROUTE);
$services = $this->getDefinedServices();
$services = $this->filterServices($services, $methodFilter, $routeFilter);

$outputFormat = $input->getOption(self::OPTION_OUTPUT_FORMAT);
switch ($outputFormat) {
Expand Down Expand Up @@ -110,16 +120,29 @@ private function printAsTable(array $services, OutputInterface $output)
*
* @param array $services
* @param string $methodsToFilter
* @param string $routesToFilter
* @return array
*/
private function filterServices(array $services, $methodsToFilter)
private function filterServices(array $services, $methodsToFilter, $routesToFilter)
{
if(empty($methodsToFilter)) {
if(!isset($services['routes']) || !is_array($services['routes'])) {
return $services;
}

$methodsToFilterArray = explode(',', strtoupper($methodsToFilter));
if(isset($services['routes']) && is_array($services['routes'])) {
if(!empty($routesToFilter)) {
foreach ($services['routes'] as $route => $methods) {
if (strpos($route, $routesToFilter) === false) {
unset($services['routes'][$route]);
}
}
}

if(!empty($methodsToFilter)) {
$methodsToFilterArray = explode(',', strtoupper($methodsToFilter));
array_walk($methodsToFilterArray, function(&$value, $index) {
$value = trim($value);
});

foreach ($services['routes'] as $route => $methods) {
foreach ($methods as $method => $config) {
if(!in_array($method, $methodsToFilterArray)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@
*/
class ListApiEndpointsUnitTest extends TestCase
{
/**
* Number of lines rendered for a table without any data, just the table header
*/
const EMPTY_TABLE_OUTPUT_LINES = 3;
/**
* Minimum number of lines rendered for a table with data and the table header
*/
const TABLE_OUTPUT_LINES = 4;
/**
* @var InputInterface
*/
Expand Down Expand Up @@ -74,12 +82,13 @@ public function missingOutputFormatParameterThrowsException()
public function withOutputFormatParameterSetTheCommandWillRenderTableStructure()
{
// since no services are returned, just the table header is rendered
$this->output->expects($this->exactly($this->countTableRowsToPrint()))
$this->output->expects($this->exactly(self::EMPTY_TABLE_OUTPUT_LINES))
->method('writeln');

$this->input->expects($this->any())
->method('getOption')
->will($this->returnValueMap([
[ListApiEndpoints::OPTION_FILTER_ROUTE, ''],
[ListApiEndpoints::OPTION_FILTER_METHOD, ''],
[ListApiEndpoints::OPTION_OUTPUT_FORMAT, 'table'],
]));
Expand All @@ -103,12 +112,13 @@ public function forEachDefinedRouteTheCommandWillRenderTableRow()
]
];

$this->output->expects($this->exactly($this->countTableRowsToPrint($services)))
$this->output->expects($this->exactly(self::TABLE_OUTPUT_LINES + 1))
->method('writeln');

$this->input->expects($this->any())
->method('getOption')
->will($this->returnValueMap([
[ListApiEndpoints::OPTION_FILTER_ROUTE, ''],
[ListApiEndpoints::OPTION_FILTER_METHOD, ''],
[ListApiEndpoints::OPTION_OUTPUT_FORMAT, 'table'],
]));
Expand All @@ -124,7 +134,7 @@ public function forEachDefinedRouteTheCommandWillRenderTableRow()
/**
* @test
*/
public function forEachFilteredRouteTheCommandWillRenderTableRow()
public function forEachFilteredRouteByMethodTheCommandWillRenderTableRow()
{
$filter = 'GET';
$services['routes'] = [
Expand All @@ -139,12 +149,88 @@ public function forEachFilteredRouteTheCommandWillRenderTableRow()
],
];

$this->output->expects($this->exactly($this->countTableRowsToPrint($services, $filter)))
$this->output->expects($this->exactly(self::TABLE_OUTPUT_LINES + 2))
->method('writeln');

$this->input->expects($this->any())
->method('getOption')
->will($this->returnValueMap([
[ListApiEndpoints::OPTION_FILTER_ROUTE, ''],
[ListApiEndpoints::OPTION_FILTER_METHOD, $filter],
[ListApiEndpoints::OPTION_OUTPUT_FORMAT, 'table'],
]));

/** @var ListApiEndpoints $command */
$command = $this->getApiEndpointsMock();
$command->method('getDefinedServices')
->willReturn($services);
$command->setApplication($this->application);
$command->run($this->input, $this->output);
}

/**
* @test
*/
public function forMultipleFilteredRoutesByMethodTheCommandWillRenderTableRow()
{
$filter = 'GET, POST';
$services['routes'] = [
'/route' => [
'GET' => ['resources' => '{}'],
'PUT' => ['resources' => '{}']
],
'/other-route' => [
'GET' => ['resources' => '{}'],
'POST' => ['resources' => '{}'],
'DELETE' => ['resources' => '{}']
],
];

$this->output->expects($this->exactly(self::TABLE_OUTPUT_LINES + 3))
->method('writeln');

$this->input->expects($this->any())
->method('getOption')
->will($this->returnValueMap([
[ListApiEndpoints::OPTION_FILTER_ROUTE, ''],
[ListApiEndpoints::OPTION_FILTER_METHOD, $filter],
[ListApiEndpoints::OPTION_OUTPUT_FORMAT, 'table'],
]));

/** @var ListApiEndpoints $command */
$command = $this->getApiEndpointsMock();
$command->method('getDefinedServices')
->willReturn($services);
$command->setApplication($this->application);
$command->run($this->input, $this->output);
}

/**
* @test
*/
public function forMultipleFilteredRoutesByRouteTheCommandWillRenderTableRow()
{
$filter = '';
$route = 'other';
$services['routes'] = [
'/route' => [
'GET' => ['resources' => '{}'],
'PUT' => ['resources' => '{}']
],
'/other-route' => [
'GET' => ['resources' => '{}'],
'POST' => ['resources' => '{}'],
'DELETE' => ['resources' => '{}']
],
];

$this->output->expects($this->exactly(self::TABLE_OUTPUT_LINES + 3))
->method('writeln');

$this->input->expects($this->any())
->method('getOption')
->will($this->returnValueMap([
[ListApiEndpoints::OPTION_FILTER_ROUTE, $route],
[ListApiEndpoints::OPTION_FILTER_METHOD, $filter],
[ListApiEndpoints::OPTION_OUTPUT_FORMAT, 'table'],
]));
Expand All @@ -160,9 +246,10 @@ public function forEachFilteredRouteTheCommandWillRenderTableRow()
/**
* @test
*/
public function forMultipleFilteredRoutesTheCommandWillRenderTableRow()
public function forMultipleFilteredRoutesByMethodAndRouteTheCommandWillRenderTableRow()
{
$filter = 'GET, POST';
$route = 'other';
$services['routes'] = [
'/route' => [
'GET' => ['resources' => '{}'],
Expand All @@ -175,12 +262,13 @@ public function forMultipleFilteredRoutesTheCommandWillRenderTableRow()
],
];

$this->output->expects($this->exactly($this->countTableRowsToPrint($services, $filter)))
$this->output->expects($this->exactly(self::TABLE_OUTPUT_LINES + 2))
->method('writeln');

$this->input->expects($this->any())
->method('getOption')
->will($this->returnValueMap([
[ListApiEndpoints::OPTION_FILTER_ROUTE, $route],
[ListApiEndpoints::OPTION_FILTER_METHOD, $filter],
[ListApiEndpoints::OPTION_OUTPUT_FORMAT, 'table'],
]));
Expand Down Expand Up @@ -212,47 +300,4 @@ protected function getApiEndpointsMock()
->willReturn(true);
return $command;
}

/**
* Helper method to count the routes in given $services array.
*
* @param array $services
* @param string $filter
* @return int
*/
protected function countRoutes(array $services, $filter = '')
{
$routesCounter = 0;
$methodsToFilterArray = explode(',', strtoupper($filter));

if(isset($services['routes']) && is_array($services['routes'])) {
foreach ($services['routes'] as $route => $methods) {
foreach ($methods as $method => $config) {
if(empty($filter) || in_array($method, $methodsToFilterArray)) {
$routesCounter++;
}
}
}
}

return $routesCounter;
}

/**
* Helper method to count all the rows printed by the Symfony Console Table component
* based on the given input parameters.
*
* @param array $services
* @param string $filter
* @return int
*/
protected function countTableRowsToPrint(array $services = [], $filter = '')
{
if (count($services) === 0 && empty($filter)) {
// default amount of rows that Symfony Console Table component will render
return 3;
}

return 4 + $this->countRoutes($services, $filter);
}
}

0 comments on commit df9ed18

Please sign in to comment.