A Single Table Inheritance Trait for Eloquent/Laravel

Overview

Single Table Inheritance

Credit

This code is a fork of Nanigans/single-table-inheritance. I've only updated it to work with Laravel 5

Latest Stable Version Total Downloads Latest Unstable Version License

Single Table Inheritance is a trait for Laravel 5.0.6+ Eloquent models that allows multiple models to be stored in the same database table. We support a few key featres

  • Implemented as a Trait so that it plays nice with others, such as Laravel's SoftDeletingTrait or the excellent Validating, without requiring a complicated mess of Eloquent Model subclasses.
  • Allow arbitrary class hierarchies not just two-level parent-child relationships.
  • Customizable database column name that is used to store the model type.
  • Customizable string for the model type value stored in the database. (As opposed to forcing the use of the fully qualified model class name.)
  • Allow database rows that don't map to known model types. They will never be returned in queries.

Installation

Simply add the package to your composer.json file and run composer update.

"phaza/single-table-inheritance": "1.0.*"

Or go to your project directory where the composer.json file is located and type:

composer require "phaza/single-table-inheritance:1.0.*"

Overview

Getting started with the Single Tabe Inheritance Trait is simple. Add the constraint and add a few properties to your models. A complete example of a Vehicle super class with two subclasses Truck and Car is given by

use Phaza\SingleTableInheritance\SingleTableInheritanceTrait;

class Vehicle extends Eloquent
{
  use SingleTableInheritanceTrait;

  protected $table = "vehicles";

  protected static $singleTableTypeField = 'type';

  protected static $singleTableSubclasses = ['Car', 'Truck'];
}

class Car extends Vehicle
{
  protected static $singleTableType = 'car';
}

class Truck extends Vehicle
{
  protected static $singleTableType = 'truck';
}

There are four requred properties to be defined in your classes:

Define the database table

In the root model set the protected property $table to define which database table to use to store all your classes.
Note: even if you are using the default for the root class (i.e. the 'vehicles' table for the Vehicle class) this is required so that subclasses inherit the same setting rather than defaulting to their own table name.

Define the databse column to store the class type

In the root model set the protected static proerty $singleTableTypeField to define which database column to use to store the type of each class.

Define the subclasses

In the root model and each branch model define the protected static property $singleTableSubclasses to define which subclasses are part of the classes hierarchy.

Define the values for class type

In each concrete class set the protected static property $singleTableType to define the string value for this class that will be stored in the $singleTableTypeField database column.

Multi Level Class Hierarchies

It's not uncommon to have many levels in your class hierarchy. Its easy to define that structure by declaring subclasses at each level. For example suppose you have a Vehicle super class with two subclasses Bike and MotorVehicle. MotorVehicle in trun has two subclasses Car and Truck. You would define the classes like this:

use Phaza\SingleTableInheritance\SingleTableInheritanceTrait;

class Vehicle extends Eloquent
{
  use SingleTableInheritanceTrait;

  protected $table = "vehicles";

  protected static $singleTableTypeField = 'type';

  protected static $singleTableSubclasses = ['MotorVehicle', 'Bike'];
}

class MotorVehicle extends Vehicle
{
  protected static $singleTableSubclasses = ['Car', 'Truck'];
}

class Car extends MotorVehicle
{
  protected static $singleTableType = 'car';
}

class Truck extends MotorVehicle
{
  protected static $singleTableType = 'truck';
}

class Bike extends Vehicle
{
  protected static $singleTableType = 'bike';
}

Defining Which Atttributes Are Persisted

Eloquent is extremly lenient in allowing you to get and set attributes. There is no mechanism to declare the set of attributes that a model supports. If you misues and attribute it typically results in a SQL error if you try to issue an insert or update for a column that doesn't exist. By default the SingleTableInheritanceTrait opperates the same way. However, when storing a class hierarchy in a single table there are often database columns that don't apply to all classes in the heirarchy. That Eloquent will store values in those columns makes it considerably easier to write bugs. There, the SingleTableInheritanceTrait allows you to define which attributes are persisted. The set of persisted attributes is also inherited from parent classes.

class Vehicle extends Eloquent
{
  protected static $persisted = ['color']
}

class MotorVehicle extends Vehicle
{
  protected static $persisted = ['fuel']
}

In the above example the class Vehicle would persiste the attribute color and the class MotorVehicle would persiste both color and fuel.

Automatically Persisted Attributes

For convineience the model primary key and any dates are automatically added to the list of persisted attributes.

BelongsTo Relations

If you are restricting the persisted attribute and yoru model has BelongsTo relations then you must include the foreign key column of the BelongsTo relation. For example:

class Vehicle extends Eloquent
{
  protected static $persisted = ['color', 'owner_id'];
  
  public function owner()
  {
    return $this->belongsTo('User', 'owner_id');
  }
}

Unfortunately there is no efficient way to automatically detect BelongsTo foreign keys.

Throwing Exceptions for Invalid Attributes

BY default the SingleTableINheritanceTrait will handle invalid attributes silently It ignores non-persisted attributes when a model is saved and ignores non-persisted columns when hydrating a model from a builder query. However, you can force exceptions to be thrown when invalid attributes are encounted in either situation by setting the $throwInvalidAttributeExceptions property to true.

