Need someone to explain design strategies

Hi, I’m relatively new to MVC designs in general and I’m having some issues trying to figure out the best/most appropriate way of accomplishing things. I’d greatly appreciate any feedback on strategies. I’ll detail a few I’ve tried so far.

So, I’m getting started on my first project with Yii (a polling site). I started with a nice little relational database, used the yiic shell command to model and crud some basic stuff. I made sure my relations worked right so I could link the poll to the choices, votes and users. This part I get, but it’s easier because it’s focused on the poll model and it’s relationships, and it’s all driven by the PollController.

What I’m trying to do now is put multiple views together (ie. for the home page). I want a list of polls as well as some other views, such as a subject list. One of my questions is what exactly drives this. Obviously, it’s the index action of the site controller. But does this mean that I have collect all my data from various models within this controller? This is where I’m hung up. If I have a view I want to use, the data for that view is in a specific method of a controller. I can call any view from any controller, but I can’t pass it the right data unless the same logic that’s in the right controller is also in the site controller. This just seems crazy to me, so I’m sure I’m doing it wrong.

Here’s what I have just done for my homepage. I have a list of Subjects and a list of Polls. I built a widget for the subjects and just call the view for the polls.

SiteController > actionIndex()




public function actionIndex()

{

	$polls=Poll::model()->findAll();

	$this->render('index', array('models'=>$polls));

}



views/site/index.php




        $this->widget('application.components.SubjectTree');

	$this->renderPartial('/issue/listbox', array('models'=>$models));



components/SubjectTree.php




class SubjectTree extends CTreeView

{

	public function init()

	{

		$subjectList=Subject::model()->findAllByAttributes(array('parent_id'=>null));

		foreach($subjectList as $subject){

			$children = Subject::model()->findAllByAttributes(array('parent_id'=>$subject['id']));

			$kids = array();

			$hasKids = false;

			foreach($children as $child){

				$kids[] = array(

					'id'=>$child['id'],

					'text'=>$child['name'],

				);

				$hasKids = true;

			}

			$subjects[] = array(

				'id'=>$subject['id'],

				'text'=>'<a class="subject-link" id="a-subject-'.$subject['id'].'">'.$subject['name'].'</a>',

				'expanded'=>false,

				'hasChildren'=>$hasKids,

				'children'=>$kids,

			);

		}

		$this->data = $subjects;

		

		$cs=Yii::app()->getClientScript();

		$cs->registerCoreScript('jquery');

		$cs->registerScriptFile('/poll/js/stjava.js');

		

		parent::init();

	}

    public function run()

    {

		parent::run();

    }

}



I like the idea of the widget containing it’s own data logic because it keeps the site controller more clean. As for the Poll thing, I don’t like that I have to retrieve all the poll models in the site controller… I wish there was a way to interact with Poll as an object and tell it to get it’s own data for whatever particular view I need.

So, in general and specifically in terms of what I have shown here, what are the correct strategies for bringing together multiple different views?

Thanks, Jaz

widgetizing is the right way, maybe have a look at the portlet extension

http://www.yiiframework.com/extension/portlet/

In your Poll model create some "named scopes" for a query like that:

Post::model()->published()->recent(5)->findAll();

http://www.yiiframework.com/doc/guide/database.ar

I’m looking for a solution like Zend’s Action View Helper that lets you forward/redirect actions. So, in a view I could say:




echo $this->action($action, $controller, $module = null, array $params = array());



I just read about this solution and I don’t know if Yii has something similar.

Ok, so this is what I ended up doing:

To call an action from another controller, I implement that action as an extension of the CAction class. Then, you can add the action to each controller that needs it via CController.actions().

SiteController.php




public function actions(){

  return array( 'latestPolls' => 'application.controllers.poll.LatestPolls' );

}

public function actionIndex(){

  $this->render('index');

}



views/site/index.php




...

$this->widget('application.components.SubjectTree');

$this->run('latestPolls');

...



controllers/poll/LatestPolls.php




class LatestPolls extends CAction 

{

	public function run()

	{

		$models=Poll::model()->recent(5)->findAll();

		$this->getController()->renderPartial('/poll/listbox',array(

			'models'=>$models,

		));

	}

}



So it seems to me that I can combine views via widgets or shared actions. Any thoughts on what’s best or other techniques?