1: <?php
2:
3: App::uses('CommitOperation', 'Operations.Lib');
4: App::uses('AnonymousFunctionOperation', 'Operations.Lib');
5: App::uses('Model', 'Model');
6: App::uses('TransactionOperation', 'Operations.Lib');
7: App::uses('UndoableOperation', 'Operations.Lib');
8:
9: class TransactionModel extends Model {
10:
11: 12: 13: 14:
15: private static $operation;
16:
17: public function begin() {
18: if (!self::$operation) {
19: self::$operation = new TransactionOperation();
20: parent::begin();
21: }
22: }
23:
24: public function commit() {
25: if (self::$operation) {
26: parent::commit();
27: self::$operation->commit();
28: self::$operation = null;
29: } else {
30: throw new Exception("No commit operation initialized");
31: }
32: }
33:
34: public function rollback() {
35: if (self::$operation) {
36: self::$operation->rollback();
37: parent::rollback();
38: self::$operation = null;
39: }
40: }
41:
42: public function rawSave($data = null, $validate = true, $fieldList = array()) {
43: return parent::save($data, $validate, $fieldList);
44: }
45:
46: public function save($data = null, $validate = true, $fieldList = array()) {
47: return $this->executeOperation(new _TransactionModel_RawSaveOperation(
48: $this, $data, $validate, $fieldList));
49: }
50:
51: public function rawDelete($id = null, $cascade = true) {
52: return parent::delete($id, $cascade);
53: }
54:
55: public function delete($id = null, $cascade = true) {
56: $_this = $this;
57: return $this->executeOperation(new AnonymousFunctionOperation(function() use($_this, $id, $cascade) {
58: return $_this->rawDelete($id, $cascade);
59: }));
60: }
61:
62: public function executeOperation(UndoableOperation $operation) {
63: $commitInitialized = self::$operation != null;
64: if (!$commitInitialized) {
65: $this->begin();
66: }
67:
68: try {
69: if (self::$operation) {
70: $result = self::$operation->execute($operation);
71: } else {
72: $result = $operation->run();
73: }
74: } catch (Exception $ex) {
75: $result = $ex;
76: }
77:
78: if ($result == false || $result instanceof Exception) {
79: if (self::$operation) {
80: self::$operation->rollback();
81: }
82:
83: if ($result instanceof Exception) {
84: throw $result;
85: } else {
86: return false;
87: }
88: } else {
89: if (!$commitInitialized) {
90: $this->commit();
91: }
92: return true;
93: }
94: }
95:
96: }
97:
98: class _TransactionModel_RawSaveOperation implements UndoableOperation {
99:
100: 101: 102: 103:
104: private $model;
105:
106: 107: 108: 109:
110: private $data;
111:
112: public function __construct(Model $model, $data, $validate, $fieldList) {
113: $this->model = $model;
114: $this->data = $data;
115: $this->validate = $validate;
116: $this->fieldList = $fieldList;
117: }
118:
119: public function __toString() {
120: return __CLASS__ . "({$this->model->name}/{$this->model->alias} => " . print_r($this->data, true) . ")".print_r($this->model->validationErrors, true);
121: }
122:
123: public function run() {
124: return $this->model->rawSave($this->data, $this->validate, $this->fieldList);
125: }
126:
127: public function undo() {
128:
129: }
130:
131: }