GithubHelp home page GithubHelp logo

laravel-sti's Introduction

A single table inheritance trait for Eloquent

Latest Version on Packagist Build Status Total Downloads

This package provides a trait that makes your eloquent models capable of single table inheritance. If configured properly, queries will automatically return instances of the correct model subclasses according to the type column.

Installation

You can install the package via composer:

composer require mannikj/laravel-sti

Basic Usage

Migration

The table you want to apply single table inheritance to must incorporate a type column.

The package's service provider adds a macro to the Blueprint class to create the type column.

Schema::table('table', function (Blueprint $table) {
    $table->sti()->nullable();
});

Using the Trait

You need to add the SingleTableInheritance trait to your root model class. The sub models need to extend the root class.

use MannikJ\Laravel\SingleTableInheritance\Traits\SingleTableInheritance;

class Root extends Model {
    use SingleTableInheritance;
}

class Sub1 extends Root {}

class Sub2 extends Root {}

For the default usage no other configuration is needed. The trait will use the class name of the subclasses as the type, scope the queries accordingly and return the correct instances of subclasses automatically.

Nested

If you have multiple levels of subclasses and you want the automatic scoping to include all sub types, you need to define the direct subclasses for each model by setting the stiSubClasses array property:

use MannikJ\Laravel\SingleTableInheritance\Traits\SingleTableInheritance;

class Root extends Model {
    use SingleTableInheritance;

    protected $stiSubClasses = [
        Sub1::class, Sub2::class
    ]
}

class Sub1 extends Root {
    protected $stiSubClasses = [
        Sub3::class
    ]
}

class Sub2 extends Root {}

class Sub3 extends Sub1 {}

Advanced Usage

Types without fully-qualified classnames

Without any tweaking, the trait assumes that there is a type column storing the fully qualified names of the subclasses. However, if you want to use some other string not directly referencing a class as the type identifier, you can do so by overwriting two functions of the trait:

    public static function resolveTypeViaClass()
    {
        $type = (new \ReflectionClass(static::class))->getShortName();
        $type = str_replace('Component', '', $type);
        $type = strtolower($type);

        return static::isSubclass() 
            ? $type 
            : null;
    }


    public function resolveModelClassViaAttributes($attributes = [])
    {
        $type = $this->resolveTypeViaAttributes($attributes);

        // Map class to type
        $mapping = [
            'motif' => MotifComponent::class,
            'text' => TextComponent::class,
        ];
        
        return $type 
            ? data_get($mapping, $type) 
            : static::class;
    }

Resolving the type based on a related model

You can also tweak the behavior even further so that the type will be determined based on a related model:

class Animal extends Model
{
    use SingleTableInheritance;

    protected $fillable = ['name'];

    public function resolveTypeViaAttributes($attributes = [])
    {
        if ($category = Category::find(Arr::get($attributes, 'category_id'))) {
            return $category->config_class;
        };
    }

    public function applyTypeCharacteristics($type)
    {
        $this->category_id = Category::where('config_class', $type)->first()?->id;
    }

    public function scopeSti(Builder $builder)
    {
        $builder->whereHas('category', function ($query) use ($builder) {
            $query->where('categories.config_class', static::class);
        });
    }

    public function category()
    {
        return $this->belongsTo(Category::class, 'category_id')->withDefault([
            'config_class' => static::class
        ]);
    }
}

Testing

composer test

Changelog

Please see CHANGELOG for more information about what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security

If you discover any security related issues, please email [email protected] instead of using the issue tracker.

Credits

License

The MIT License (MIT). Please see License File for more information.

Laravel Package Boilerplate

This package was generated using the Laravel Package Boilerplate.

laravel-sti's People

Contributors

mannikj avatar tankonyako avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

tankonyako

laravel-sti's Issues

STI Model ::find method fails in model but succeeds in controller

  • Laravel 5.8.34
  • PHP 7.3.11
  • PostgreSQL 11.5

Description:

I have Car and Bike classes, each extended from Vehicle class.
The Vehicle class uses the SingleTableInheritance trait.
The Vehicle migration has a $table->sti()->nullable() which create a type field.
The Vehicle model has a protected $table = 'vehicles'; field.
In my database i have a Car object stored in the Vehicle table like this:

id: "id_string"
type: "App\Models\Car"

In a controller when I do Vehicle::find("id_string") it succeeds and returns me an instance of Car.
But in a model Vehicle::find("id_string") returns me null when Car::find("id_string") returns me an instance of Car.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.