Laravel one-to-one polymorphic relationship

Laravel one-to-one polymorphic relationship

In this article let’s understand Laravel one-to-one polymorphic relationship.

Laravel provides many relationship to work with multiple tables and one of them is one-to-one polymorphic relationship.

Check below graphics to understand it in simple scenario.

one-to-one polymorphic relationship Laravel

What you can see from graphics is one Country can have one Capital as well one State can also have one Capital. When “Country” & “State” both can share “Capital” table we can use one-to-one polymorphic relationship.

Let’s understand it through example where we have:

php artisan make:model Country -m
php artisan make:model State -m
php artisan make:model Capital -m

This will create three models and three migrations as below:

app/Models/
    Country.php
    State.php
    Capital.php

database/migrations/
    ***_create_countries_table.php
    ***_create_states_table.php
    ***_create_capitals_table.php

Update all three migrations as below for each:

//Country
Schema::create('countries', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->timestamps();
});

//State
Schema::create('states', function (Blueprint $table) {
    $table->id();
    $table->text('name');
    $table->timestamps();
});

// Capital
 Schema::create('capitals', function (Blueprint $table) {
    $table->id();
    $table->morphs('capitalizable');
    $table->text('name');
    $table->timestamps();
});

The morphs(‘capitalizable’) will create two columns as below:

The capitalizable_type will save model reference for mapping,capitalizable_id will be the reference model id. See below:

The relationship between three tables will be defined as

  • morphOne : country->capital
  • morphOne : state->capital
  • morphTo : capital

Open app/Models/Country.php and modify as below:

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Country extends Model
{
    use HasFactory;
    public function capital()
    {
        return $this->morphOne(Capital::class, 'capitalizable');
    }
}

Check app/Models/State.php and modify as blow:

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class State extends Model
{
    use HasFactory;
    public function capital()
    {
        return $this->morphOne(Capital::class, 'capitalizable');
    }
}

Check app/Models/Capital.php and modify as blow:


namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Capital extends Model
{
    use HasFactory;
    public function capitalizable()
    {
        return $this->morphTo();
    }
}

Run Migrations:

php artisan migrate

Use below methods in your controller to check how one-to-one polymorphic relationship works:

//Create country,state and capital for each.

$country = Country::create(['name'=>"USA"]);
$state = State::create(['name'=>"Ohio"]);

$country->capital()->save(new Capital(['name'=>'Washington D.C.']));
$state->capital()->save(new Capital(['name'=>'Columbus']));

// Fetch country capital
$country = Country::find(1);

echo $country->capital->name; //output : Washington D.C.

// Fetch state capital
$state= State::find(1);
echo $state->capital->name; //output : Columbus

This is very basic and simple implementation of this relationship, but just to make you understand it’s concept. You can play with its various implementation as per your need.

That’s it on one-to-one polymorphic . Hope this finds you helpful.

See other articles on Laravel here.