I created a module and there exists a default controller inside that. Now I can access the index action (default action) in the default controller like /mymodule/. For all other action i need to specify the controller id in the url like /mymodule/default/register/ . I would like to know is it possible to eliminate the controller id from url for the default controller in a module.
I need to set url rule like this:
before beautify : www.example.com/index.php?r=mymodule/default/action/
after beautify : www.example.com/mymodule/action/
Note: I want this to happen only for the default controller.
Thanks
This is a little tricky because the action part might be considered as a controller or you might be pointing to an existing controller. But you can get away with this by using a Custom URL Rule Class. Here's an example (I tested it and it seems to work well):
class CustomURLRule extends CBaseUrlRule
{
const MODULE = 'mymodule';
const DEFAULT_CONTROLLER = 'default';
public function parseUrl($manager, $request, $pathInfo, $rawPathInfo)
{
if (preg_match('%^(\w+)(/(\w+))?$%', $pathInfo, $matches)) {
// Make sure the url has 2 or more segments (e.g. mymodule/action)
// and the path is under our target module.
if (count($matches) != 4 || !isset($matches[1]) || !isset($matches[3]) || $matches[1] != self::MODULE)
return false;
// check first if the route already exists
if (($controller = Yii::app()->createController($pathInfo))) {
// Route exists, don't handle it since it is probably pointing to another controller
// besides the default.
return false;
} else {
// Route does not exist, return our new path using the default controller.
$path = $matches[1] . '/' . self::DEFAULT_CONTROLLER . '/' . $matches[3];
return $path;
}
}
return false;
}
public function createUrl($manager, $route, $params, $ampersand)
{
// #todo: implement
return false;
}
}
Related
Im using PHP MVC for my site and I have an issue with routing.
When I go to the index (front page), I use http://www.example.com or http://www.example.com/index.
When I go to the contact page, I use http://www.example.com/contact.
When I go to the services or about pages, I use http://www.example.com/content/page/services or http://www.example.com/content/page/about.
My index and contact pages have their own controllers because they are static pages. But the services and about pages are pulled from my db, thus dynamic. So I created a controller, named it content and just pass the parameters needed to get whatever page I want.
I want to make my URLs more consistent. If I go to the services or about pages, I want to use http://www.example.com/services or http://www.example.com/about.
How can I change my routing to meet this requirement? I ultimately would like to be able to create pages in my db, and then pull the page with a URL that looks like it has its own controller. Instead of having to call the content controller to get it to work.
Below are my controllers and what methods they contain, as well as my routing code.
Controllers:
IndexController
function: index
ContentController
function: page
function: sitemap
ContactController
function: index
function: process
Routing
class Application
{
// #var mixed Instance of the controller
private $controller;
// #var array URL parameters, will be passed to used controller-method
private $parameters = array();
// #var string Just the name of the controller, useful for checks inside the view ("where am I ?")
private $controller_name;
// #var string Just the name of the controller's method, useful for checks inside the view ("where am I ?")
private $action_name;
// Start the application, analyze URL elements, call according controller/method or relocate to fallback location
public function __construct()
{
// Create array with URL parts in $url
$this->splitUrl();
// Check for controller: no controller given ? then make controller = default controller (from config)
if (!$this->controller_name) {
$this->controller_name = Config::get('DEFAULT_CONTROLLER');
}
// Check for action: no action given ? then make action = default action (from config)
if (!$this->action_name OR (strlen($this->action_name) == 0)) {
$this->action_name = Config::get('DEFAULT_ACTION');
}
// Rename controller name to real controller class/file name ("index" to "IndexController")
$this->controller_name = ucwords($this->controller_name) . 'Controller';
// Check if controller exists
if (file_exists(Config::get('PATH_CONTROLLER') . $this->controller_name . '.php')) {
// Load file and create controller
// example: if controller would be "car", then this line would translate into: $this->car = new car();
require Config::get('PATH_CONTROLLER') . $this->controller_name . '.php';
$this->controller = new $this->controller_name();
// Check for method: does such a method exist in the controller?
if (method_exists($this->controller, $this->action_name)) {
if (!empty($this->parameters)) {
// Call the method and pass arguments to it
call_user_func_array(array($this->controller, $this->action_name), $this->parameters);
} else {
// If no parameters are given, just call the method without parameters, like $this->index->index();
$this->controller->{$this->action_name}();
}
} else {
header('location: ' . Config::get('URL') . 'error');
}
} else {
header('location: ' . Config::get('URL') . 'error');
}
}
// Split URL
private function splitUrl()
{
if (Request::get('url')) {
// Split URL
$url = trim(Request::get('url'), '/');
$url = filter_var($url, FILTER_SANITIZE_URL);
$url = explode('/', $url);
// Put URL parts into according properties
$this->controller_name = isset($url[0]) ? $url[0] : null;
$this->action_name = isset($url[1]) ? $url[1] : null;
// Remove controller name and action name from the split URL
unset($url[0], $url[1]);
// rebase array keys and store the URL parameters
$this->parameters = array_values($url);
}
}
}
In order to do this you should map your urls to controllers, check following example:
// route mapping 'route' => 'controller:method'
$routes = array(
'/service' => 'Content:service'
);
also controller can be any php callable function.
Answer Version 2:
Brother in the simplest mode, let's say you have an entity like below:
uri: varchar(255), title: varchar(255), meta_tags: varchar(500), body: text
and have access to StaticPageController from www.example.com/page/ url and what ever it comes after this url will pass to controller as uri parameter
public function StaticPageController($uri){
// this can return a page entity
// that contains what ever a page needs.
$page = $pageRepository->findByUri($uri)
// pass it to view layer
$this->renderView('static_page.phtml', array('page' => $page));
}
I hope this helps.
My current router / FrontController is setup to dissect URL's in the format:
http://localhost/controller/method/arg1/arg2/etc...
However, I'm not sure how to get certain requests to default to the IndexController so that I can type:
http://localhost/contact
or
http://localhost/about/portfolio
Instead of:
http://localhost/index/contact
or
http://localhost/index/about/portfolio
How is this accomplished?
<?php
namespace framework;
class FrontController {
const DEFAULT_CONTROLLER = 'framework\controllers\IndexController';
const DEFAULT_METHOD = 'index';
public $controller = self::DEFAULT_CONTROLLER;
public $method = self::DEFAULT_METHOD;
public $params = array();
public $model;
public $view;
function __construct() {
$this->model = new ModelFactory();
$this->view = new View();
}
// route request to the appropriate controller
public function route() {
// get request path
$basePath = trim(substr(PUBLIC_PATH, strlen($_SERVER['DOCUMENT_ROOT'])), '/') . '/';
$path = trim(parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH), '/');
if($basePath != '/' && strpos($path, $basePath) === 0) {
$path = substr($path, strlen($basePath));
}
// determine what action to take
#list($controller, $method, $params) = explode('/', $path, 3);
if(isset($controller, $method)) {
$obj = __NAMESPACE__ . '\\controllers\\' . ucfirst(strtolower($controller)) . 'Controller';
$interface = __NAMESPACE__ . '\\controllers\\' . 'InterfaceController';
// make sure a properly implemented controller and corresponding method exists
if(class_exists($obj) && method_exists($obj, $method) && in_array($interface, class_implements($obj))) {
$this->controller = $obj;
$this->method = $method;
if(isset($params)) {
$this->params = explode('/', $params);
}
}
}
// make sure we have the appropriate number of arguments
$args = new \ReflectionMethod($this->controller, $this->method);
$totalArgs = count($this->params);
if($totalArgs >= $args->getNumberOfRequiredParameters() && $totalArgs <= $args->getNumberOfParameters()) {
call_user_func_array(array(new $this->controller, $this->method), $this->params);
} else {
$this->view->load('404');
}
}
}
You can use your URLs by one of two methods:
Establish the controllers the way your routing defines them
example.com/contact => Have a "contact" controller with default or index action
example.com/about/portfolio => Have an "about" controller with a "portfolio" action
Because your currently available routing says your URL is treated like "/controller/method", there is no other way.
Establish dynamic routing to allow multiple URLs to be handled by a single controller
Obviously this needs a bit of configuration because one cannot know which URLs are valid and which one should be redirected to the generic controller, and which ones should not. This is somehow a replacement for any of the rewriting or redirecting solutions, but as it is handled on the PHP level, change might be easier to handle (some webserver configurations do not offer .htaccess because of performance reasons, and it generally is more effort to create these).
Your configuration input is:
The URL you want to be handled and
The controller you want the URL passed to, and it's action.
You'll end up having an array structure like this:
$specialRoutes = array(
"/contact" => "IndexController::indexAction",
"/about/portfolio" => "IndexController::indexAction"
);
What's missing is that this action should get the current URL passed as a parameter, or that the path parts become designated parameters within your URL schema.
All in all this approach is a lot harder to code. To get an idea, try to look at the routing of common MVC frameworks, like Symfony and Zend Framework. They offer highly configurable routing, and because of this, the routing takes place in multiple classes. The main router only reads the configuration and then passes the routing of any URL to the configured routers if a match is detected.
Based on your code snippet I'd do it like this (pseudo php code):
$handler = get_controller($controller);
if(!$handler && ($alias = lookup_alias($path))) {
list($handler, $method) = $alias;
}
if(!$handler) error_404();
function lookup_alias($path) {
foreach(ALL_CONTROLLERS as $controller) {
if(($alias = $controller->get_alias($path))) {
return $alias;
}
}
return null;
}
So basically in case there is no controller to handle a certain location you check if any controller is configured to handle the given path as an alias and if yes return that controller and the method it maps to.
You can create a rewrite in your webserver for these exceptions. For example:
RewriteRule ^contact$ /index/contact
RewriteRule ^about/portfolio$ /about/portfolio
This will allow you to have simplified URLs that map to your regular structure.
You could have a dynamic rule if you are able to precisely define what should be rewritten to /index. For example:
RewriteRule ^([a-z]+)$ /index/$1
Try this dynamic htaccess rewrite rule:
RewriteRule ^(.+)/?$ /index/$1 [QSA]
The QSA flag in the above rule allows you to also add a query string to the end if you want, like this:
http://localhost/contact?arg1=1&arg2=2
EDIT: This rule would also handle cases such as /about/portfolio:
RewriteRule ^(.+)/?(.+)?$ /index/$1 [QSA]
I've literally downloaded Laravel today and like the looks of things but i'm struggeling on 2 things.
1) I like the controllers' actions method of analysing urls instead of using routes, it seems to keep everything together more cleanly, but lets say I want to go to
/account/account-year/
how can I write an action function for this? i.e.
function action_account-year()...
is obviously not valid syntax.
2) If i had
function action_account_year( $year, $month ) { ...
and visited
/account/account_year/
An error would be displayed about missing arguments, how do you go about making this user friendly/load diff page/display an error??
You would have to manually route the hyphenated version, e.g.
Route::get('account/account-year', 'account#account_year');
Regarding the parameters, it depends on how you are routing. You must accept the parameters in the route. If you are using full controller routing (e.g. Route::controller('account')) then the method will be passed parameters automatically.
If you are manually routing, you have to capture the params,
Route::get('account/account-year/(:num)/(:num)', 'account#account_year');
So visiting /account/account-year/1/2 would do ->account_year(1, 2)
Hope this helps.
You can think of the following possibility as well
class AccountController extends BaseController {
public function getIndex()
{
//
}
public function getAccountYear()
{
//
}
}
Now simply define a RESTful controller in your routes file in the following manner
Route::controller('account', 'AccountController');
Visiting 'account/account-year' will automatically route to the action getAccountYear
I thought I'd add this as an answer in case anyone else is looking for it:
1)
public function action_account_year($name = false, $place = false ) {
if( ... ) {
return View::make('page.error' );
}
}
2)
not a solid solutions yet:
laravel/routing/controller.php, method "response"
public function response($method, $parameters = array())
{
// The developer may mark the controller as being "RESTful" which
// indicates that the controller actions are prefixed with the
// HTTP verb they respond to rather than the word "action".
$method = preg_replace( "#\-+#", "_", $method );
if ($this->restful)
{
$action = strtolower(Request::method()).'_'.$method;
}
else
{
$action = "action_{$method}";
}
$response = call_user_func_array(array($this, $action), $parameters);
// If the controller has specified a layout view the response
// returned by the controller method will be bound to that
// view and the layout will be considered the response.
if (is_null($response) and ! is_null($this->layout))
{
$response = $this->layout;
}
return $response;
}
I'm working on an (oh no, not another) MVC framework in PHP, primarily for education, but also fun and profit.
Anyways, I'm having some trouble with my Router, specifically routing to the correct paths, with the correct parameters. Right now, I'm looking at a router that (using __autoload()) allows for arbitrarily long routing paths:
"path/to/controller/action"
"also/a/path/to/a/controller/action"
Routing starts at the application directory, and the routing path is essentially parallel with the file system path:
"/framework/application/path/to/controller.class.php" => "action()"
class Path_To_Controller{
public function action(){}
}
"/framework/application/also/a/path/to/a/controller.class.php" => "action()"
class Also_A_Path_To_A_Controller{
public function action(){}
}
This will allow for module configuration files to be available at varying levels of the application file system. The problem is of course, when we introduce routing path parameters, it becomes difficult differentiating where the routing path ends and the path parameters begin:
"path/to/controller/action/key1/param1/key2/param2"
Will obviously be looking for the file:
"/framework/application/path/to/controller/action/key1/param1/key2.class.php"
=> 'param2()'
//no class or method by this name can be found
This ain't good. Now this smells like a design issue of course, but I'm certain there must be a clean way to circumvent this problem.
My initial thoughts were to test each level of the routing path for directory/file existence.
If it hits 1+ directories followed by a file, additional path components are an action followed by parameters.
If it hits 1+ directories and no file is found, 404 it.
However, this is still susceptible to erroneously finding files. Sure this can be alleviated by stricter naming conventions and reserving certain words, but I'd like to avoid that if possible.
I don't know if this is the best approach. Has anyone solved such an issue in an elegant manner?
Well, to answer my own question with my own suggestion:
// split routePath and set base path
$routeParts = explode('/', $routePath);
$classPath = 'Flooid/Application';
do{
// append part to path and check if file exists
$classPath .= '/' . array_shift($routeParts);
if(is_file(FLOOID_PATH_BASE . '/' . $classPath . '.class.php')){
// transform to class name and check if method exists
$className = str_replace('/', '_', $classPath);
if(method_exists($className, $action = array_shift($routeParts))){
// build param key => value array
do{
$routeParams[current($routeParts)] = next($routeParts);
}while(next($routeParts));
// controller instance with params passed to __construct and break
$controller = new $className($routeParams);
break;
}
}
}while(!empty($routeParts));
// if controller exists call action else 404
if(isset($controller)){
$controller->{$action}();
}else{
throw new Flooid_System_ResponseException(404);
}
My autoloader is about as basic as it gets:
function __autoload($className){
require_once FLOOID_PATH_BASE . '/' . str_replace('_', '/', $className) . '.class.php';
}
This works, surprisingly well. I've yet to implement certain checks, like ensuring that the requested controller in fact extends from my Flooid_System_ControllerAbstract, but for the time being, this is what I'm running with.
Regardless, I feel this approach could benefit from critique, if not a full blown overhaul.
I've since revised this approach, though it ultimately performs the same functionality. Instead of instantiating the controller, it passes back the controller class name, method name, and parameter array. The guts of it all are in getVerifiedRouteData(), verifyRouteParts() and createParamArray(). I'm thinking I want to refactor or revamp this class though. I'm looking for insight on where I can optimize readability and usability.:
class Flooid_Core_Router {
protected $_routeTable = array();
public function getRouteTable() {
return !empty($this->_routeTable)
? $this->_routeTable
: null;
}
public function setRouteTable(Array $routeTable, $mergeTables = true) {
$this->_routeTable = $mergeTables
? array_merge($this->_routeTable, $routeTable)
: $routeTable;
return $this;
}
public function getRouteRule($routeFrom) {
return isset($this->_routeTable[$routeFrom])
? $this->_routeTable[$routeFrom]
: null;
}
public function setRouteRule($routeFrom, $routeTo, Array $routeParams = null) {
$this->_routeTable[$routeFrom] = is_null($routeParams)
? $routeTo
: array($routeTo, $routeParams);
return $this;
}
public function unsetRouteRule($routeFrom) {
if(isset($this->_routeTable[$routeFrom])){
unset($this->_routeTable[$routeFrom]);
}
return $this;
}
public function getResolvedRoutePath($routePath, $strict = false) {
// iterate table
foreach($this->_routeTable as $routeFrom => $routeData){
// if advanced rule
if(is_array($routeData)){
// build rule
list($routeTo, $routeParams) = each($routeData);
foreach($routeParams as $paramName => $paramRule){
$routeFrom = str_replace("{{$paramName}}", "(?<{$paramName}>{$paramRule})", $routeFrom);
}
// if !advanced rule
}else{
// set rule
$routeTo = $routeData;
}
// if path matches rule
if(preg_match("#^{$routeFrom}$#Di", $routePath, $paramMatch)){
// check for and iterate rule param matches
if(is_array($paramMatch)){
foreach($paramMatch as $paramKey => $paramValue){
$routeTo = str_replace("{{$paramName}}", $paramValue, $routeTo);
}
}
// return resolved path
return $routeTo;
}
}
// if !strict return original path
return !$strict
? $routePath
: false;
}
public function createParamArray(Array $routeParts) {
$params = array();
if(!empty($routeParts)){
// iterate indexed array, use odd elements as keys
do{
$params[current($routeParts)] = next($routeParts);
}while(next($routeParts));
}
return $params;
}
public function verifyRouteParts($className, $methodName) {
if(!is_subclass_of($className, 'Flooid_Core_Controller_Abstract')){
return false;
}
if(!method_exists($className, $methodName)){
return false;
}
return true;
}
public function getVerfiedRouteData($routePath) {
$classParts = $routeParts = explode('/', $routePath);
// iterate class parts
do{
// get parts
$classPath = 'Flooid/Application/' . implode('/', $classParts);
$className = str_replace('/', '_', $classPath);
$methodName = isset($routeParts[count($classParts)]);
// if verified parts
if(is_file(FLOOID_PATH_BASE . '/' . $classPath . '.class.php') && $this->verifyRouteParts($className, $methodName)){
// return data array on verified
return array(
'className'
=> $className,
'methodName'
=> $methodName,
'params'
=> $this->createParamArray(array_slice($routeParts, count($classParts) + 1)),
);
}
// if !verified parts, slide back class/method/params
$classParts = array_slice($classParts, 0, count($classParts) - 1);
}while(!empty($classParts));
// return false on not verified
return false;
}
}
This situation arises from someone wanting to create their own "pages" in their web site without having to get into creating the corresponding actions.
So say they have a URL like mysite.com/index/books... they want to be able to create mysite.com/index/booksmore or mysite.com/index/pancakes but not have to create any actions in the index controller. They (a non-technical person who can do simple html) basically want to create a simple, static page without having to use an action.
Like there would be some generic action in the index controller that handles requests for a non-existent action. How do you do this or is it even possible?
edit: One problem with using __call is the lack of a view file. The lack of an action becomes moot but now you have to deal with the missing view file. The framework will throw an exception if it cannot find one (though if there were a way to get it to redirect to a 404 on a missing view file __call would be doable.)
Using the magic __call method works fine, all you have to do is check if the view file exists and throw the right exception (or do enything else) if not.
public function __call($methodName, $params)
{
// An action method is called
if ('Action' == substr($methodName, -6)) {
$action = substr($methodName, 0, -6);
// We want to render scripts in the index directory, right?
$script = 'index/' . $action . '.' . $this->viewSuffix;
// Script file does not exist, throw exception that will render /error/error.phtml in 404 context
if (false === $this->view->getScriptPath($script)) {
require_once 'Zend/Controller/Action/Exception.php';
throw new Zend_Controller_Action_Exception(
sprintf('Page "%s" does not exist.', $action), 404);
}
$this->renderScript($script);
}
// no action is called? Let the parent __call handle things.
else {
parent::__call($methodName, $params);
}
}
You have to play with the router
http://framework.zend.com/manual/en/zend.controller.router.html
I think you can specify a wildcard to catch every action on a specific module (the default one to reduce the url) and define an action that will take care of render the view according to the url (or even action called)
new Zend_Controller_Router_Route('index/*',
array('controller' => 'index', 'action' => 'custom', 'module'=>'index')
in you customAction function just retrieve the params and display the right block.
I haven't tried so you might have to hack the code a little bit
If you want to use gabriel1836's _call() method you should be able to disable the layout and view and then render whatever you want.
$this->_helper->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender(true);
I needed to have existing module/controller/actions working as normal in a Zend Framework app, but then have a catchall route that sent anything unknown to a PageController that could pick user specified urls out of a database table and display the page. I didn't want to have a controller name in front of the user specified urls. I wanted /my/custom/url not /page/my/custom/url to go via the PageController. So none of the above solutions worked for me.
I ended up extending Zend_Controller_Router_Route_Module: using almost all the default behaviour, and just tweaking the controller name a little so if the controller file exists, we route to it as normal. If it does not exist then the url must be a weird custom one, so it gets sent to the PageController with the whole url intact as a parameter.
class UDC_Controller_Router_Route_Catchall extends Zend_Controller_Router_Route_Module
{
private $_catchallController = 'page';
private $_catchallAction = 'index';
private $_paramName = 'name';
//-------------------------------------------------------------------------
/*! \brief takes most of the default behaviour from Zend_Controller_Router_Route_Module
with the following changes:
- if the path includes a valid module, then use it
- if the path includes a valid controller (file_exists) then use that
- otherwise use the catchall
*/
public function match($path, $partial = false)
{
$this->_setRequestKeys();
$values = array();
$params = array();
if (!$partial) {
$path = trim($path, self::URI_DELIMITER);
} else {
$matchedPath = $path;
}
if ($path != '') {
$path = explode(self::URI_DELIMITER, $path);
if ($this->_dispatcher && $this->_dispatcher->isValidModule($path[0])) {
$values[$this->_moduleKey] = array_shift($path);
$this->_moduleValid = true;
}
if (count($path) && !empty($path[0])) {
$module = $this->_moduleValid ? $values[$this->_moduleKey] : $this->_defaults[$this->_moduleKey];
$file = $this->_dispatcher->getControllerDirectory( $module ) . '/' . $this->_dispatcher->formatControllerName( $path[0] ) . '.php';
if (file_exists( $file ))
{
$values[$this->_controllerKey] = array_shift($path);
}
else
{
$values[$this->_controllerKey] = $this->_catchallController;
$values[$this->_actionKey] = $this->_catchallAction;
$params[$this->_paramName] = join( self::URI_DELIMITER, $path );
$path = array();
}
}
if (count($path) && !empty($path[0])) {
$values[$this->_actionKey] = array_shift($path);
}
if ($numSegs = count($path)) {
for ($i = 0; $i < $numSegs; $i = $i + 2) {
$key = urldecode($path[$i]);
$val = isset($path[$i + 1]) ? urldecode($path[$i + 1]) : null;
$params[$key] = (isset($params[$key]) ? (array_merge((array) $params[$key], array($val))): $val);
}
}
}
if ($partial) {
$this->setMatchedPath($matchedPath);
}
$this->_values = $values + $params;
return $this->_values + $this->_defaults;
}
}
So my MemberController will work fine as /member/login, /member/preferences etc, and other controllers can be added at will. The ErrorController is still needed: it catches invalid actions on existing controllers.
I implemented a catch-all by overriding the dispatch method and handling the exception that is thrown when the action is not found:
public function dispatch($action)
{
try {
parent::dispatch($action);
}
catch (Zend_Controller_Action_Exception $e) {
$uristub = $this->getRequest()->getActionName();
$this->getRequest()->setActionName('index');
$this->getRequest()->setParam('uristub', $uristub);
parent::dispatch('indexAction');
}
}
You could use the magic __call() function. For example:
public function __call($name, $arguments)
{
// Render Simple HTML View
}
stunti's suggestion was the way I went with this. My particular solution is as follows (this uses indexAction() of whichever controller you specify. In my case every action was using indexAction and pulling content from a database based on the url):
Get an instance of the router (everything is in your bootstrap file, btw):
$router = $frontController->getRouter();
Create the custom route:
$router->addRoute('controllername', new Zend_Controller_Router_Route('controllername/*', array('controller'=>'controllername')));
Pass the new route to the front controller:
$frontController->setRouter($router);
I did not go with gabriel's __call method (which does work for missing methods as long as you don't need a view file) because that still throws an error about the missing corresponding view file.
For future reference, building on gabriel1836 & ejunker's thoughts, I dug up an option that gets more to the point (and upholds the MVC paradigm). Besides, it makes more sense to read "use specialized view" than "don't use any view".
// 1. Catch & process overloaded actions.
public function __call($name, $arguments)
{
// 2. Provide an appropriate renderer.
$this->_helper->viewRenderer->setRender('overload');
// 3. Bonus: give your view script a clue about what "action" was requested.
$this->view->action = $this->getFrontController()->getRequest()->getActionName();
}
#Steve as above - your solution sounds ideal for me but I am unsure how you implmeented it in the bootstrap?