1

I have 3 data models, one of which extends the other:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Opinion extends Model
{
    public function reactions()
    {
        return $this->morphMany('App\Models\Reaction', 'reactable');
    }

    ...
}
namespace App\Models\Activity;

use App\Models\Opinion;

class ActivityOpinion extends Opinion
{
    ...
}
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Reaction extends Model
{
    public function reactable()
    {
        return $this->morphTo();
    }

    ...
}

The App\Models\Opinion model has a polymorphic relationship with the App\Models\Reaction model. I can retrieve all of the App\Models\Opinion reactions no problem, so I know the relationship works great.

My question is, how can I retrieve the same set of reactions from the App\Models\Activity\ActivityOpinion model? Because right now, it is looking for App\Models\Activity\ActivityOpinion as the relationship but I need it to look for App\Models\Opinion. Is it possible to mock another model in a polymorphic relationship?

ATLChris
  • 3,198
  • 7
  • 39
  • 65
  • so you want the opinions from ActivityOpinion through Reaction right ? – Ahmed Aboud May 15 '19 at 02:12
  • if that's your goal take a look https://stackoverflow.com/questions/43285779/laravel-polymorphic-relations-has-many-through – Ahmed Aboud May 15 '19 at 02:23
  • @AhmedAboud Not exactly I want to get the Reaction of Opinion from ActivityOpinion which is extended from Opinion. So when I call `reactions()` from ActivityOpinion it will query for `App\Models\Opinion` in the `reactable_type` field instead of `App\Models\Activity\ActivityOpinion` – ATLChris May 15 '19 at 02:58

1 Answers1

0

This is because in a Polymorphic Relationship in the stored data (if leaved as default) the relationship type gets the class namespace (sort of) to specify wich model needs to be returned. That's why when you try to access to your reactions() relationship from ActivityOpinion it will look up for the App\ActivityOpinion value in the reactable_type.

You can customize the morph class to search in the model addind this:

Opinion.php

protected $morphClass = 'reaction';

This should be enough, if not, add it also in the ActivityOpinion model.


Note

This could breake some things when trying to search results using Eloquent. Check this other answer in order to address this possible inconviniance.



Update

I've just found out that you could do all this even easier with MorphMap. From the docs:

Custom Polymorphic Types

By default, Laravel will use the fully qualified class name to store the type of the related model. For instance, given the one-to-many example above where a Comment may belong to a Post or a Video, the default commentable_type would be either App\Post or App\Video, respectively. However, you may wish to decouple your database from your application's internal structure. In that case, you may define a "morph map" to instruct Eloquent to use a custom name for each model instead of the class name:

use Illuminate\Database\Eloquent\Relations\Relation;

Relation::morphMap([
    'posts' => 'App\Post',
    'videos' => 'App\Video',
]);

You may register the morphMap in the boot function of your AppServiceProvider or create a separate service provider if you wish.

Kenny Horna
  • 13,485
  • 4
  • 44
  • 71
  • I already looked into `morphMap` as a solution for this, but my understanding is that you can't have 2 models morphed to one. – ATLChris May 15 '19 at 17:13
  • That is because you are extending one from the other, but the thing is that you are trying to get the results from one in the other model. Maybe you should structure your table a little bit diferent to get your desired output (a field `type`maybe). – Kenny Horna May 15 '19 at 17:18