0011996: add fallback app icon
[tine20] / tine20 / Tinebase / TransactionManager.php
1 <?php
2 /**
3  * Tine 2.0
4  * 
5  * @package     Tinebase
6  * @subpackage  TransactionManager
7  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
8  * @copyright   Copyright (c) 2008-2011 Metaways Infosystems GmbH (http://www.metaways.de)
9  * @author      Cornelius Weiss <c.weiss@metaways.de>
10  */
11
12 /**
13  * Transaction Manger for Tine 2.0
14  * 
15  * This is the central class, all transactions within Tine 2.0 must be handled with.
16  * For each supported transactionable (backend) this class start a real transaction on 
17  * the first startTransaction request.
18  * 
19  * Transactions of all transactionable will be commited at once when all requested transactions
20  * are being commited using this class.
21  * 
22  * Transactions of all transactionable will be roll back when one rollBack is requested
23  * using this class.
24  * 
25  * @package     Tinebase
26  * @subpackage  TransactionManager
27  */
28 class Tinebase_TransactionManager
29 {
30     /**
31      * @var array holds all transactionables with open transactions
32      */
33     protected $_openTransactionables = array();
34     
35     /**
36      * @var array list of all open (not commited) transactions
37      */
38     protected $_openTransactions = array();
39     /**
40      * @var Tinebase_TransactionManager
41      */
42     private static $_instance = NULL;
43     
44     /**
45      * don't clone. Use the singleton.
46      */
47     private function __clone()
48     {
49         
50     }
51     
52     /**
53      * constructor
54      */
55     private function __construct()
56     {
57         
58     }
59     
60     /**
61      * @return Tinebase_TransactionManager
62      */
63     public static function getInstance() 
64     {
65         if (self::$_instance === NULL) {
66             self::$_instance = new Tinebase_TransactionManager;
67         }
68         
69         return self::$_instance;
70     }
71     
72     /**
73      * starts a transaction
74      *
75      * @param   mixed $_transactionable
76      * @return  string transactionId
77      * @throws  Tinebase_Exception_UnexpectedValue
78      */
79     public function startTransaction($_transactionable)
80     {
81         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . "  startTransaction request");
82         if (! in_array($_transactionable, $this->_openTransactionables)) {
83             if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . "  new transactionable. Starting transaction on this resource");
84             if ($_transactionable instanceof Zend_Db_Adapter_Abstract) {
85                 $_transactionable->beginTransaction();
86             } else {
87                 $this->rollBack();
88                 throw new Tinebase_Exception_UnexpectedValue('Unsupported transactionable!');
89             }
90             array_push($this->_openTransactionables, $_transactionable);
91         }
92         
93         $transactionId = Tinebase_Record_Abstract::generateUID();
94         array_push($this->_openTransactions, $transactionId);
95         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . "  queued transaction with id $transactionId");
96         
97         return $transactionId;
98     }
99     
100     /**
101      * commits a transaction
102      *
103      * @param  string $_transactionId
104      * @return void
105      */
106     public function commitTransaction($_transactionId)
107     {
108         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . "  commitTransaction request for $_transactionId");
109          $transactionIdx = array_search($_transactionId, $this->_openTransactions);
110          if ($transactionIdx !== false) {
111              unset($this->_openTransactions[$transactionIdx]);
112          }
113          
114          $numOpenTransactions = count($this->_openTransactions);
115          if ($numOpenTransactions === 0) {
116              if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . "  no more open transactions in queue commiting all transactionables");
117              foreach ($this->_openTransactionables as $transactionableIdx => $transactionable) {
118                  if ($transactionable instanceof Zend_Db_Adapter_Abstract) {
119                      $transactionable->commit();
120                  }
121              }
122              $this->_openTransactionables = array();
123              $this->_openTransactions = array();
124          } else {
125              if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . "  commiting defered, as there are still $numOpenTransactions in the queue");
126          }
127     }
128     
129     /**
130      * perform rollBack on all transactionables with open transactions
131      * 
132      * @return void
133      */
134     public function rollBack()
135     {
136         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . "  rollBack request, rollBack all transactionables");
137         foreach ($this->_openTransactionables as $transactionable) {
138             if ($transactionable instanceof Zend_Db_Adapter_Abstract) {
139                 $transactionable->rollBack();
140             }
141         }
142         $this->_openTransactionables = array();
143         $this->_openTransactions = array();
144     }
145 }