phplaraveleloquentrelationshippolymorphic-associations

Laravel - reverse polymorphic relationship


I basically have two models (dog and cat) of the same type: pets. The table pets joins all dogs and cats in the database. Now I would like to be able to find a specific pet through the pet id in the PetController. Like so:

$pet = Pet::findOrFail($id); // returns a dog or cat

Tables structure:

┌──────────────┐  ┌───────────┐  ┌───────────┐
│ pets         │  │ dogs      │  │ cats      │
├──────────────┤  ├───────────┤  ├───────────┤
│ id           │  │ id        │  │ id        │
│ related_type │  │ name      │  │ name      │
│ related_id   │  │ eye_color │  │ tail_size │
└──────────────┘  └───────────┘  └───────────┘

Pets table:

┌────┬──────────────┬────────────┐
│ id │ related_type │ related_id │
├────┼──────────────┼────────────┤
│ 1  │ dog          │ 1          │
├────┼──────────────┼────────────┤
│ 2  │ dog          │ 2          │
├────┼──────────────┼────────────┤
│ 3  │ cat          │ 1          │
└────┴──────────────┴────────────┘

I have searched the Laravel docs but none of the relationships seem to fit for this problem. Only the polymorphic relationship would work the other way around, so that I could access the pet model through the dog- or cat-id. But I am looking for a solution that work the other way around. Is there any kind of relationship without needing to use nasty if-else in the PetController manually?

Thank you!


Solution

  • You can define a polymorphic relationship between these 3 models like this

    Pet Model

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

    Dog Model

    public function pets(){
         $this->morphMany('App\Pet', 'related');
    }
    

    Cat Model

    public function pets(){
         $this->morphMany('App\Pet', 'related');
    }
    

    Now fetch it like this

    $pet = Pet::findOrFail($id)->related;
    dd($pet); //you will get either cat or dog
    

    Easy create

    $dog = Dog::create(['name'=> 'dog1', 'eye_color' => 'gray']);
    $dog->pets()->create();
    

    Check details here https://laravel.com/docs/5.6/eloquent-relationships#polymorphic-relations