From 8994971b67bc712b5096730cd379371c63f80dc1 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Sun, 24 Jan 2016 12:42:54 -0500 Subject: [PATCH] Reject controller names that are not camel case. Controller names that are not CamelCase cause a few issues downstream: 1. They don't work on case-sensitive filesystems. 2. They cause Controller::$name and Controller::$modelClass to be wrong. To help reduce these cryptic and environment sensitive issues we reject all controller names that start with a lower case letter. Refs #8091 Refs #8085 --- src/Controller/Controller.php | 2 +- .../Filter/ControllerFactoryFilter.php | 7 ++++- tests/TestCase/Controller/ControllerTest.php | 6 ----- tests/TestCase/Routing/DispatcherTest.php | 26 ++++++++++++++++++- 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/Controller/Controller.php b/src/Controller/Controller.php index 76cc3d57d0f..dbd94778f4c 100644 --- a/src/Controller/Controller.php +++ b/src/Controller/Controller.php @@ -237,7 +237,7 @@ public function __construct(Request $request = null, Response $response = null, } if ($this->name === null && isset($request->params['controller'])) { - $this->name = Inflector::camelize($request->params['controller']); + $this->name = $request->params['controller']; } if ($this->name === null) { diff --git a/src/Routing/Filter/ControllerFactoryFilter.php b/src/Routing/Filter/ControllerFactoryFilter.php index b8642e6f86a..c73e1856ed9 100644 --- a/src/Routing/Filter/ControllerFactoryFilter.php +++ b/src/Routing/Filter/ControllerFactoryFilter.php @@ -74,7 +74,12 @@ protected function _getController($request, $response) ); $namespace .= '/' . implode('/', $prefixes); } - if (strpos($controller, '\\') !== false || strpos($controller, '.') !== false) { + $firstChar = substr($controller, 0, 1); + if ( + strpos($controller, '\\') !== false || + strpos($controller, '.') !== false || + $firstChar === strtolower($firstChar) + ) { return false; } $className = false; diff --git a/tests/TestCase/Controller/ControllerTest.php b/tests/TestCase/Controller/ControllerTest.php index a7be6991fc6..e07a2bc7d92 100644 --- a/tests/TestCase/Controller/ControllerTest.php +++ b/tests/TestCase/Controller/ControllerTest.php @@ -359,12 +359,6 @@ public function testConstructSetModelClass() $this->assertEquals('Posts', $controller->modelClass); $this->assertInstanceOf('Cake\ORM\Table', $controller->Posts); - $request->params['controller'] = 'posts'; - $controller = new \TestApp\Controller\PostsController($request, $response); - $this->assertEquals('Posts', $controller->modelClass); - $this->assertInstanceOf('Cake\ORM\Table', $controller->Posts); - unset($request->params['controller']); - $controller = new \TestApp\Controller\Admin\PostsController($request, $response); $this->assertEquals('Posts', $controller->modelClass); $this->assertInstanceOf('Cake\ORM\Table', $controller->Posts); diff --git a/tests/TestCase/Routing/DispatcherTest.php b/tests/TestCase/Routing/DispatcherTest.php index 7a5796f7c18..e528459027e 100644 --- a/tests/TestCase/Routing/DispatcherTest.php +++ b/tests/TestCase/Routing/DispatcherTest.php @@ -302,6 +302,30 @@ public function testMissingControllerAbstract() $this->dispatcher->dispatch($request, $response, ['return' => 1]); } + /** + * Test that lowercase controller names result in missing controller errors. + * + * In case-insensitive file systems, lowercase controller names will kind of work. + * This causes annoying deployment issues for lots of folks. + * + * @expectedException \Cake\Routing\Exception\MissingControllerException + * @expectedExceptionMessage Controller class somepages could not be found. + * @return void + */ + public function testMissingControllerLowercase() + { + $request = new Request([ + 'url' => 'pages/home', + 'params' => [ + 'controller' => 'somepages', + 'action' => 'display', + 'pass' => ['home'], + ] + ]); + $response = $this->getMock('Cake\Network\Response'); + $this->dispatcher->dispatch($request, $response, ['return' => 1]); + } + /** * testDispatch method * @@ -477,7 +501,7 @@ public function testDispatcherFilter() $request = new Request([ 'url' => '/', 'params' => [ - 'controller' => 'pages', + 'controller' => 'Pages', 'action' => 'display', 'home', 'pass' => []