[Solved] Request A 'relation Of A Relation'

I have the following very simple structure:

User model (id, name, photo),

Post model (id, user_id, text, date),

Comments model (id, post_id, user_id, date).

What I want to achieve through relations is when displaying one Post like this:


Post::model()->with('comments')->findByPk($postid);

To not only get the ‘comments.user_id’ of the creator but to retrieve the related User model along with each comment as well. (actually, enough if I get just one or two attributes like ‘name’ and ‘avatar’).

I was fiddling around with the ‘through’ parameter but I honestly couldn’t get it working (didn’t understand fully) the logic.

If someone could help me out with specifying and explaining which relation goes to which model.

For now I obviously have the basic ones: ‘User HAS_MANY Posts’ and ‘Posts HAS_MANY Comments’ and ‘Comments HAS_ONE User’.

Thank you very much!

if you have your relations declared right you should be able to access comment user via comment object




<?php

// comments model

'user'=>array(static::BELONGS_TO, 'User', 'user_id');




<?php foreach ($posts as $post) { ?>

	<?php echo $post->title ?>

	<?php echo $post->body ?>

	<!-- go thru each comment diplay the comment body and author name -->

	<?php foreach($post->comments as $comment) { ?>	

		<?php echo $comment->body ?>

		<?php echo $comment->user->name ?>

	<?php } ?>

<?php } ?>

Thank you alirz23, I do that on the live site. But I am asking this to be able to return the whole as JSON through an API.

So just to answer my own question should anyone need this.

I’m building a one-liner call for an API to get all posts, get the associated comments with each post and get the photo and name of the user who added the comment. It has to be an eager query so we minimize the database calls and return all information to the API it requires in one call.

User model has an ‘api’ scope saying we only need the ‘photo’ and ‘name’ to display the comments:


public function scopes()

    {

        return array(

            'api' => array(

                'select' => 'photo, name', // only showing these for the comments API call

            ),

        );

    }

Posts model has the following relations, a User who created it and many Comments added to it:


public function relations()

	{

		return array(

			'comments' => array(self::HAS_MANY, 'Comments', 'post_id'),

          		'user' => array(self::BELONGS_TO, 'User', 'user_id'),

			);

	}

Comments model is set up with the relations connected to both post and the user that created it:


public function relations()

	{

	return array(

		'posts' => array(self::BELONGS_TO, 'Posts', 'post_id'),

		'user' => array(self::BELONGS_TO, 'Users', 'user_id'),

		);

	}


public function defaultScope()

    {

        return array(

            'with' => array('user:api'), // pull the "api" scope of Users model by default. "user" is the name of the relation from this model, "api" is the scope from the User model.

        );

    }

The following ‘api’ scope for Comments will be merged with the default scope when called.




    public function scopes()

    {

        return array(

            'api' => array(

                'select' => 'id, comment, date', // only need minimal information for the API from the Comments table/model

            ),

        );

    }

Then to get all posts with associated comments and user names and photos to come with the comments we just call this one line:


$data = Posts::model()->with('comments:api')->findAll();