CodeIgniter4のCodeIgniter\ModelとQuery Builderの関係
この記事は CodeIgniter Advent Calendar 2022 - Qiita の25日目です。
CodeIgniter\Model とは?
CodeIgniter4で追加された機能です。
これは、データベース内の「1つのテーブル」をより便利に扱うために、よく使う便利な機能や追加機能を提供するものです。
以下のような機能があります。
- 自動データベース接続
- 基本的なCRUDメソッド
- モデル内でのバリデーション
- 自動ページネーション
- 論理削除
- モデルイベント
テーブルに主キーがあることが前提であり、複合主キーには現在(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
に定義されていないメソッドの場合、
- データベース接続オブジェクトに存在するメソッドの場合、それを呼び出す
- 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日目です。
関連
- CodeIgniter\Modelを使わない場合
- CodeIgniter4のCodeIgniter\Model (1)CRUDメソッド
- CodeIgniter4のCodeIgniter\Model (2)Entityクラスの利用
- CodeIgniter4のCodeIgniter\Model (3)モデル内でのバリデーション
- 本当は危ないCodeIgniter4のModel::update()
参考
Date: 2022/12/25