3

I have a comments table that have comments of articles, recipes and products. So its a polymorphic relation. I have two columns rel_id and rel_type in my comments table those are being used for this relation.

Now in my Comment.php I have following relation

public function rel()
{
    $this->morphTo();
}

And in my other all classes I have following

public function comments()
{
    return $this->morphMany('App\Models\Comment', 'rel');
}

When I try to get owner of comment and all its related data I found class not found error. For example

$comments = Comment::find(1);
echo $comments->rel_type //article

Now if I want to get data of article and when I try

$comments->rel

I found article class not found. I am using namespace App\Models\Article I have searched it out I found answer given here. When I try accepted answer, nothing happens, error remains same. When I try second answer of same question, I found

 Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation 

My ultimate goal is to get comment owner data like $comments->articles->id and so on. Please guide how can I do that?

Community
  • 1
  • 1
user1272333
  • 33
  • 1
  • 5

1 Answers1

1

I have a blog post about this:

http://andrew.cool/blog/61/Morph-relationships-with-namespaces

There are a couple things you need to do. First, for all of your models that have comments, add the $morphClass variable to the class, e.g.:

class Photo {
    protected $morphClass = 'photo';
}
class Album {
    protected $morphClass = 'album';
}

Second, on the Comment class, define an array called $rel_types on your Comment class. This will be basically the inverse of what you just did, it's a mapping from short name to full class name.

class Comment {
    protected $rel_types = [
        'album' => \App\Album::class,
        'photo' => \App\Photo::class,
    ];
}

Finally, define an accessor for the rel_type column. This accessor will first retrieve the column from the database ("album", "photo", etc.) and then convert it to the full class name ("\App\Album", "\App\Photo", etc.)

/**
 * @param  string  $type  short name
 * @return string  full class name
 */
public function getRelTypeAttribute($type)
{
    if ($type === null) {
        return null;
    }

    $type = strtolower($type);
    return array_get($this->rel_types, $type, $type);
}

Note: $morphClass is something Laravel actually defines, so it has to be named that. $rel_types can be named anything you want, I just based it off of the rel_type column you have.

To make this even better, add that getRelTypeAttribute method to a trait so that any model that morphs can reuse that trait and method.

andrewtweber
  • 24,520
  • 22
  • 88
  • 110
  • actually the point that I am not getting is that following your method I get `string(18) "app\models\article" ` that is class string not object. So let say `$comment = Comment::find(1)` has `rel_type article and rel_id 1`. so now how can I get article data like all attributes of article from article table that belongs to this comment. – user1272333 Oct 18 '15 at 06:47
  • @user1272333 Just use `$comment->rel` as you were before. The problem you faced earlier was that rel_type was just "article" and it tried to create a new object of class "article" which doesn't exist. Now, rel_type is "app\models\article" and it will successfully create an object of that full class name. – andrewtweber Oct 19 '15 at 04:35
  • When I try `$comment->rel` it gives me error `Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation` – user1272333 Oct 19 '15 at 14:07
  • Because `$comment->rel()` is returning null. Why it is returning null? – user1272333 Oct 19 '15 at 14:27
  • Hi, its fixed because I was doing a blunder while doing morphTo as I wasn't using return statement. Thanks you solutions worked. – user1272333 Oct 19 '15 at 14:33
  • @user1272333 ok great, I should have noticed that in your question, glad you caught it – andrewtweber Oct 19 '15 at 14:49