I needed to call another controller’s action and that seemed to be a problem using yii. I heard that this ability is somehow linked with hmvc (don’t know how though).
So I wrote a little function which implements this functionality and placed it in the Controller class:
private $_action;
public function useAction($route,$controller=NULL)
{
ob_start();
if(empty($controller)){
// ## this is almost CWebApp::runController
if(($ca=Yii::app()->createController($route))!==null){
list($controller,$actionID)=$ca;
$controller -> init();
$controller -> _action = $actionID;
$controller -> run($actionID);
unset($controller);
}else{
throw new Exception('Dont know this controller: '.$route);
}
}else{
$oldaction = $controller -> _action;
$controller -> _action = $actionID;
$controller -> run($route);
$controller -> _action = $oldaction;
}
return ob_get_clean();
}
Your solution looks more like a “hack” to me. And I don’t like hacks
There are more "clear" ways to do it, e.g. create an action class, use CController.forward() method, create a base class for controllers, or simply redirect.
If none of this ways suits you, then there is probably a design mistake (IMHO of course).
-your get variable would be the same in the controller you are calling, and that may cause unexpected behaviors
its not using curlmanager
to fix you could do something like:
public static function runModule($uri,$args=array()){
$olduri=$_SERVER['REQUEST_URI'];
//clean up the get variable and save the old content
$oldget=$_GET;
$_GET=array();
//parse the url using url manager
$_SERVER['REQUEST_URI']="/".$uri;
$urlManager=Yii::app()->getUrlManager();
$url=$urlManager->parseUrl(new CHttpRequest());
//set the get variables
if(is_array($args) && count($args)>0){
foreach($args as $k=>$v)
@$get="{$k}/{$v}/";
$urlManager->parsePathInfo(trim($get,"/"));
}
ob_start();
ob_implicit_flush(false);
Yii::app()->runController($url)
$_GET=$oldget;
$_SERVER['REQUEST_URI']=$olduri;
return ob_get_clean();
}
-the right place to post would be under tips , snippets & tutorials
anyway, you are not necessarily wrong doing something like that ( zend has a built-in method to do it )
Redirecting is not it. The Controller::forward method is almost redirecting. Don’t see how creating an action class would help.
And yes, I surely placed this function in Controller base class (the one that is automatically created with application in the components directory).
Gustavo
Thanks! I would place it under tips but I don’t have enough rating. Also I’d prefer first to discuss it.
Didn’t think about CUrlManager and $_GET at all. That’s very intresting.
Abstract
The reason I needed this function is to build a page using several actions. Each action displays a part of the page and sometimes I needed to call actions from external Controllers. Also I was building something like a CMS where needed actions where called depending on the data in DB. Layouts are just not enough.
Also I am confused about possible creation of one controller several times. I suppose there should be a private array of all created controllers and before creating another one we should check if he exists.
If you keep with the fat models, lean controllers rule, then just call the model code from any controller, and use intelligent widgets for the presentation.
You could couple that with components, and get an even more flexible solution.
Whole page is not a "logical part". An action renders a view with a layout. Or you will use renderPartial() in each action? A logical part which you can share between different pages = widget.
In my little cms I stored info about which logical part should a page have in DB and created a AR class (I called it a Block) which called actions from different controllers. Each Block represented some action specially marked in phpdoc style.
I suppose that Block is close to the widget here.
Though if I use widgets instead - why would I need controllers then?
The filter thing is pretty nice also.
jacmoe
Why not use only one controller in every app then?
The reason why I started the topic was to find out - what’s so dirty about this stuff?
andy_s
You’re right. While building the page: renderPartial() every time and render() - only once per page.
Gustavo
Speaking of ajax: I heard of ideas even creating javascript views. So that the web server would only return pure data (in json I suppose) and javascript would render it. No need in php then. But this way requires a very strong js framework. Ahh, f man can always dream…
Just using ajax is not so hard but why not try building pages the hmvc way?
It’s up to you to learn and discover how to apply MVC on your project.
The reason why I suggested using widgets is that they are essentially a mini-controller with a view.
And they’re are meant to be small, well-defined and reusable.
The structure of your application will decide how many controllers you need. IMO.
Just think about the urls you need for your application - site/[<module>]controller/action/parameters - and you get a pretty good picture of how many controllers you need.
Grouped by functionality/responsibility.
Sometimes, you only need one controller. Nothing wrong with that. Depends on your use case.
But the main deciding factor on your design is of course your database schema. But that is another topic, really.