FuelPHP の orm で delete した際に LIMIT が付いてしまってエラーになる場合の対応

最終更新日時:2017-02-08 00:00:00
FuelPHP PostgreSQL SQLite

タイトルの通りです。
コード的には全く問題ないはずなのに、$obj->delete() を実行してエラーが出ることがあります。
エラーメッセージを確認して、DELETE FROM ... を実行時に LIMIT が付いているせいでエラーが出ている場合には、ここで記載する対応が使えます。
ちなみに、delete だけでなく、update も同様です。

ほぼ、FuelPHP x PostgreSQLでDELETEに失敗する場合の対応 の内容そのままですが、一部異なりますので元サイトの内容も参考にしてもらった方がよいと思います。

原因


この問題が起きる原因は、FuelPHP が MySQL を想定して作られているためです。
もし、FuelPHP が PDO ならOKという仕様なのであれば、確実にバグですね(^_^;
PostgreSQLSQLite では UPDATE 文と DELETE 文には LIMIT 指定は出来ません。

ちなみに、DELETE 文にそもそも LIMIT 指定なんてする意味があるのか?という話もありますが、MySQL だとこんな話もあるので。
UPDATEやDELETE時のLIMIT指定のすすめ


対応方法


FuelPHP-1.8 での例です。

上記で書いたように LIMIT 指定が問題なので、勝手に LIMIT を付けられないようにします。
これには、コアクラスをオーバーロードして修正するのがスマートだと思います。

まず、fuel/app/bootstrap.php のオートローダーに、以下のように update と delete 時に読み込むクラスを指定します。

 \Autoloader::add_classes(array(
     'Database_Query_Builder_Delete' => APPPATH.'classes/extensions/core/classes/database/query/builder/delete.php',
     'Database_Query_Builder_Update' => APPPATH.'classes/extensions/core/classes/database/query/builder/update.php',
 ));


次に、上記で指定した PHP ファイルをそれぞれ作成します。
delete.php であれば以下のような感じです。

 class Database_Query_Builder_Delete extends \Fuel\Core\Database_Query_Builder_Delete {
      public function compile($db = null) {
           ...
      }
 }


compile 関数の中身は、以下のコアクラスのものをコピペします。

 fuel/core/classes/database/query/builder/delete.php
 fuel/core/classes/database/query/builder/update.php


このままだとコアクラスそのものなので、以下の LIMIT のところを削除します。

                if ($this->_limit !== null)
                {
                        // Add limiting
                        $query .= ' LIMIT '.$this->_limit;
                }


補足


冒頭で記載した情報元サイトでは、

 if ($this->_limit !== null)




 if ($this->_limit !== NULL && substr($db->_db_type, 0, 6) !== 'sqlite' && substr($db->_db_type, 0, 5) !== 'pgsql')


に修正するような内容になっていますが、私の環境では $db->_db_type というものは存在しなかったのでエラーとなりました。
厳密にはこのように DB の種類によって LIMIT を使い分けした方が良いかもしれませんが、使う DB によってオートローダーで読み込ませるか否かを設定すれば良いだけの話なので、自分としてはバッサリ削除を推奨します(^_^;
ということで、エラーの原因は深く追っていません(/_\*)

お問い合わせは 掲示板 にて。