/** * Wraps a transaction around a closure or string callback. * If an Exception is thrown inside, the operation is automatically rolled back. * If no Exception happens, it commits automatically. * It also supports (simulated) nested transactions (that is useful when * you have many methods that needs transactions but are unaware of * each other). * * Example: * * <code> * $from = 1; * $to = 2; * $amount = 300; * * R::transaction(function() use($from, $to, $amount) * { * $accountFrom = R::load('account', $from); * $accountTo = R::load('account', $to); * $accountFrom->money -= $amount; * $accountTo->money += $amount; * R::store($accountFrom); * R::store($accountTo); * }); * </code> * * @param Adapter $adapter Database Adapter providing transaction mechanisms. * @param callable $callback Closure (or other callable) with the transaction logic * * @return mixed */ public static function transaction(Adapter $adapter, $callback) { if (!is_callable($callback)) { throw new RedException('R::transaction needs a valid callback.'); } static $depth = 0; $result = null; try { if ($depth == 0) { $adapter->startTransaction(); } $depth++; $result = call_user_func($callback); //maintain 5.2 compatibility $depth--; if ($depth == 0) { $adapter->commit(); } } catch (\Exception $exception) { $depth--; if ($depth == 0) { $adapter->rollback(); } throw $exception; } return $result; }
/** * Log queries * * @param string $event * @param Adapter $info */ public function onEvent($event, $info) { $this->queries[] = $info->getSQL(); }