0

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?

Smandoli
  • 6,919
  • 3
  • 49
  • 83
  • 1
    In proper MVC the model is a layer , not an ORM instance ... so , your approach is already wrong. – tereško Aug 27 '12 at 10:34
  • 1
    tereško, I hope one day to understand your thinking on this (which I know is famous). Is Yii conducive to proper MVC? I fear I am destined to fake-MVC, and I know I can never, never have your hair. – Smandoli Aug 27 '12 at 12:02
  • tereski, your post at http://stackoverflow.com/a/10960679/122139 was easy for me to grasp. I'm still excited about fake-MVC, but wondering if it can be rebranded for more effective marketing? But seriously: Will a sound PHP framework ever be developed? (And will I develop the level of insight that lets me put it to work?) I'm sold on Yii in the meantime because I don't have to write as much code and it kind of makes sense. I can never have your hair, but I can post my own solution to this post in the next few days. – Smandoli Sep 13 '12 at 18:05
  • It already has been branded as "MVC" for the marketing purposes. The pattern that most of so called "mvc frameworks" implement comes from Rails (you can read [this rant](http://stackoverflow.com/a/11984678/727208), if you're interested), and it's not only PHP community that has been harmed. Also it's not all bad. On the PHP en Symfony2 and ZF2 are quite decent frameworks (not perfect, but made with OOP principles in mind), thought you might notice that none of them is advertised as "mvc framework". – tereško Sep 13 '12 at 20:46

1 Answers1

2

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);
Stu
  • 4,160
  • 24
  • 43
  • +1 for clear explanation, excerpt from manual supported by link, and BONUS you said "[I'm] right". :-) This looks sound and helpful. I will give the community a few hours to comment. – Smandoli Aug 26 '12 at 13:28
  • Embarrassing, but I can't figure out how to apply this. The manual reference doesn't give this humble newbie enough context. I've also decided looking it up in the view is easy enough, and am moving on. * UPDATE * Hey, the controller file has lines that look like this... – Smandoli Aug 27 '12 at 21:51
  • yes, in your controller when you are searching the Part model, either through `findAll()` / `findAllByAttributes()` etc, you just need to add `with()` and the relation name before the find, so for example `Part::model()->with('category')->findAll()` would find all the parts and return the category of each part too. – Stu Aug 28 '12 at 06:57