CodeIgniter4のCodeIgniter\ModelとQuery Builderの関係

この記事は CodeIgniter Advent Calendar 2022 - Qiita の25日目です。

CodeIgniter\Model とは?

CodeIgniter4で追加された機能です。

これは、データベース内の「1つのテーブル」をより便利に扱うために、よく使う便利な機能や追加機能を提供するものです。

以下のような機能があります。

テーブルに主キーがあることが前提であり、複合主キーには現在(v4.3でも)対応していません。

Query Builderとの関係

CodeIgniter\Model は内部的にテーブル名とそのテーブル用の Query Builder を持ちます。

そのテーブル用のQuery Builder

CodeIgniter\Model を継承したモデルクラス内で、以下でそのテーブル用のQuery Builderを取得できます。

$builder = $this->builder();

CodeIgniter\Model は基本的にこのテーブル用のQuery Builderを共有して処理を実行します。

外部からのQuery Builderメソッドの呼び出し

CodeIgniter\Model では、外部からでもQuery Builderメソッドを直接呼び出すことができます。

具体的な実装は以下です。

    /**
     * Provides direct access to method in the builder (if available)
     * and the database connection.
     *
     * @return mixed
     */
    public function __call(string $name, array $params)
    {
        $builder = $this->builder();
        $result  = null;

        if (method_exists($this->db, $name)) {
            $result = $this->db->{$name}(...$params);
        } elseif (method_exists($builder, $name)) {
            $this->checkBuilderMethod($name);

            $result = $builder->{$name}(...$params);
        } else {
            throw new BadMethodCallException('Call to undefined method ' . static::class . '::' . $name);
        }

        if ($result instanceof BaseBuilder) {
            return $this;
        }

        return $result;
    }

CodeIgniter\Model に定義されていないメソッドの場合、

  1. データベース接続オブジェクトに存在するメソッドの場合、それを呼び出す
  2. Query Builderに存在するメソッドの場合、それを呼び出す

そして、結果を返しますが、Query Builderが返ってきた場合は、CodeIgniter\Model 自身を返します。

この実装により、以下のようなコードが実行できるわけです。

$users = $userModel->where('status', 'active')
    ->orderBy('last_login', 'asc')
    ->findAll();

上記で、where()orderBy() はQuery Builderのメソッドで、findAll()CodeIgniter\Model のメソッドです。

しかし、Query BuilderがQuery Builder自身ではなく、何らかの結果を返した場合は、その結果が返されます。

その場合、CodeIgniter\Model のメソッドによって返されるものとは異なり、期待されたものでないかもしれません。Query Builderが結果を返しているので、CodeIgniter\Model のイベントはトリガーされませんし、また、論理削除も考慮されません。

このような期待しない動作を防ぐためには、メソッドチェーンの最後には、Query Builderのメソッドではなく、CodeIgniter\Model のメソッドを指定する必要があります。

結局、どのメソッドが CodeIgniter\Model のメソッドでどのメソッドがQuery Builderのメソッドか区別がつかないと CodeIgniter\Model をうまく使えません。

これが、CodeIgniter\Model がわかりにくいとされる理由です。

この記事は CodeIgniter Advent Calendar 2022 - Qiita の25日目です。

関連

参考

Date: 2022/12/25

Tags: codeigniter, codeigniter4