Skip to content

Commit

Permalink
Prefix routing bug (#349)
Browse files Browse the repository at this point in the history
* Resolves #330
  • Loading branch information
cnizzardini authored Nov 24, 2021
1 parent 90c5a16 commit 3453a60
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 6 deletions.
25 changes: 25 additions & 0 deletions src/Lib/Route/RouteDecorator.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ class RouteDecorator
*/
private $controllerFqn;

/**
* @var string|null
*/
private $prefix;

/**
* @param \Cake\Routing\Route\Route $route Route
*/
Expand All @@ -73,6 +78,7 @@ public function __construct(Route $route)
->setName($route->getName())
->setPlugin($defaults['plugin'])
->setController($defaults['controller'])
->setPrefix($defaults['prefix'] ?? null)
->setAction($defaults['action'])
->setMethods($methods);
}
Expand Down Expand Up @@ -229,6 +235,25 @@ public function setControllerFqn(string $controllerFqn)
return $this;
}

/**
* @return string|null
*/
public function getPrefix(): ?string
{
return $this->prefix;
}

/**
* @param string|null $prefix The routing prefix, for example "Admin" when controller is in App\Controller\Admin
* @return $this
*/
public function setPrefix(?string $prefix)
{
$this->prefix = $prefix;

return $this;
}

/**
* Converts a CakePHP route template to an OpenAPI path
*
Expand Down
11 changes: 5 additions & 6 deletions src/Lib/Route/RouteScanner.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,12 @@ private function loadRoutes(): void
}

$routeDecorator = new RouteDecorator($route);
$path = 'Controller\\';
$path .= $routeDecorator->getPrefix() ? $routeDecorator->getPrefix() . '\\' : '';
$path .= $routeDecorator->getController() . 'Controller';

$controller = $routeDecorator->getController();

$results = array_filter($classes, function ($fqn) use ($controller, $route) {
$prefix = !empty($route->defaults['prefix']) ? $route->defaults['prefix'] . '\\' : '';

return strstr($fqn, '\\' . $prefix . $controller . 'Controller');
$results = array_filter($classes, function ($fqn) use ($path) {
return strstr($fqn, $path);
});

if (count($results) === 1) {
Expand Down
81 changes: 81 additions & 0 deletions tests/TestCase/Lib/Route/PrefixRouteTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php

namespace SwaggerBake\Test\TestCase\Lib\Route;

use Cake\Collection\Collection;
use Cake\Routing\RouteBuilder;
use Cake\Routing\Router;
use Cake\TestSuite\TestCase;
use SwaggerBake\Lib\Configuration;
use SwaggerBake\Lib\Model\ModelScanner;
use SwaggerBake\Lib\Route\RouteScanner;
use SwaggerBake\Lib\Swagger;

class PrefixRouteTest extends TestCase
{
/**
* @var string[]
*/
public $fixtures = [
'plugin.SwaggerBake.DepartmentEmployees',
'plugin.SwaggerBake.Departments',
'plugin.SwaggerBake.Employees',
];

/**
* @var Router
*/
private $router;

/**
* @var array
*/
private $config;

public function setUp(): void
{
parent::setUp(); // TODO: Change the autogenerated stub
$router = new Router();
$router::scope('/', function (RouteBuilder $builder) {
$builder->setExtensions(['json']);
$builder->resources('Departments');
$builder->resources('Departments', [
'prefix' => 'Admin',
'path' => 'admin/departments',
'only' => ['index']
]);
});
$this->router = $router;

$this->config = [
'prefix' => '/',
'yml' => '/config/swagger-bare-bones.yml',
'json' => '/webroot/swagger.json',
'webPath' => '/swagger.json',
'hotReload' => false,
'exceptionSchema' => 'Exception',
'requestAccepts' => ['application/x-www-form-urlencoded'],
'responseContentTypes' => ['application/json'],
'namespaces' => [
'controllers' => ['\SwaggerBakeTest\App\\'],
'entities' => ['\SwaggerBakeTest\App\\'],
'tables' => ['\SwaggerBakeTest\App\\'],
]
];
}

/**
* Tests prefix routing by verifying that paths are added for:
* - App\Controller\DepartmentsController
* - App\Controller\Admin\DepartmentsController
*/
public function test_prefix_routing_with_same_controller_shortname(): void
{
$config = new Configuration($this->config, SWAGGER_BAKE_TEST_APP);
$cakeRoute = new RouteScanner($this->router, $config);
$openApi = (new Swagger(new ModelScanner($cakeRoute, $config)))->getArray();
$paths = new Collection(array_keys($openApi['paths']));
$this->assertTrue($paths->contains('/admin/departments'));
$this->assertTrue($paths->contains('/departments'));
}
}
27 changes: 27 additions & 0 deletions tests/test_app/src/Controller/Admin/DepartmentsController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);

namespace SwaggerBakeTest\App\Controller\Admin;

use SwaggerBakeTest\App\Controller\AppController;

/**
* Departments Controller
*
* @property \App\Model\Table\DepartmentsTable $Departments
*
* @method \App\Model\Entity\Department[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = [])
*/
class DepartmentsController extends AppController
{
/**
* Just a test for prefix routing when two controllers share the same short name
*/
public function index()
{
$departments = $this->paginate($this->Departments);

$this->set(compact('departments'));
$this->viewBuilder()->setOption('serialize', 'departments');
}
}

0 comments on commit 3453a60

Please sign in to comment.