Framework design: why no $layoutPath on controllers?

I was recently inspecting Yii framework code (specifically, the View-related pipeline) for research purposes.

[size="2"]If anyone is curious, I am exploring options for a unified "action result" interface – there are lots of helpers if you want to output HTML, but it would be nice if you could also do JSON, XML, etc using one and the same interface (similar to what ASP.NET MVC is doing with ActionResult).[/size]

My question is: why is there no $layoutPath on controllers like there is on CWebApplication and CWebModule? Especially since CController does have a $viewPath property. Am I missing something, or is it simply because there’s no real need?

Thanks in advance.

i think you can achieve similar effect with themes in Yii - just create theme named “json” and put views rendering json there. then you can switch html <-> json with setting theme to empty/‘standard’ or ‘json’

Thanks for the suggestion. In fact with JSON the thing is that you probably want to pass in an object that will get serialized, so just one view would be enough (render ‘//json’). What I do not like is the fact that you still call something named render() even if your view is made to e.g. serve a download. In any case I don’t have a problem to solve, rather a question to find the answer to.

I understand and I am also interested in where this discussion could go :)

just provided first possible solution I thought about. There is one more thing in ‘themes’ approach - with this you can overload ANY view, not only layouts. You can also in such view disable layout, so this solution would work.

Another possibility is to use ‘language’ - if you set Yii::app()->language = ‘json’ then render( ‘view’ ) will first look for view file in /views/[controller id]/[language]/[view name].php so in this case: /views/controller/json/view.php. But overloading language attribute can be tricky and lead to side effects…

Just for fun, here’s an idea of what I 'm playing with:




function actionFoo() {

    return $this->result->html()->view('/debug/foo')->data(array('x' => 42))->layout('blah');


    // or...

    return $this->result->json()->data(array('name' => 'PJ'));


    // I might want to support this syntax as well, although it requires reflection to work

    // and as such I 'm not sure if it would be appropriate for Yii (need to benchmark though)

    return $this->result->json(array('name' => 'PJ'));


    // another option

    return $this->result->redirect('home/index');

}



Main benefits:

  • consistent syntax for everything

  • extensible (each type of result corresponds to a class, extend or provide your own)

  • short (most of the time it’s an one-liner)

$this->result is an object (let’s call it “coordinator”) that has three responsibilities:

1. Create the actual result object

Result objects are instances of classes such as HtmlResult, JsonResult etc; they all extend abstract class ActionResult. The coordinator uses an override of __call to map the ->html() call to a new HtmlResult instance.

2. Assign properties on the result object

Calls such as ->data(), ->layout() and such all go through coordinator’s __call (which returns $this to allow chaining). They check that the result object has settable properties with the same name and set their values.

Generally Yii chooses not to do things this way and instead accept arrays for configuring components. However, in this specific case arrays are not ideal because you would typically set just a couple properties on the result and IMHO for such low volumes the array syntax is way more cumbersome.

3. Provide the result object back to the controller

The coordinator keeps a reference to the result object and also interfaces with the controller so that the result can be acted upon.