best way to have two controllers render views in one layout?

hello - new on the forum, and also to the Yii framework. like it so far though!

what I am trying to do might be weird, but, it makes sense with the app I’m building: instead of rendering just a single $content into a layout, each page has two “panels” of content: a $rightcontent and a $leftcontent. I would like to generate the $rightcontent with one controller, and the $leftcontent with another controller. what would be the best way to do this?

I’ve had a few thoughts so far:

  • somehow override the default request handling so that ?r=leftcontroller/rightcontroller calls two controllers and renders the indexAction view of both into the layout file

  • route everything through one controller (siteController maybe), and simply render two Widgets (ignoring the regular $content)

(if this will work, how much can a widget be associated with a controller? CWidgets have "controller" and "owner" properties which refer to Controllers… what do these do?)

  • pass in to 1st controller’s action the name of the 2nd controller, have it call an action in the 2nd controller with a partialRender() output, and then pass the content from the 2nd controller back into the regular render() function in the 1st controller’s action

any thoughts? I’m sort of new to this whole MVC thing anyway, so perhaps I’m overlooking a simple solution.

thanks!

I am also new, but based on my understanding of the blog test application, MVC, and the use of widgets, I would think that your second option (ie. one controller, with seperate widgets placed via html/css in the different areas of your layout).

Each widget can have independant business logic, data access and display.

This would be inline with each page having core content (ie. it might be your rightcolumn), with interchanged secondary content via a combination of one/many widgets.

If it’s only for the multi column layout, check this cookbook article:

http://www.yiiframework.com/doc/cookbook/28/

thanks for the tips, but I actually ended up extending the Controller model with a different render() function (a variation on my 3rd option). when render() is called it looks up a session variable to see what the $leftpanel should contain, then renders that in the $leftpanel and renders the normal content in the $rightpanel. it works slick!

the reasons why I would want to do this might not be obvious, but when the app is done I’ll post about it and all will be made clear.

I have to say though, considering the non-traditional UI my app needs I’ve been pleased with how (relatively) easy it has to make it happen in Yii - even for a noob!

thanks again

would you share your solution?

I have encountered the same problem, but i want to render six small views into my baselayout.

At the moment, my solution looks like this:




<?php $SC = new SiteController('site'); ?>


<? if(Yii::app()->user->isGuest): ?>

<div id="headerleft"> <?php $SC->actionShowPartial(1); ?></div>

<div id="headercenter"> <?php $SC->actionShowPartial(2); ?></div>

<div id="headerright"><?php  $SC->actionShowPartial(3); ?></div>

<div id="menu">Menu Navigation</div>

<div id="footerleft"><?php $SC->actionShowPartial(4); ?></div>

<div id="footercontent"><?php $SC->actionShowPartial(5); ?></div>

<div id="footerright"><?php $SC->actionShowPartial(6); ?></div>

<? endif; ?>



I just added this function actionShowPartial to my SiteController:




 public function actionShowPartial($id)

  {

    $_GET['id'] = $id;

    $this->renderPartial('show',array('model'=>$this->loadSite($id)));

  }




The css that produces my 6 fields looks like this:




#headerleft {

  background: #FF9900;

  position: absolute;

  top: 0px;

  left: 0px;

  width: 300px;

  height: 250px;

}

#headercenter {

  background: #FF9900;

  position: absolute;

  top: 0px;

  left: 300px;

  width: 300px;

  height: 250px;

}

#headerright {

  background: #FF9900;

  position: absolute;

  top: 0px;

  left: 600px;

  width: 300px;

  height: 250px;

}

#menu {

  background: #FF9900;

  position: absolute;

  top: 250px;

  left: 0px;

  width: 900px;

  height: 50px;

}


#footerleft {

  background: #FF9900;

  position: absolute;

  top: 300px;

  left: 0px;

  width: 300px;

  height: 300px;

}

#footercontent {

  background: #FF9900;

  position: absolute;

  top: 300px;

  left: 300px;

  width: 300px;

  height: 300px;

}

#footerright {

  background: #FF9900;

  position: absolute;

  top: 300px;

  left: 600px;

  width: 300px;

  height: 300px;

}



I would like to see your Solution to this, i am not really happy with mine, cause $content is not used, and i have problems drawing my Back-End when a User logs in.

I have another Solution for this:

I need to build a page, that offers three layout-modes:

1.) Default Layout-Mode: my SiteController renders 6 views, like shown in my prevous Post

2.) Enhanced Layout-Mode: my Sitecontroller renders 12 tiny views

3.) Backend Mode: Only 1 Big View for the admin

Does it make sense to define an Trigger in the Application (like Yii::app()->layoutMode), and including another css file, depending on the Mode?

if(Yii::app()->layoutMode == "default") include "layout_standard.css"; echo $contentdefault;

if(Yii::app()->layoutMode == "default_huge") include "layout_huge.css"; echo $contenthuge;

if(Yii::app()->layoutMode == "admin") include "layout_admin.css"; echo $contentadmin;

The mode could be toggled by any Controller.

Or is there an other, more yii-ish, elegant way to solve this "Problem"?

Maybe we could include something like an "layout Manager" in the >1.1 version of yii?

Hey, I just posted something similar. I was looking for a way to call multiple controller actions and render multiple views. I have worked out ways to do this via widgets and actions shared between controllers. Please take a look at my post, in particular reply #4.

@thyseus

I am no longer attempting to do this. It was an attempt to do was a “visual history” where the new controller’s view would load up in the right side of the layout, and the previously visited panel would load up in the left side. So the “new” page was always on the right, and the “old” page was always on the left. Two “pages” in a single view.

It did this by pushing the request URI (and GET/POST params) to a session variable on each new request. An overridden Render method then looked at the history stack each time and called a renderPartial on the top item, and basically concatenated it with the original $content the Render method is supposed to return. So a single $content chunk was spit out to the layout, but it actually contained two views (held together with a couple additional Divs).

It worked slick for simple cases, but I wanted it to work so that if a link in the Left side was clicked the Right side was replaced, and if a link in the Right side was clicked the Right side would become the Left and the new content would load in Right side. It got confusing, to say the least. The difficulty of determining which side a link or form submit was coming from not worth it and I gave up. Plus there was uncertainty about how the new Render method should handle requests when there was nothing on the history stack… a default page? Render in a wide single column?

The project has reverted to a much more traditional MVC structure. :)

But good luck! And if anyone thinks my code might be useful I can post it but it seems a little different from what anyone else is trying.

Never heard anything like that before @thaddeusmt. Bet it would have been cool. I can see how it could get complicated though…