1: <?php
2:
3: namespace RedBeanPHP\Util;
4:
5: use RedBeanPHP\OODB as OODB;
6: use RedBeanPHP\OODBBean as OODBBean;
7: use RedBeanPHP\RedException as RedException;
8: use RedBeanPHP\Adapter as Adapter;
9:
10: /**
11: * Transaction Helper
12: *
13: * This code was originally part of the facade, however it has
14: * been decided to remove unique features to service classes like
15: * this to make them available to developers not using the facade class.
16: *
17: * Database transaction helper. This is a convenience class
18: * to perform a callback in a database transaction. This class
19: * contains a method to wrap your callback in a transaction.
20: *
21: * @file RedBeanPHP/Util/Transaction.php
22: * @author Gabor de Mooij and the RedBeanPHP Community
23: * @license BSD/GPLv2
24: *
25: * @copyright
26: * copyright (c) G.J.G.T. (Gabor) de Mooij and the RedBeanPHP Community
27: * This source file is subject to the BSD/GPLv2 License that is bundled
28: * with this source code in the file license.txt.
29: */
30: class Transaction
31: {
32: /**
33: * Wraps a transaction around a closure or string callback.
34: * If an Exception is thrown inside, the operation is automatically rolled back.
35: * If no Exception happens, it commits automatically.
36: * It also supports (simulated) nested transactions (that is useful when
37: * you have many methods that needs transactions but are unaware of
38: * each other).
39: *
40: * Example:
41: *
42: * <code>
43: * $from = 1;
44: * $to = 2;
45: * $amount = 300;
46: *
47: * R::transaction(function() use($from, $to, $amount)
48: * {
49: * $accountFrom = R::load('account', $from);
50: * $accountTo = R::load('account', $to);
51: * $accountFrom->money -= $amount;
52: * $accountTo->money += $amount;
53: * R::store($accountFrom);
54: * R::store($accountTo);
55: * });
56: * </code>
57: *
58: * @param Adapter $adapter Database Adapter providing transaction mechanisms.
59: * @param callable $callback Closure (or other callable) with the transaction logic
60: *
61: * @return mixed
62: */
63: public static function transaction( Adapter $adapter, $callback )
64: {
65: if ( !is_callable( $callback ) ) {
66: throw new RedException( 'R::transaction needs a valid callback.' );
67: }
68:
69: static $depth = 0;
70: $result = null;
71: try {
72: if ( $depth == 0 ) {
73: $adapter->startTransaction();
74: }
75: $depth++;
76: $result = call_user_func( $callback ); //maintain 5.2 compatibility
77: $depth--;
78: if ( $depth == 0 ) {
79: $adapter->commit();
80: }
81: } catch ( \Exception $exception ) {
82: $depth--;
83: if ( $depth == 0 ) {
84: $adapter->rollback();
85: }
86: throw $exception;
87: }
88: return $result;
89: }
90: }
91: