Smandoli
Smandoli

Reputation: 7019

Using a view to get referenced value -- proper MVC for Yii?

As you would guess from the two snips below, I will reference the Category table when displaying Part details.

Part model:

public function relations()    {
    return array(
        'category' => array(self::BELONGS_TO, 'Category', 'fid_caty2') );
}

Category model:

public function relations()    {
    return array('part' => array(self::HAS_MANY, 'Part', 'fid_caty2') );
}

I've learned this method of rendering the referenced value in a view:

echo CHtml::encode($data->category->name_caty2);

I've found some other methods too, but they all take place in the view. Since the model sets the relationship, why shouldn't the referenced value be included in the CActiveRecord of the model? I thought this was exactly the kind of crunching we reserved for the model. Working it out in a view seems strange, plus a lot of extra work.

If I'm right, how do I make it work in the model view? Or does my understanding of MVC need correction?

How about this

public function loadModel($id)
{   $model=Part::model()->findByPk($id);
    if($model===null)
        throw new CHttpException(404,'The requested page does not exist.'); 
    return $model;
}

Here are in the controller page. Can I sneak my referenced value into the model when it is loaded?

Upvotes: 0

Views: 148

Answers (1)

Stu
Stu

Reputation: 4150

Yii uses lazy loading, which means it only loads the models it needs, and therefore only queries the tables it needs for a set statement.

When you pull your Part model in your controller, for example;

$data = Part::model()->findAll($criteria);

You won't be pulling the relation, as it's not explicitly needed, and as you've already mentioned, your code in the view;

$data->category->name_caty2;

Will perform another query, and you don't want to do that in the view, you're right in your question that business logic shouldn't appear in the view.

The way around this is to use Yii's eager loading (as opposed to lazy loading mentioned above). As mentioned in the manual;

The eager loading approach retrieves the related AR instances together with the main AR instance(s). This is accomplished by using the with() method together with one of the find or findAll methods in AR. For example,

$posts=Post::model()->with('author')->findAll();

So in your case, you would need to use;

$data = Part::model()->with('category')->findAll($criteria);

Upvotes: 2

Related Questions