Parental is an early-stage development, alpha Laravel package by Tighten that brings STI (Single Table Inheritance) capabilities to Eloquent.
composer require "tightenco/parental=0.4-alpha"
- Create "child" model: ex.
Admin.php
- Extend "parent" model: ex.
User.php
- Add
HasParentModel
trait toAdmin.php
use Tightenco\Parental\HasParentModel;
class Admin extends User
{
use HasParentModel;
}
// Returns "Admin" model, but reference "users" table:
Admin::first();
Laravel performs some internal magic to derive the table name and field names from each model's class name. For example, calling Admin::first()
, even though Admin extends User, would throw an error because it would be looking for an admins
table. Fortunately, you can manually set a protected $table = 'users'
property on the Admin model to override this behavior. Unfortunately, it's difficult to do something similar for foreign key names, and pivot column / table names.
By adding the HasParentModel
class to your Admin model, all the hard work is done automatically. Admin::first()
will look in the parent User model's table, but return the proper Admin model.
- Create "child/children" models: ex.
Admin.php
,Manager.php
- Extend "parent" model: ex.
User.php
- Add
type
column tousers
table - Add
HasParentModel
trait toAdmin.php
,Manager.php
- Add
ReturnsChildModels
trait toUser.php
use Tightenco\Parental\HasParentModel;
class Admin extends User
{
use HasParentModel;
}
use Tightenco\Parental\HasParentModel;
class Manager extends User
{
use HasParentModel;
}
use Tightenco\Parental\ReturnsChildModels;
class User extends Model
{
use ReturnsChildModels;
}
// In users table migration:
$table->string('type')->nullable();
// Adds row to "users" table with "type" column set to: "App/Admin"
Admin::create(...);
// Adds row to "users" table with "type" column set to: "App/Manager"
Manager::create(...);
// Returns 2 model instances: Admin, and Manager
User::all();
Before, when we just added the HasParentModel
, we got half-way there. That enabled us to find, retreive, and use the Admin
model, instead of the User
model. However, this is only one side of the equation. Before, if we ran: User::first()
we would only get back User
models. By simply adding the ReturnsChildModels
to the User
model, now running User::first()
will return an instance of whatever model, that User
is supposed to be. To accomplish this sort polymorphic behavior, we need to use a type
column on the users
table to keep track of what model instance to return from User queries.
If for some reason you don't want to store raw class names in the type column, you can override them using the $childTypeAliases
property.
use Tightenco\Parental\ReturnsChildModels;
class User extends Model
{
use ReturnsChildModels;
protected $childTypeAliases = [
'admin' => App\Admin::class,
];
}
Now, running Admin::create()
will set the type
column in the users
table to admin
instead of App\Admin
.
This feature is useful for those who are already using a type column with a different naming scheme, or those who don't want to store application classes directly in the database.
You can override the default type column by setting the $childTypeColumn
property on the parent model.
use Tightenco\Parental\ReturnsChildModels;
class User extends Model
{
use ReturnsChildModels;
protected $childTypeColumn = 'parental_type';
}
Thanks to @sschoger for the sick logo design, and @DanielCoulbourne for helping brainstorm the idea on Twenty Percent Time.