通过关系强制创建 eloquent 模型

Force create an eloquent model through a relationship

在一个使用 Laravel 5.3 和 Stripe 的小项目中,我试图通过 hasOne 关系在 User 上强制创建 Subscription

// User.php
public function subscription() {
    return $this->hasOne('App\Subscription');
}

public function subscribe($data) {
    return $this->subscription()->forceCreate(
        // $data contains some guarded fields;
        // create() will simply ignore them...
    );
}

但是,我得到:

Call to undefined method Illuminate\Database\Query\Builder::forceCreate()

即使 forceCreate()valid Eloquent method

有什么办法可以模拟这种行为吗?或者我应该 save a Subscription 手动分配每个字段?复杂的是某些字段应该保留 guarded,例如stripe_id.

编辑

我的快速解决方案:

// User.php @ subscribe($data)
return (new Subscription())
        ->forceFill([
            'user_id' => $this->id,
            // $data with sensitive guarded data
        ])
        ->save();

我相信还有更好的方法!

调用 $this->subscriptions() returns HasMany class, not a Model 的一个实例。

create and createMany, there's no forceCreate() implemented in HasOneOrMany相反class。因此,在这种情况下没有第一手的 API 可以使用。

看到了吗?当您调用 $this->subscriptions()->create() 时,您是在 HasMany 实例而不是 Model 实例上调用 create 方法。事实上 Model class 有一个 forceCreate 方法,与此无关。

您可以使用 getRelated() 方法获取相关模型,然后对其调用 forceCreate()unguarded()

public function subscribe($data) {
    return $this->subscription()
                ->getRelated()
                ->forceCreate($data);
}

但是这种方法有一个严重的缺点;当我们从关系中提取模型时,它不会设置关系。要解决它,您可以说:

public function subscribe($data)
{
    // $data['user_id'] = $this->id;
    // Or more generally:  
    $data[$this->courses()->getPlainForeignKey()] = $this->courses()->getParentKey();

    return $this->courses()
                ->getRelated()
                ->forceCreate($data);
}

呃,好像太hacky了,不是我的做法。我更喜欢解除底层模型的保护,调用 create 然后重新保护它。大致如下:

public function subscribe($data)
{
    $this->courses()->getRelated()->unguard();

    $created = $this->courses()->create($data);

    $this->courses()->getRelated()->reguard();

    return $created;
}

这样,您就不必手动设置外键了。

laravel/internals相关讨论:
[PROPOSAL] Force create model through a relationship