CakePHP2のModelは未定義のメソッドを呼ぶとquery()に流す

$this->User->foo();

Userモデルに定義してないfoo()メソッドを呼びます。

Error: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'foo' at line 1

SQL Query: foo

モデルに未定義のメソッドを呼ぶと、そのメソッド名がそのままSQLとして発行されます。当然、そんなSQLは有効じゃないので、エラーになります。
SQL系のエラーなのに、どう見てもメソッド名なのが出てる場合、メソッドをtypoしてる事が多いです。

解説

/**
 * Handles custom method calls, like findBy<field> for DB models,
 * and custom RPC calls for remote data sources.
 *
 * @param string $method Name of method to call.
 * @param array $params Parameters for the method.
 * @return mixed Whatever is returned by called method
 */
  public function __call($method, $params) {
      $result = $this->Behaviors->dispatchMethod($this, $method, $params);
      if ($result !== array('unhandled')) {
          return $result;
      }
      $return = $this->getDataSource()->query($method, $params, $this);
      return $return;
  }

https://github.com/cakephp/cakephp/blob/2.2.7/lib/Cake/Model/Model.php#L775

Modelクラスは、マジックメソッドでfindBy<fieldName>()findAllBy<fieldName>()という、カラムを比較してSELECTする方法があります。これは__call()マジックメソッドで実装されています。未定義のメソッドを呼んだ時__call()が呼ばれますが、コードを見ての通りDboSourceのquery()に処理が移ってます。

      } elseif (count($args) > 1 && (strpos($args[0], 'findBy') === 0 || strpos($args[0], 'findAllBy') === 0)) {

https://github.com/cakephp/cakephp/blob/2.2.7/lib/Cake/Model/Datasource/DboSource.php#L539

ちなみにquery()って名前なのにどうなのかと思うけどfindBy<fieldName>()findAllBy<fieldName>()の分岐はquery()の方に書いてあります。
ともあれ、Modelに未定義のメソッドを呼ぶと、このquery()によってメソッド名がそのままSQLとして発行されるという事になる様です。

環境

環境 バージョン
CakePHP 2.2.7

CakePHP2のModelは未定義のメソッドを呼ぶとquery()に流す」への2件のフィードバック

  1. ooiooxp

    小一時間悩みましたがこの記述で一発解決しました!
    まさかtypoとは・・・。
    ありがとうございました。

  2. kanonji 投稿作成者

    コメントどうもです。
    お役に立ったようで良かったです。
    最初意味が分からず、ハマるんですよね、これ。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>