diff --git a/infection.json.dist b/infection.json.dist index 3776e22..dfda80e 100644 --- a/infection.json.dist +++ b/infection.json.dist @@ -12,5 +12,6 @@ }, "mutators": { "@default": true - } + }, + "minMsi": 100 } diff --git a/src/FileRouter.php b/src/FileRouter.php index 7733f35..ebcce4a 100644 --- a/src/FileRouter.php +++ b/src/FileRouter.php @@ -155,61 +155,56 @@ private function parseRequestPath(ServerRequestInterface $request): Generator } } - $possibleAction = null; - if ($path === '/') { yield [ - $this->cleanClassname( - $this->namespace . '\\' . $this->baseControllerDirectory . '\\' . $this->defaultControllerName . $this->classPostfix - ), - $possibleAction, + $this->makeClassName($this->defaultControllerName, ''), + null, ]; return; } - $controllerName = preg_replace_callback( - '#(/.)#u', - static fn(array $matches) => mb_strtoupper($matches[1]), + $pathAsNamespace = preg_replace_callback( + '#/.#u', + static fn(array $matches) => mb_strtoupper($matches[0]), $path, ); - if (!preg_match('#^(.*?)/([^/]+)/?$#', $controllerName, $matches)) { + if (!preg_match('#^/?(.*?)/([^/]+)/?$#', $pathAsNamespace, $matches)) { return; } - - $directoryPath = $matches[1]; - $controllerName = $matches[2]; + [, $directoryPath, $controllerName] = $matches; yield [ - $this->cleanClassname( - $this->namespace . '\\' . $this->baseControllerDirectory . '\\' . $directoryPath . '\\' . $controllerName . $this->classPostfix - ), - $possibleAction, + $this->makeClassName($controllerName, $directoryPath), + null, ]; - if (preg_match('#^(.*?)/([^/]+)/?$#', $directoryPath, $matches)) { - $possibleAction = strtolower($controllerName); - $directoryPath = $matches[1]; - $controllerName = $matches[2]; + if ($directoryPath === '') { + yield [ + $this->makeClassName($this->defaultControllerName, $controllerName), + null, + ]; } else { - $directoryPath = $controllerName; - $controllerName = $this->defaultControllerName; + yield [ + $this->makeClassName($directoryPath, ''), + strtolower($controllerName), + ]; } - - yield [ - $this->cleanClassname( - $this->namespace . '\\' . $this->baseControllerDirectory . '\\' . $directoryPath . '\\' . $controllerName . $this->classPostfix - ), - $possibleAction, - ]; } - private function cleanClassname(string $className): string + private function makeClassName(string $controllerName, string $directoryPath): string { - return str_replace( - ['\\/\\', '\\/', '\\\\'], - '\\', - $className, - ); + $parts = []; + if ($this->namespace !== '') { + $parts[] = $this->namespace; + } + if ($this->baseControllerDirectory !== '') { + $parts[] = $this->baseControllerDirectory; + } + if ($directoryPath !== '') { + $parts[] = str_replace('/', '\\', $directoryPath); + } + $parts[] = str_replace('/', '\\', $controllerName) . $this->classPostfix; + return implode('\\', $parts); } } diff --git a/tests/FileRouterTest.php b/tests/FileRouterTest.php index 3257814..c7c433e 100644 --- a/tests/FileRouterTest.php +++ b/tests/FileRouterTest.php @@ -17,6 +17,7 @@ use Yiisoft\FileRouter\Tests\Support\App3; use Yiisoft\FileRouter\Tests\Support\App4; use Yiisoft\FileRouter\Tests\Support\App5; +use Yiisoft\FileRouter\Tests\Support\App6; use Yiisoft\FileRouter\Tests\Support\HeaderMiddleware; use Yiisoft\Middleware\Dispatcher\MiddlewareDispatcher; use Yiisoft\Middleware\Dispatcher\MiddlewareFactory; @@ -103,6 +104,26 @@ public static function dataRouter(): iterable '/user', 'Hello, delete!', ]; + yield 'HEAD /user' => [ + 'HEAD', + '/user', + 'Hello, head!', + ]; + yield 'OPTIONS /user' => [ + 'OPTIONS', + '/user', + 'Hello, options!', + ]; + yield 'GET /user/profile/view' => [ + 'GET', + '/user/profile/view', + 'Hello, User\Profile\IndexController!', + ]; + yield 'GET /user/blog/view' => [ + 'GET', + '/user/blog/view', + 'Hello, blog view!', + ]; } public function testUnsupportedMethod(): void @@ -272,19 +293,41 @@ public function testRoutesCollision(string $method, string $uri, string $expecte public static function dataRoutesCollision(): iterable { - yield 'direct' => [ + yield 'direct get' => [ 'GET', '/user', - 'Hello, Controller/UserController!', + 'Hello, index Controller/UserController!', + ]; + yield 'direct delete' => [ + 'DELETE', + '/user', + 'Hello, delete Controller/UserController!', ]; - yield 'indirect' => [ + yield 'indirect post' => [ 'POST', '/user', - 'Hello, Controller/User/IndexController!', + 'Hello, create Controller/User/IndexController!', ]; } + public function testActions(): void + { + $router = $this->createRouter(); + $router = $router->withNamespace('Yiisoft\FileRouter\Tests\Support\App6'); + + $handler = $this->createExceptionHandler(); + $request = new ServerRequest( + method: 'POST', + uri: '/user', + ); + + $response = $router->process($request, $handler); + + $this->assertEquals(200, $response->getStatusCode()); + $this->assertEquals('Hello, create Controller/User/IndexController!', (string) $response->getBody()); + } + #[DataProvider('dataUnicodeRoutes')] public function testTestUnicodeRoutes(string $method, string $uri, string $expectedResponse): void { @@ -370,6 +413,13 @@ public static function dataModularity(): iterable '/m/o/d/u/l/e/index', 'Hello, module2!', ]; + yield 'модуль3 /index' => [ + 'Yiisoft\\FileRouter\\Tests\\Support\\App5\\Модуль3', + '/Модуль3', + 'GET', + '/Модуль3/index', + 'Hello, модуль3!', + ]; } public function testModularityFastPath(): void @@ -407,6 +457,7 @@ private function createRouter(): FileRouter $container = new SimpleContainer([ HeaderMiddleware::class => new HeaderMiddleware(), + App1\Controller\User\Profile\ViewController::class => new App1\Controller\User\Profile\ViewController(), App1\Controller\User\BlogController::class => new App1\Controller\User\BlogController(), App1\Controller\UserController::class => new App1\Controller\UserController(), App1\Controller\IndexController::class => new App1\Controller\IndexController(), @@ -421,6 +472,10 @@ private function createRouter(): FileRouter App5\Module1\Controller\IndexController::class => new App5\Module1\Controller\IndexController(), App5\Module2\Controller\IndexController::class => new App5\Module2\Controller\IndexController(), + App5\Модуль3\Controller\Index\IndexController::class => new App5\Модуль3\Controller\Index\IndexController(), + + App6\Controller\UserController::class => new App6\Controller\UserController(), + App6\Controller\User\IndexController::class => new App6\Controller\User\IndexController(), ]); return new FileRouter( diff --git a/tests/Support/App1/Controller/User/BlogController.php b/tests/Support/App1/Controller/User/BlogController.php index 5215cda..d001105 100644 --- a/tests/Support/App1/Controller/User/BlogController.php +++ b/tests/Support/App1/Controller/User/BlogController.php @@ -20,4 +20,9 @@ public function index(): ResponseInterface { return new TextResponse('Hello, index!'); } + + public function view(): ResponseInterface + { + return new TextResponse('Hello, blog view!'); + } } diff --git a/tests/Support/App1/Controller/User/Profile/ViewController.php b/tests/Support/App1/Controller/User/Profile/ViewController.php new file mode 100644 index 0000000..202dfaa --- /dev/null +++ b/tests/Support/App1/Controller/User/Profile/ViewController.php @@ -0,0 +1,16 @@ + 'index', + ]; + + public function index(): ResponseInterface + { + return new TextResponse('Hello, index Controller/UserController!'); + } + + public function create(): ResponseInterface + { + return new TextResponse('Hello, create Controller/UserController!'); + } +}