[CakePHP] Model::deleteAll()の落とし穴 第3の引数

  • このエントリーをはてなブックマークに追加

指定の条件に一致したレコードを一掃するのに便利なModel::deleteAll()。
公式のマニュアルを見ると第1引数に削除対象のレコードの条件、第2引数には関連モデルの削除をするか否かの真偽値となっています。

The Cookbook :: 1.2 Collection :: The Manual :: Developing with CakePHP :: Models :: Deleting Data

ですが、1.2.0.7296 RC2で確認したところ第3の引数が存在しました。

その第3の引数はコールバックメソッドの実行をするか否かの真偽値です。
メソッドの定義部分を見れば一目瞭然です。

ソース解析

cake/libs/model/model.php

/**
 * Allows model records to be deleted based on a set of conditions
 *
 * @param mixed $conditions Conditions to match
 * @param boolean $cascade Set to true to delete records that depend on this record
 * @param boolean $callbacks Run callbacks (not being used)
 * @return boolean True on success, false on failure
 * @access public
 */
    function deleteAll($conditions, $cascade = true, $callbacks = false) {
        if (empty($conditions)) {
            return false;
        }
        $db =& ConnectionManager::getDataSource($this->useDbConfig);

        if (!$cascade && !$callbacks) {
            return $db->delete($this, $conditions);
        } else {
            $ids = Set::extract(
                $this->find('all', array_merge(array('fields' => "{$this->alias}.{$this->primaryKey}", 'recursive' => 0), compact('conditions'))),
                "{n}.{$this->alias}.{$this->primaryKey}"
            );

            if (empty($ids)) {
                return false;
            }

            if ($callbacks) {
                $_id = $this->id;

                foreach ($ids as $id) {
                    $this->delete($id, $cascade);
                }
                $this->id = $_id;
            } else {
                foreach ($ids as $id) {
                    $this->_deleteLinks($id);
                    if ($cascade) {
                        $this->_deleteDependent($id, $cascade);
                    }
                }
                return $db->delete($this, array($this->alias . '.' . $this->primaryKey => $ids));
            }
        }
    }

解説

引数$callbacksになにも渡さないとデフォルト値のfalseが適用されてしまうわけで、コールバックメソッドを呼ばずにレコードを削除します。
これが落とし穴で、要はbeforeDelete()afterDelete()が実行されないので、意図とは違う結果になってしまうこともあり得ます。
俺の場合はbeforeDelete()で関連するファイルを削除する処理を書いていたのですが、それが実行されずに困った事がありました。
みなさんもまだ未完成のマニュアルを過信しないようにして、こういったところを注意しておくべきと思います。

余談

ちなみに先日、株式会社ブルーオーシャンが執筆のCakePHPポケットリファレンスを購入しました。コンパクトだし、内容もうまくまとまっていてなかなか使い勝手が良いリファレンスなのですが、Model::deleteAll()に関する項目は存在しませんでした。Model::saveAll()も同様です。使いやすい本ですが、その辺の情報が欠如しているのが残念です。やはりバージョン1.1の内容も含まれているせいで1.2を主体で書いているわけではないからでしょうね。1.2正式リリース後に再編集して出して欲しい一冊です。

  • このエントリーをはてなブックマークに追加

SNSでもご購読できます。




コメントを残す