在使用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();
我确定有更好的方法!
答案 0 :(得分:4)
对$this->subscriptions()
的调用会返回HasMany
类的实例,而不是Model
。
与create
和createMany
相反,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相关讨论: