Laravel 4 - 自动创建其他模型时保存的db事务

时间:2015-08-16 17:52:41

标签: php laravel laravel-4 transactions eloquent

我有两个模型: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;
}

嗯,这个解决方案实际上可行,但如果我需要更新支付怎么办?它会触发保存功能,并且(当然)它会创建一个新的事务。这绝对是错误的。

那么只有将其应用于创建支付的解决方案是什么?

我考虑过创建和创建等事件。在创建的情况下,我无法告诉交易模型它属于谁,因为还没有创建支付。另一方面,在创建的情况下,我无法在保存交易时判断出是否出现问题,以便我可以回滚付款。

那么这里的解决方案是什么?任何帮助表示赞赏。

1 个答案:

答案 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