読者です 読者をやめる 読者になる 読者になる

【CakePHP 2.x】Controller内でトランザクションをかける

CakePHPの公式サイトを確認すると、
モデル内で以下のようにかけるらしい。

<?php
$dataSource->begin();
if (/*すべて成功*/) {
    $dataSource->commit();
} else {
    $dataSource->rollback();
}

でも今回はコントローラーでかけたい。
ということで、トランザクション管理用のモデルを作った。

<?php
App::uses('AppModel', 'Model');
class TransactionManager extends AppModel {
    public $useTable = false;
    public function begin(){
        $dataSource = $this->getDataSource();
        $dataSource->begin($this);
        return $dataSource;
    }
    public function commit($_dataSource){
        $_dataSource->commit();
    }
    public function rollback($_dataSource){
        $_dataSource->rollback();
    }
}

---追記 2015/10/27 ---
上記のコードについてコメント欄で
$_dataSource->commit();
$_dataSource->rollback();
に以下のように $this を付けないとエラーになるとの指摘を受けました。
$_dataSource->commit($this);
$_dataSource->rollback($this);

その後のコメントで、$thisを付けなくても大丈夫とのことでした。

完全な勘ですが、begin() で $this を渡しているので、
$dataSource ではそれが保持されていると思います。
なので、commit() に $this を指定しなくても動作すると思います。
むしろ、commit() に $this を指定すると、コミット対象の $dataSource が
上書きされそう・・・。
---------------------

こーゆーモデルを作ればController側で以下のように使える。

---追記 2014/12/16 ---
コメント欄で
$transaction = $this->TransactionManager->begin();
のスコープについてご指摘をいただいたので修正しました。
---------------------

<?php
$this->loadModel('TransactionManager');
$transaction = $this->TransactionManager->begin();                                                
try{           
 //モデルの処理を書く。
 //ここで複数のモデルを使っても1つのトランザクションで管理されるので問題ない。
    $this->TransactionManager->commit($transaction);
}catch(Exception $e){  
    $this->TransactionManager->rollback($transaction);                                                       
}

$this->loadModel('TransactionManager'); の部分は $uses で定義してもいい。

トランザクション用のモデルを作らずに AppModel.php に作っても動くが、
以下の様な書き方になる。
メソッド名とかモデル名はテキトーです。

<?php
$this->User->begin();
$this->Point->insertData(100);
$this->User->insertData(100);
$this->User->commit();

User, Point という複数のモデルを使っているが、
トランザクションは User モデルでスタートしている。
一応、UserとPointにトランザクションが効くが、
なんかイメージつかない。
Userのみトランザクション対象に思える。

ということで、トランザクション用のモデルを作ったほうがいいかな。