PR

CakePHP 簡単に”実データを削除しない”論理削除を実装する

bakeするとview、edit、deleteするリンクを作ってくれる。でも、そのまま削除されると困ることもある。今回はactiveフラグを1から0に書き換えるように変更するにはどうしたらいいか考える。

◆bakeされたコード

◇viewの1レコードの終りに

<?php echo $html->link(__(‘Delete’, true), array(‘action’ => ‘delete’, $customer[‘Customer’][‘id’]), null, sprintf(__(‘Are you sure you want to delete # %s?’, true), $customer[‘Customer’][‘id’])); ?>

これをクリックすると実行するの?と聞かれ、Yesとすれば削除(=delete action)され、Noとすれば何も起こらない。

◇controllerのdelete actionは次のようになっている

 function delete($id = null) {
  if (!$id) {
   $this->Session->setFlash(__(‘Invalid id for Customer’, true));
   $this->redirect(array(‘action’=>’index’));
  }
  if ($this->Customer->del($id)) {
   $this->Session->setFlash(__(‘Customer deleted’, true));
   $this->redirect(array(‘action’=>’index’));
  }
 }

※これは1.2で作成された。たしか、1.3からはdelは非推奨になった気がする。

スポンサードリンク

◆既にあった!

んー。delにそのまま投げているのか。activeフラグを変更する場合はsaveを呼ばないといけないかな。

危ない危ない。車輪を~するところだった。調べてみると、もっと素晴らしいものがあった。softDeletableBehaviorというのがあるらしい。要するに論理削除してくれるもの。当に今やろうとしているそのもの。早速やってみる:

  1. Soft Deletable Behavior (Articles) | The Bakery, Everything CakePHP から soft_deletable.php をダウンロードする。執筆時1.1.38が最新らしい。
  2. 解凍して、/models/behaviors に入れる。
  3. 実行したいmodelに以下のコードを追加する
    var $actsAs = array(‘SoftDeletable’); 
  4. ない場合はテーブルに以下を追加する
    `deleted` TINYINT NOT NULL ;  
    `deleted_date` DATETIME NULL ; 

◇削除したレコードを取得したいとき:

論理削除したレコードを含めて取得したい場合は find する前に下記のコードを実行します。
$this->Model->enableSoftDeletable(false); 
論理削除を一時的に無効にすることができます。

◇素晴らしい点:

これだけで論理削除が実現できます。find などでも取得されなくなります。

SoftDeletable Behavior を使用すると Model::del は必ず false が返ります。これは Behavior が beforeDelete で削除フラグを立てて、モデルの del メソッドを実行させないために false を返すためです。この点だけ注意が必要です。

◆やってみる

やってみると、動作する。けれど、missing viewと言われる。しばらく悩む。renderを使わないようにするとか、viewを指定するとかやってみるも、ダメ。で、悩んだ挙句、”SoftDeletable Behavior を使用すると Model::del は必ず false が返ります”を思い出す。そうか。デフォルトのbakeコードは、idがあるかチェックして、あれば削除実行、成功すればtrueが返り、処理して完了。だから、falseが返った時の処理がない。だからautoRenderはdelete.ctpがないというのか。ということで、デフォルトのコードに!を追加して逆にしてあげればいいはず。

 function delete($id = null) {
  if (!$id) {
   $this->Session->setFlash(__(‘Invalid id for Customer’, true));
   $this->redirect(array(‘action’=>’index’));
  }
  if ($this->Customer->del($id)===false) {
   $this->Session->setFlash(__(‘Customer deleted’, true));
   $this->redirect(array(‘action’=>’index’));
  }
 }

ってことで期待通りに動作した。ふぅ。

”deleteしないでactiveフラグ変更する”をやろうとしたけれど、便利な論理削除が簡単に組み込めることがわかった。この実装をするとfindでも返らないということなので、findのwhereでactive=1とかしなくてもよくなるっぽい。それに、activeというカラムさえ不要になるんだろう。

参考文献

コメント