力通过关系打造雄辩模型

Ale*_*lex 4 php relationship laravel eloquent laravel-5.3

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

// 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...
    );
}
Run Code Online (Sandbox Code Playgroud)

但是,我得到:

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

尽管forceCreate()这是一个有效的雄辩方法

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

编辑

我的快速又肮脏的解决方案:

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

我确信有更好的方法!

sep*_*ehr 6

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

create与和相反createMany,在类中没有forceCreate()实现HasOneOrMany。因此,在这种情况下没有可用的第一手 API。

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

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

public function subscribe($data) {
    return $this->subscription()
                ->getRelated()
                ->forceCreate($data);
}
Run Code Online (Sandbox Code Playgroud)

但这种方法有一个严重的缺点:当我们从关系中获取模型时,它不会设置关系。要解决这个问题,你可能会说:

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);
}
Run Code Online (Sandbox Code Playgroud)

呃,看起来太老套了,不是我的方法。我更喜欢不保护底层模型,调用create然后重新保护它。大致如下:

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

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

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

    return $created;
}
Run Code Online (Sandbox Code Playgroud)

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

laravel/internals 相关讨论:
[提案] 通过关系强制创建模型