/**
 * Whether the model should throw an InvalidAttributesException if non-persisted 
 * attributes are encoutered when saving or hydrating a model.
 * If not set, it will default to false.
 *
 * @var boolean
 */
protected static $throwInvalidAttributeExceptions = true;
You might also like...
A make:pivot command to create a pivot table with Laravel

make:pivot for Laravel Installation Requires PHP 8.0.0+ You can install the package via composer: composer require felixdorn/laravel-make-pivot-table

A dynamic table component for Laravel Livewire - For Slack access, visit:
A dynamic table component for Laravel Livewire - For Slack access, visit:

A dynamic Laravel Livewire component for data tables. Bootstrap 4 Demo | Bootstrap 5 Demo | Tailwind Demo | Demo Repository Installation You can insta

Laravel Larex lets you translate your whole Laravel application from a single CSV file.
Laravel Larex lets you translate your whole Laravel application from a single CSV file.

Laravel Larex Translate Laravel Apps from a CSV File Laravel Larex lets you translate your whole Laravel application from a single CSV file. You can i

Library for generating random names (for table-top roleplaying games)

RPG-Name-Generator The RPG character name generator library is designed to create list of random names used for table-top role-playing games. This lib

Data Table package with server-side processing, unlimited exporting and VueJS components
Data Table package with server-side processing, unlimited exporting and VueJS components

Data Table package with server-side processing, unlimited exporting and VueJS components. Quickly build any complex table based on a JSON template.

This package extends Illuminate to provide partitioned table creation in migrations.
This package extends Illuminate to provide partitioned table creation in migrations.

Laravel Partitions for Migrations This package extends Illuminate to provide partitioned table creation in migrations for PostgreSQL. Support for othe

Creates a Filament table action.
Creates a Filament table action.

Filament Action Designed for easy integration and manage of Filament actions. Installation You can install the package via composer: composer require

Update multiple Laravel Model records, each with it's own set of values, sending a single query to your database!

Laravel Mass Update Update multiple Laravel Model records, each with its own set of values, sending a single query to your database! Installation You

This Package helps you in laravel application to log all desired activity for each request from request entry point to generate response at a single snapshot.

Laravel Scenario Logger This Package helps you in laravel application to log all desired activity for each request from request entry point to generat

Comments
  • PSR-2 and numeric types

    PSR-2 and numeric types

    I've formatted the code according to PSR-2 coding standards (using phpcbf and phpcs). I'm not sure how you feel about PSR-2 but it's a major movement within the PHP community to promote ease of reading and maintaining PHP code.

    I also fixed a bug where the use of array_merge() in the trait's getSingleTableTypeMap() function effectively prevented support for when $singleTableTypeField refers to a numeric column. This was a major show-stopper for a project I was trying to use it on. So I replaced array_merge() with a brute-force merge (a single foreach loop.)

    The test all still pass, although I haven't added any new ones yet.

    opened by curtisdf 0
Releases(1.0.1)
Owner
Peter Haza
Peter Haza
Tag support for Laravel Eloquent models - Taggable Trait

Laravel Taggable Trait This package is not meant to handle javascript or html in any way. This package handles database storage and read/writes only.

Rob 859 Dec 11, 2022
ODM with inheritance and OOP composition for Laravel 5+

ODM with inheritance and OOP composition for Laravel 5+ Full Documentation | CHANGELOG LODM module is intended to bring the Spiral ODM component funct

Anton Titov 21 Aug 17, 2022
This package provides a trait that will generate a unique uuid when saving any Eloquent model.

Generate slugs when saving Eloquent models This package provides a trait that will generate a unique uuid when saving any Eloquent model. $model = new

Abdul Kudus 2 Oct 14, 2021
Trait for Laravel testing to count/assert about database queries

counts_database_queries Trait for Laravel testing to count/assert about database queries Installing composer require ohffs/counts-database-queries-tra

null 1 Feb 23, 2022
Generate and autoload custom Helpers, Builder Scope, Service class, Trait

laravel-make-extender Generate and autoload custom helpers, It can generate multilevel helpers in the context of the directory. Generate Service class

Limewell 30 Dec 24, 2022
Trait for multilingual resource file support

⚡ Usage This library supports MultilingualResourceTrait which can be used in PluginBase. Multilingual support of resource files is possible using this

PocketMine-MP projects of PresentKim 1 Jun 7, 2022
This package provides a trait to run your tests against a MinIO S3 server.

Laravel MinIO Testing Tools This package provides a trait to run your tests against a MinIO S3 server. ?? Blog post: https://protone.media/en/blog/how

Protone Media 7 Oct 12, 2022
Livewire trait (throttling). Limiting request processing speed

Livewire Throttling Installation You can install the package via composer: composer require f1uder/livewire-throttling Usage Livewire component <?php

Fluder 5 Dec 7, 2022
Razorpay payment gateway integration in laravel with submit form and storing details in payment table.

Integrating razorpay payment gateway in laravel with submit form and storing payment details in payment table. How to settup the project in your local

Mohammed-Thamnees 3 Apr 15, 2021
Laravel Grid is a package that helps you display table data.

Laravel Grid Laravel Grid is a package that helps you display table data. I could not find package that would satisfy my needs so I decided to write o

null 9 Nov 29, 2022