From 6dbd68fc3d7a23c7613e3ac019581bb1a131495e Mon Sep 17 00:00:00 2001 From: Andrew Coulton Date: Tue, 6 Mar 2018 17:09:08 +0000 Subject: [PATCH] Add support for namespaced controllers Per kohana/core#578 from @rjd22 --- CHANGELOG.md | 2 + classes/Kohana/Request/Client/Internal.php | 6 ++ classes/Kohana/Route.php | 8 +++ tests/kohana/RouteTest.php | 19 ++++++ tests/kohana/request/client/InternalTest.php | 61 ++++++++++++++++++++ 5 files changed, 96 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2ca7b2f..55ee2423 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ You're really going to want to read this. ## Unreleased +* Add support for loading controllers with namespaced classes per https://github.com/kohana/core/pull/578/files + thanks to @rjd22 for the original implementation. * Removed default support for passing client params to Request_Client * Add new Request::initInitial which should now be called from index.php when creating the main request. Request::fromGlobals no longer modifies any global state. diff --git a/classes/Kohana/Request/Client/Internal.php b/classes/Kohana/Request/Client/Internal.php index 29d81b12..bc5c4746 100644 --- a/classes/Kohana/Request/Client/Internal.php +++ b/classes/Kohana/Request/Client/Internal.php @@ -40,6 +40,12 @@ public function execute_request(Request $request, Response $response) $prefix .= str_replace(array('\\', '/'), '_', trim($directory, '/')).'_'; } + // Use the FQCN to load the Controller + if (substr($controller, 0, 1) === '\\') + { + $prefix = ''; + } + if (Kohana::$profiling) { // Set the benchmark name diff --git a/classes/Kohana/Route.php b/classes/Kohana/Route.php index 976c46f5..502f23ef 100644 --- a/classes/Kohana/Route.php +++ b/classes/Kohana/Route.php @@ -351,6 +351,14 @@ public function defaults(array $defaults = NULL) return $this->_defaults; } + if (isset($defaults['controller']) AND substr($defaults['controller'], 0, 1) === '\\') + { + if (isset($defaults['directory'])) + { + throw new Kohana_Exception('Route directory should not be set when the controller is a FQCN.'); + } + } + $this->_defaults = $defaults; return $this; diff --git a/tests/kohana/RouteTest.php b/tests/kohana/RouteTest.php index 16696810..a597d335 100644 --- a/tests/kohana/RouteTest.php +++ b/tests/kohana/RouteTest.php @@ -512,6 +512,25 @@ public function test_defaults_are_not_used_if_param_is_identical() $this->assertSame('welcome2', $route->uri(array('controller' => 'welcome2'))); } + + /** + * When using a FQCN test if the directory is not set else throw an exception + * + * @test + * @covers Route::defaults + */ + public function test_defaults_throws_exception_when_setting_fqcn_and_directory() + { + $this->setExpectedException('Kohana_Exception', 'Route directory should not be set when the controller is a FQCN.'); + + $route = new Route('((/(/)))'); + $route->defaults(array( + 'directory' => 'directory/path', + 'controller' => '\FQCN\Class\Name', + 'action' => 'index' + )); + } + /** * Provider for test_required_parameters_are_needed * diff --git a/tests/kohana/request/client/InternalTest.php b/tests/kohana/request/client/InternalTest.php index d3b317ef..967f954b 100644 --- a/tests/kohana/request/client/InternalTest.php +++ b/tests/kohana/request/client/InternalTest.php @@ -76,4 +76,65 @@ public function test_response_failure_status($directory, $controller, $action, $ $this->assertSame($expected, $response->status()); } + + public function provider_controller_class() + { + return [ + [ + ['directory' => NULL, 'controller' => 'Test', 'action' => 'anything'], + 'Controller_Test', + 'Controller_Test::anything' + ], + [ + ['directory' => 'Subdir', 'controller' => 'Test', 'action' => 'anything'], + 'Controller_Subdir_Test', + 'Controller_Subdir_Test::anything' + ], + [ + ['directory' => NULL, 'controller' => '\My\Test\Test', 'action' => 'things'], + '\My\Test\Test', + 'My\Test\Test::things' + ], + [ + ['directory' => NULL, 'controller' => '\My\Test\TestController', 'action' => 'things'], + '\My\Test\TestController', + 'My\Test\TestController::things' + ], + + ]; + } + + /** + * @dataProvider provider_controller_class + */ + public function test_it_executes_expected_controller_class($params, $controller_class, $expect) + { + if ( ! class_exists($controller_class)) { + $this->defineExtensionClass($controller_class, ClassReturningController::class); + } + $client = new Request_Client_Internal; + $request = \Request::with($params); + $response = $client->execute($request); + $this->assertEquals($expect, $response->body()); + } + + protected function defineExtensionClass($fqcn, $base_class) + { + $parts = array_filter(explode('\\', $fqcn)); + $class = array_pop($parts); + $ns = implode('\\', $parts); + if ($ns) { + $ns = 'namespace '.$ns.';'; + } + eval("$ns class $class extends \\$base_class {}"); + } +} + +class ClassReturningController extends Controller { + + public function execute() + { + $this->response->body(get_class($this).'::'.$this->request->action()); + return $this->response; + } }