tightenco / parental
一个简单的优雅特性,允许通过子模型访问关系。
Requires
- php: ^8.0
- illuminate/database: ^9.0||^10.0||^11.0
- illuminate/events: ^9.0||^10.0||^11.0
Requires (Dev)
- orchestra/testbench: ^7.0||^8.0||^9.0
- phpunit/phpunit: ^9.5.10||^10.5
- tightenco/duster: ^2.7
This package is auto-updated.
Last update: 2024-09-12 14:14:43 UTC
README
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()
将返回子模型的一个实例(在这种情况下是 Admin
或 Guest
)。
类型别名
如果你不想在类型列中存储原始类名,你可以使用 $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 为其出色的标志设计,以及 @DanielCoulbourne 在 Twenty Percent Time 上帮助构思想法。