Works very well and is quite flexible. However, as you get deeper URL's the controller classes bloat. Say the URL
Code: Select all
mysite/users/
maps to the controller users with some default action
mysite/users/1/
maps to the controller users with the action to view userpage for user 1
mysite/users/1/stuff
maps to the controller users with the action to view userpage for user 1 and subcontroller stuff
mysite/users/1/stuff/edit
maps to the controller users with the action to view userpage for user 1 and subcontroller stuff, subaction editWhat I would like to have is suggestions is how to handle the bloat and hierarchical coupling which starts to creep in the controllers by doing it this way. My guess is that I should look into some sort of Chain of Responsibility. Or the way Konstruct handles controllers (at least, from what I understand from a bit of reading).
I need some way to have each controller be more or less independent of the complete chain. Each controller can run several actions, or dispatch to other controllers. Those controllers can again run actions or dispatch to others, etc. All the time, each controller has access to the request object, so it knows what to do. And each controller in the chain returns a response.
The thing is, I don't want to be limited to a single pair of controller/action. I might have
Code: Select all
/admin/users/
which maps to controller admin and action users
/admin/users/edit/
mapping to controller admin and action users and subaction edit
/news/
mapping to controller news
/news/2006/
mapping to controller news and parameter year=2006One controller runs an action directly. Another controller dispatches to another, which dispatches to another just as long until the right one runs an action
below a simplified example of what I mean:
Frontcontroller:
Code: Select all
require_once('config.php');
require_once('A/DL.php');
require_once('A/Locator.php');
require_once('A/Http/Request.php');
require_once 'A/Http/PathInfo.php';
require_once('A/Http/Response.php');
require_once('A/Controller/Front.php');
require_once('A/Controller/Mapper.php');
$Locator =& new A_Locator();
$Response =& new A_Http_Response();
$Locator->set('Request', new A_Http_Request());
$Locator->set('Response', $Response);
$map = array(
'' => array(
'controller',
'action',
'id',
),
'date' => array(
'' => array(
'controller',
'year',
'month',
3 => 'day',
),
),
'users' => array(
'' => array(
'controller',
'id',
'subcontroller',
'subaction'
)
)
);
$map2 = array(
'' => array(
),
'param1' => array(
'' => array(
'subcontroller',
'subaction',
'subparam',
),
),
);
$Request = new A_Http_Request();
// set first map and process
$Mapper = new A_Http_PathInfo($map, false);
$Mapper->run($Request);
// set second map and process to map those routes
$Mapper->setMap($map2);
$Mapper->run($Request);
$DefaultAction = new A_DL('', 'home', 'run');
$ErrorAction = new A_DL('', 'error', 'run');
$Mapper = new A_Controller_Mapper('controller/', $DefaultAction);
$Controller = new A_Controller_Front($Mapper, $ErrorAction);
$Controller->run($Locator);
$Response->out();Controller class:
Code: Select all
class users {
function run($locator) {
$request = $locator->get('Request');
$response = $locator->get('Response');
// URI /users/1/
if($request->get('id')) {
// URL / users/1/climbs/
if($request->get('subcontroller') == 'climbs') {
// URL /users/1/climbs/add/
if($request->get('subaction') == 'add') {
$content = $this->addNewClimb();
$response->setContent($content);
// URL /users/1/climbs/view/
} elseif ($request->get('subaction') == 'view') {
$content = $this->showClimbsByUserView();
$response->setContent($content);
} else {
$content = $this->showClimbsByUser();
$response->setContent($content);
}
} else {
$content = $this->showUserById();
$response->setContent($content);
}
}
else {
$url = 'http://mysite.com/users/1/someotheraction/';
$response = $locator->get('Response');
$response->setRedirect($url);
}
}
function addNewClimb() {}
function showClimbsByUserView() {}
// other functions ....
}Code: Select all
class users {
function run($locator) {
$request = $locator->get('Request');
$response = $locator->get('Response');
// URI /users/1/
if($request->get('id')) {
$dispatchedresponse = new SomeSubcontroller();
$content = $dispatchedresponse->getContent();
} else {
$dispatchedresponse = new SomeOtherSubcontroller();
$content = $dispatchedresponse->getContent();
}
$response->setContent($content);
//etc etc
}
class SomeSubcontroller {
function run($locator) {
$request = $locator->get('Request');
$response = $locator->get('Response');
// URI /users/1/view/
if($request->get('subcontroller')) {
$dispatchedresponse = new SomeSubSubcontroller();
$content = $dispatchedresponse->getContent();
} else {
$dispatchedresponse = new SomeOtherSubSubcontroller();
$content = $dispatchedresponse->getContent();
}
$response->setContent($content);
//etc etc
}Basicly my question is: is this the right way to match the mapping to the controllers, actions, subcontrollers, subactions, etc?