Force通过关系创建一个雄辩的模型

时间:2016-12-31 07:11:49

标签: php laravel eloquent relationship laravel-5.3

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

// 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...
    );
}

但是,我得到了:

  

调用未定义的方法Illuminate \ Database \ Query \ Builder :: forceCreate()

即使forceCreate()valid Eloquent method

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

修改

我的快速' ñ'肮脏的解决方案:

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

我确定有更好的方法!

1 个答案:

答案 0 :(得分:4)

$this->subscriptions()的调用会返回HasMany类的实例,而不是Model

createcreateMany相反,HasOneOrMany课程中没有forceCreate()实施。因此,在这种情况下没有第一手的API可供使用。

你知道吗?当您致电$this->subscriptions()->create()时,您在create实例上调用HasMany方法,而不是Model实例。 Model类具有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