envor / parental
资助包维护!
calebporzio
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
- phpunit/phpunit: ^9.5.10||^10.0
- tightenco/duster: ^2.7
README
Parental
Parental是一个Laravel包,它将STI(单表继承)功能带到了Eloquent。
什么是单表继承(STI)?
这是一个复杂名称,指的是一个简单概念:扩展一个模型(通常是为了添加特定行为),但引用的是同一个表。
安装
composer require envor/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 上的想法启发。