我有两个模型:UserPayout和UserTransaction,其中UserTransaction是多态的,需要知道它属于哪个模型。 每当用户创建支付时,都应自动进行交易。如果在这个过程中出现问题,两者都应该回滚。
我的实际解决方案如下:
控制器:
$user_payout = new UserPayout($input);
$user->payouts()->save($user_payout);
UserPayout:
public function save(array $options = Array())
{
DB::beginTransaction();
try{
parent::save($options);
$transaction = new UserTransaction(
array(
'user_id' => $this->user_id,
'template_id' => $this->template->id,
'value' => -$this->amount
)
);
$this->transactions()->save($transaction);
}
catch(\Exception $e)
{
DB::rollback();
throw $e;
}
DB::commit();
return $this;
}
的UserTransaction:
public function save(array $options = Array())
{
DB::beginTransaction();
try{
$user = User::find($this->user_id);
$user->balance = $user->balance + $this->value;
if(!$user->save()) throw new Exception('User could not be saved. Check for validation rules.');
parent::save($options);
}
catch(\Exception $e)
{
DB::rollback();
throw $e;
}
DB::commit();
return $this;
}
嗯,这个解决方案实际上可行,但如果我需要更新支付怎么办?它会触发保存功能,并且(当然)它会创建一个新的事务。这绝对是错误的。
那么只有将其应用于创建支付的解决方案是什么?
我考虑过创建和创建等事件。在创建的情况下,我无法告诉交易模型它属于谁,因为还没有创建支付。另一方面,在创建的情况下,我无法在保存交易时判断出是否出现问题,以便我可以回滚付款。
那么这里的解决方案是什么?任何帮助表示赞赏。
答案 0 :(得分:1)
那么只有将其应用于创建支付的解决方案是什么?
您可以通过检查是否在 save()方法中设置了ID来轻松确定是否创建了付款:
if ($this->id) {
//update transaction
} else {
//create transaction
}
其次,如果你看看Eloquent如何处理交易,你会发现它们不会嵌套。只有第一次调用调用堆栈中的 beginTransaction()才会启动数据库事务,只有最后一次调用 commit()才会提交事务,因此您不需要担心嵌套交易。
说到事件,它们提供了很好的关注点分离,使用会使代码更灵活。你写的不正确:
如果创建我无法告诉交易模型它是谁 属于,因为尚未创建支付。另一方面 在创建的情况下,我无法判断在保存时是否出现了问题 交易,以便我可以回滚支付。
在创建事件上调用的回调会获取已知类型的对象。你没有身份证,这是真的。但您仍然可以将此模型与其他模型关联,Eloquent将正确设置外键。只需确保直接使用 associate()之类的关系方法,而不仅仅设置外键值,因为尚未设置ID:
$transaction = new UserTransaction($data);
$transaction->payout()->associate($payout);
$transaction->save();
您还应该查看 Eloquent 提供的 DB :: transaction()包装器。它为您处理开始/提交/回滚,因此需要的代码更少:
DB::transaction(function () {
// do whatever logic needs to be executed in a transaction
});
您可以在此处详细了解 Laravel 中的交易:http://laravel.com/docs/5.1/database#database-transactions