From da2fd13b38cc45b282bec3e8ed4b1e2ded60a351 Mon Sep 17 00:00:00 2001 From: Andrew Short Date: Sun, 11 Oct 2009 00:07:07 +0000 Subject: [PATCH] FEATURE: Allow you to access nested pages by falling over to a child page in ContentController if one is available. From: Andrew Short git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@88483 467b73ca-7a2a-4603-9d3b-597d59a354a9 --- core/control/ContentController.php | 26 ++++++++++ core/control/HTTPRequest.php | 18 +++++++ tests/control/ContentControllerTest.php | 65 +++++++++++++++++++++++++ tests/control/ContentControllerTest.yml | 16 ++++++ 4 files changed, 125 insertions(+) mode change 100644 => 100755 core/control/HTTPRequest.php create mode 100755 tests/control/ContentControllerTest.php create mode 100755 tests/control/ContentControllerTest.yml diff --git a/core/control/ContentController.php b/core/control/ContentController.php index 9357334d8..b0e0b9dac 100755 --- a/core/control/ContentController.php +++ b/core/control/ContentController.php @@ -155,6 +155,32 @@ class ContentController extends Controller { return new $controllerClass($widget); } + /** + * This acts the same as {@link Controller::handleRequest()}, but if an action cannot be found this will attempt to + * fall over to a child controller in order to provide functionality for nested URLs. + * + * @return HTTPResponse + */ + public function handleRequest(HTTPRequest $request) { + $response = parent::handleRequest($request); + + // If the default handler returns an error, due to the action not existing, attempt to fall over to a child + // SiteTree object, then use its corresponding ContentController to handle the request. This allows for the + // building of nested chains of controllers corresponding to a nested URL. + if(SiteTree::nested_urls() && $response instanceof HTTPResponse && $response->isError()) { + $SQL_URLParam = Convert::raw2sql($request->param('Action')); + + if($SQL_URLParam && $nextPage = DataObject::get_one('SiteTree', "\"ParentID\" = $this->ID AND \"URLSegment\" = '$SQL_URLParam'")) { + if($nextPage->canView()) { + $request->shiftAllParams(); + return ModelAsController::controller_for($nextPage)->handleRequest($request); + } + } + } + + return $response; + } + /** * @uses ErrorPage::response_for() * @return HTTPResponse diff --git a/core/control/HTTPRequest.php b/core/control/HTTPRequest.php old mode 100644 new mode 100755 index fb9fadb54..974361cc6 --- a/core/control/HTTPRequest.php +++ b/core/control/HTTPRequest.php @@ -381,6 +381,24 @@ class HTTPRequest extends Object implements ArrayAccess { function allParams() { return $this->allParams; } + + /** + * Shift all the parameter values down a key space, and return the shifted value. + * + * @return string + */ + public function shiftAllParams() { + $keys = array_keys($this->allParams); + $values = array_values($this->allParams); + $value = array_shift($values); + + foreach($keys as $position => $key) { + $this->allParams[$key] = isset($values[$position]) ? $values[$position] : null; + } + + return $value; + } + function latestParams() { return $this->latestParams; } diff --git a/tests/control/ContentControllerTest.php b/tests/control/ContentControllerTest.php new file mode 100755 index 000000000..071eef3af --- /dev/null +++ b/tests/control/ContentControllerTest.php @@ -0,0 +1,65 @@ +assertEquals('Home Page', $this->get('/')->getBody()); + $this->assertEquals('Home Page', $this->get('/home/index/')->getBody()); + $this->assertEquals('Home Page', $this->get('/home/second-index/')->getBody()); + + $this->assertEquals('Second Level Page', $this->get('/home/second-level/')->getBody()); + $this->assertEquals('Second Level Page', $this->get('/home/second-level/index/')->getBody()); + $this->assertEquals('Second Level Page', $this->get('/home/second-level/second-index/')->getBody()); + + $this->assertEquals('Third Level Page', $this->get('/home/second-level/third-level/')->getBody()); + $this->assertEquals('Third Level Page', $this->get('/home/second-level/third-level/index/')->getBody()); + $this->assertEquals('Third Level Page', $this->get('/home/second-level/third-level/second-index/')->getBody()); + + SiteTree::disable_nested_urls(); + + $this->assertEquals('Home Page', $this->get('/')->getBody()); + $this->assertEquals('Home Page', $this->get('/home/')->getBody()); + $this->assertEquals('Home Page', $this->get('/home/second-index/')->getBody()); + + $this->assertEquals('Second Level Page', $this->get('/second-level/')->getBody()); + $this->assertEquals('Second Level Page', $this->get('/second-level/index/')->getBody()); + $this->assertEquals('Second Level Page', $this->get('/second-level/second-index/')->getBody()); + + $this->assertEquals('Third Level Page', $this->get('/third-level/')->getBody()); + $this->assertEquals('Third Level Page', $this->get('/third-level/index/')->getBody()); + $this->assertEquals('Third Level Page', $this->get('/third-level/second-index/')->getBody()); + } + +} + +class ContentControllerTest_Page extends Page { + + public static $allowed_actions = array ( + 'second_index' + ); + +} + +class ContentControllerTest_Page_Controller extends Page_Controller { + + public function index() { + return $this->Title; + } + + public function second_index() { + return $this->index(); + } + +} \ No newline at end of file diff --git a/tests/control/ContentControllerTest.yml b/tests/control/ContentControllerTest.yml new file mode 100755 index 000000000..9166efa61 --- /dev/null +++ b/tests/control/ContentControllerTest.yml @@ -0,0 +1,16 @@ +ContentControllerTest_Page: + root_page: + Title: Home Page + URLSegment: home + second_level_page: + Title: Second Level Page + URLSegment: second-level + Parent: =>ContentControllerTest_Page.root_page + third_level_page: + Title: Third Level Page + URLSegment: third-level + Parent: =>ContentControllerTest_Page.second_level_page + third_level_page_2: + Title: Third Level Page Two + URLSegment: third-level-2 + Parent: =>ContentControllerTest_Page.second_level_page \ No newline at end of file