Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

igaster's avatar

Laravel 6 Feature: Eloquent Inheritance

True multitable inheritence in Eloquent. In a perfect world I could:

class User extends Eloquent{
  // table 'users': common columns for all users
}

class Student extends User{
  // table 'students': adds columns specific to students
  // key 'user_id' points to parent object
}

class Teacher extends User{
  // table 'teachers': adds columns specific to teachers
  // key 'user_id' points to parent object
}

In this perfect world Laravel would abstract the database structure from the child models. For example:

User::create([
  'name' => 'Joe', // table: users.name
  'class' => 'C',  // table: students.class
)];

Teachers::create([
  'name' => 'Albert',   // table: users.name
  'lesson' => 'maths',  // table: teachers.lesson
)];

Student::find(1); // LEFT JOIN between users and students
Teachers::where('lesson', 'algebra')->get(); // Got the point?

This functinality would require that Laravel has knowledge about the table's structure so that it can distinguish between their attributes and handle conflicts. (this is the reason for Laravel 6 title!)

Doctrine has a basic implementation, but far from perfect...

Why do I need this:

  • DRY database & models
  • Proper normalize DB
  • DB Performance (?)
  • OOP inheritance = DB inheritance = Developer happiness

By the way, I've already tried to simulate igaster/eloquent-inheritance but itis not a true solution..

Looking for your thoughts!

0 likes
11 replies
jekinney's avatar

Visual studio and asp.net has a tool to map your db and create your models and relationships. But that's part of the visual studio not the asp framework.

And it will do the opposite too though 5 years ago it was really buggy that direction and only worked for msSQL.

igaster's avatar

@martinbean: Polymorphic relations are a nice work-around to achieve polymorphism, but they are not true OOP inheritance. You still have to do

$teacher->user->name;

instead of

$teacher->name;

and of course none of your base class methods are available in the children (since there is no real inheritance)

1 like
jimmck's avatar

@igaster PHP only allows for single inheritance. Databases only know of relations through keys, constraints and triggers. So to achieve what you want would have to be synthetic which is what @martinbean is pointing you towards.

moetanahy's avatar

Hi Axelitus. I came across your comment here and the package you mentioned - has this package been finalised or is this still a proof of concept? I'm looking for a way to solve this problem at the moment using multiple table inheritance.

kiasaty's avatar

Hey @igaster, I have the same issue. How did you solve this? Did you find the perfect solution?

corybaumer's avatar

This is basically what I am doing, my ecommerce project has two types of Promo, BuyOneGetOne and DiscountByTotal. Instead of having them share a table, I make them extend the interface PromoType, PromoType requires they have a relationship to the Promo base model

Promo
|-- Promo.php
`-- PromoType
    |-- BuyOneGetOne.php
    |-- OrderTotal.php

then I can loop through the promos,

public function applyPromos(LineItem $lineItem, array $promos)
    {
        $productDiscount = 0;
        $shippingDiscount = 0;

        foreach ($promos as $promo) {
            $productDiscount += $promo->promoType->productDiscount($lineItem->product);
            $shippingDiscount += $promo->promoType->shippingDiscount($lineItem->product);
        }

        $lineItem->product_discount = $productDiscount;
        $lineItem->shipping_discount = $shippingDiscount;
        $lineItem->save();
    }

This works, but each time I add a new PromoType that's one extra query to the db. Not a BIG deal, but if we had proper inheritance eloquent would select from the promo base table with a conditional left join (by id and type) to each type table and get it all in one trip to the database.

This is my only real gripe with Laravel, I have tried all the packages I could find, they all have the same issue with eager loading and have n+1 issues.

bugsysha's avatar
// Model Foo is the parent model
Schema::create('foo', function (Blueprint $table) {
    $table->increments('id');
    $table->integer('a');
});

// Model Bar inherits Foo.
Schema::create('bar', function (Blueprint $table) {
    $table->increments('id');
    $table->integer('b');
    $table->integer('foo_id')->nullable(); // Foreign Key to Foo
});

Had an app where I had to use nullable for foreign key and it was a mess so I would avoid it at any cost.

OOP inheritance = DB inheritance = Developer happiness

I would prefer composition over inheritance.

True multitable inheritence in Eloquent.

Looks to me as if you are having an issue with database and not with Laravel/Eloquent.

class Foo extends Eloquent
{
    use \igaster\EloquentInheritance\EloquentInherited;

    // ...
    public function fooMethod(){}
}

class Bar extends Eloquent
{
    use \igaster\EloquentInheritance\EloquentInherited;

    // ...
    public function barMethod(){}
}

class BarExtendsFoo extends igaster\EloquentInheritance\InheritsEloquent{
    // Set Parent/Child classes
    public static $parentClass = Foo::class;
    public static $childClass  = Bar::class;

    // You must declare Parent/Child keys explicity:
    public static $parentKeys = ['id','a'];
    public static $childKeys  = ['id','b','foo_id'];

    // Childs Foreign Key (points to Parent)
    public static $childFK  = 'foo_id';

    // You can add your functions / variables ...
    public function newMethod(){}
}

This looks like I could forget it in a week of not using it and then I would be in hell to figure everything out again.

Doctrine has a basic implementation, but far from perfect...

Link is not working for me.

Please or to participate in this conversation.