首页 > 解决方案 > Laravel - Eloquent 模型不触发事件

问题描述

我正在使用https://github.com/JosephSilber/bouncer包。我目前正在努力使其与 UUID 而不是典型的 int 标识符一起使用。从问题中我发现了如何做到这一点:https ://github.com/JosephSilber/bouncer/issues/256 。

问题是创建角色/能力最终会出错:

SQLSTATE[23000]:[Microsoft][ODBC Driver 17 for SQL Server][SQL Server]无法将值 NULL 插入列 'id',表 'db.dbo.roles';列不允许空值。插入失败。(SQL: insert into [roles] ([name], [title], [updated_at], [created_at]) 值 (Users, User, 2021-07-08 15:22:46.247, 2021-07-08 15:22 :46.247))

我的数据库中有 uuid 而不是 id,因此我在自定义角色/能力模型中创建了一个引导方法来捕获creating如下事件:

trait BouncerUuidTrait
{
    public static function boot(){
        parent::boot();

        // NEVER REACHING HERE
        self::creating(function ($model) {
            $model->incrementing = false;
            $model->{$model->getKeyName()} = Str::uuid()->toString();
        });
    }
}

我的自定义角色类的示例:

use Silber\Bouncer\Database\Role as BouncerRole;

class Role extends BouncerRole
{
    use BouncerUuidTrait;

    public $incrementing = false;

    protected $fillable = ['id', 'name', 'title'];
}

创建角色的逻辑:

        $role = Bouncer::role()->firstOrCreate([
            'name' => LDAPInterface::LDAP_GROUP_WCR_USERS,
            'title' => 'User',
        ]);

这是我从保镖包(带有 uuids)的迁移:

public function up()
    {
        Schema::create(Models::table('abilities'), function (Blueprint $table) {
            $table->uuid('id')->primary();
            $table->string('name');
            $table->string('title')->nullable();
            $table->bigInteger('entity_id')->unsigned()->nullable();
            $table->string('entity_type')->nullable();
            $table->boolean('only_owned')->default(false);
            $table->json('options')->nullable();
            $table->integer('scope')->nullable()->index();
            $table->timestamps();
        });

        Schema::create(Models::table('roles'), function (Blueprint $table) {
            $table->uuid('id')->primary();
            $table->string('name');
            $table->string('title')->nullable();
            $table->integer('level')->unsigned()->nullable();
            $table->integer('scope')->nullable()->index();
            $table->timestamps();

            $table->unique(
                ['name', 'scope'],
                'roles_name_unique'
            );
        });

        Schema::create(Models::table('assigned_roles'), function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->uuid('role_id')->index();
            $table->bigInteger('entity_id')->unsigned();
            $table->string('entity_type');
            $table->bigInteger('restricted_to_id')->unsigned()->nullable();
            $table->string('restricted_to_type')->nullable();
            $table->integer('scope')->nullable()->index();

            $table->index(
                ['entity_id', 'entity_type', 'scope'],
                'assigned_roles_entity_index'
            );

            $table->foreign('role_id')
                  ->references('id')->on(Models::table('roles'))
                  ->onUpdate('cascade')->onDelete('cascade');
        });

        Schema::create(Models::table('permissions'), function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->uuid('ability_id')->index();
            $table->uuid('entity_id')->nullable();
            $table->string('entity_type')->nullable();
            $table->boolean('forbidden')->default(false);
            $table->integer('scope')->nullable()->index();

            $table->index(
                ['entity_id', 'entity_type', 'scope'],
                'permissions_entity_index'
            );

            $table->foreign('ability_id')
                  ->references('id')->on(Models::table('abilities'))
                  ->onUpdate('cascade')->onDelete('cascade');
        });
    }

标签: phplaraveleloquent

解决方案


为了触发模型事件,必须实例化模型。

基本模型示例

对于单个模型(没有关系),这就像选择一个创建语法而不是另一个一样简单:

不触发模型事件

Model::create([
  'field' => 'value
]);

触发模型事件

$model = new Model;
$model->field = 'value;
$model->save();

关系示例

对于关系,我们遵循类似的语法。

不触发模型事件

Model::related()->create(['field' => 'value']);

触发模型事件

$model = Model::find(1);

$related = new Related;
$related->field = 'value';

$model->related()->attach($related);

概括

您会注意到这两种类型之间的主要区别在于static方法调用的使用与首先实际创建new模型的区别。和类似的create方法是方便的捷径,但您需要注意这些权衡。


推荐阅读