tightenco/parental

一个简单的优雅特性,允许通过子模型访问关系。

资助包维护!
calebporzio

安装次数: 457 171

依赖项: 6

建议者: 0

安全性: 0

星标: 1 340

关注者: 34

分支: 98

开放问题: 11

v1.4.0 2024-03-12 13:04 UTC

README

Parental - Use single table inheritance in your Laravel App

Parental

Parental 是一个 Laravel 包,它为 Eloquent 带来了 STI (单表继承) 功能。

什么是单表继承 (STI)?

这是一个简单概念的复杂名称:扩展一个模型(通常是为了添加特定行为),但引用相同的表。

安装

composer require tightenco/parental

简单用法

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Parental\HasChildren;

// The "parent"
class User extends Model
{
    use HasChildren;
    //
}
namespace App\Models;

use Parental\HasParent;

// The "child"
class Admin extends User
{
    use HasParent;

    public function impersonate($user) {
        //...
    }
}
use App\Models\Admin;

// Returns "Admin" model, but reference "users" table:
$admin = Admin::first();

// Can now access behavior exclusive to "Admin"s
$admin->impersonate($user);

我们刚刚解决了什么问题?

没有 Parental,调用 Admin::first() 会抛出错误,因为 Laravel 正在寻找一个 admins 表。Laravel 使用模型的类名生成预期的表名,以及外键和关联表名。通过将 HasParent 特性添加到 Admin 模型中,Laravel 现在将引用父模型的类名 users

从父模型访问子模型

// First, we need to create a `type` column on the `users` table
Schema::table('users', function ($table) {
    $table->string('type')->nullable();
});
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Parental\HasChildren;

// The "parent"
class User extends Model
{
    use HasChildren;

    protected $fillable = ['type'];
}
namespace App\Models;

use Parental\HasParent;

// A "child"
class Admin extends User
{
    use HasParent;
}
namespace App\Models;

use Parental\HasParent;

// Another "child"
class Guest extends User
{
    use HasParent;
}
use App\Models\Admin;
use App\Models\Guest;
use App\Models\User;

// 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/Guest"
Guest::create(...);

// Returns 2 model instances: Admin, and Guest
User::all();

我们刚刚解决了什么问题?

在此之前,如果我们运行: User::first() 我们只会得到 User 模型。通过添加 HasChildren 特性和一个 type 列到 users 表中,运行 User::first() 将返回子模型的一个实例(在这种情况下是 AdminGuest)。

类型别名

如果你不想在类型列中存储原始类名,你可以使用 $childTypes 属性来覆盖它们。

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Parental\HasChildren;

class User extends Model
{
    use HasChildren;

    protected $fillable = ['type'];

    protected $childTypes = [
        'admin' => Admin::class,
        'guest' => Guest::class,
    ];
}

现在,运行 Admin::create() 将在 users 表中的 type 列中设置 admin 而不是 App\Models\Admin

这个特性如果你正在使用现有的类型列,或者如果你想将应用程序的细节与数据库解耦时非常有用。

自定义类型列名称

你可以通过在父模型上设置 $childColumn 属性来覆盖默认的类型列。

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Parental\HasChildren;

class User extends Model
{
    use HasChildren;

    protected $fillable = ['parental_type'];

    protected $childColumn = 'parental_type';
}

Laravel Nova 支持

如果你想使用共享父 Nova 资源与子模型,你可以在 NovaServiceProvider 的 boot 方法末尾注册以下提供者

class NovaServiceProvider extends NovaApplicationServiceProvider
{
    public function boot() {
        parent::boot();
        // ...
        $this->app->register(\Parental\Providers\NovaResourceProvider::class);
    }
}

感谢 @sschoger 为其出色的标志设计,以及 @DanielCoulbourneTwenty Percent Time 上帮助构思想法。