CodeIgniter4 クエリビルダの「失敗時は FALSE」はいつ発生するのか
はじめに
クエリビルダクラス内 insert
update
等のデータ挿入・更新を扱うメソッドの戻り値について、公式ドキュメントでは以下の様に記載されている。
戻り値: 成功時は TRUE、失敗時は FALSE
以下の様な失敗時のエラーハンドリングの要否が自分の中で曖昧であった為、動作確認を行った。
<?php
namespace App\Controllers;
use App\Controllers\BaseController;
use App\Models\TestTableModel;
class TestController extends BaseController
{
//...
public function store()
{
$model = new TestTableModel();
if ($model->insert($this->request->getPost())) {
// 成功時
} else {
// 失敗時
}
}
}
<?php
namespace App\Models;
class TestTableModel extends Model
{
/**
* @var string
*/
protected string $table = 'test_table';
}
抽象モデルは kenjis さまの CodeIgniter\Modelを使わない場合 を参考にさせていただきました。
ありがとうございます。
<?php
namespace App\Models;
use CodeIgniter\Database\BaseBuilder;
use CodeIgniter\Database\ConnectionInterface;
abstract class Model
{
/**
* @var string
*/
protected string $table;
/**
* @var ConnectionInterface
*/
protected $db;
/**
* @var BaseBuilder
*/
protected BaseBuilder $builder;
public function __construct(?ConnectionInterface $db = null)
{
if ($db === null) {
$this->db = db_connect();
} else {
$this->db = $db;
}
$this->builder = $this->db->table($this->table);
}
/**
* @param array $data
* @return bool
*/
public function insert(array $data): bool
{
return $this->builder->insert($data);
}
/**
* @param array $where
* @param array $data
* @return bool
*/
public function update(array $where, array $data): bool
{
$this->builder->where($where);
return $this->builder->update($data);
}
/**
* @param array $where
* @return bool|string
*/
public function delete(array $where): bool|string
{
$this->builder->where($where);
return $this->builder->delete();
}
}
実行環境
- CodeIgniter 4.2.7
- PostgreSQL 9.2
動作確認
確認を行ったパターン
データベースの接続に失敗した場合
誤ったホスト名を指定
CodeIgniter\Database\Exceptions\DatabaseException #8
Unable to connect to the database.
Main connection [Postgre]: pg_connect(): Unable to connect to PostgreSQL server: could not translate host name "XXX.XXX.XXX.XXX" to address: Unknown host
テーブル名の指定に誤りがある場合
ErrorException
pg_query(): Query failed: ERROR: リレーション"Test_table"は存在しません
存在しないカラムを指定した場合
ErrorException
pg_query(): Query failed: ERROR: リレーション"test_table"の列"hoge"は存在しません
データ挿入時にプライマリキーに値が指定されていない場合
NOT NULL制約違反
ErrorException
pg_query(): Query failed: ERROR: 列"id"内のNULL値はNOT NULL制約違反です
プライマリキーの値が重複した場合
ErrorException
pg_query(): Query failed: ERROR: 重複キーが一意性制約"test_table_pk"に違反しています
確認結果
常に HTTP ステータスコード 500 で例外が投げられていたので
もしや FALSE
が返却されるケースは存在しないのでは?とも一瞬思ったが、よく確認すると development
環境では Config\Database.php
の DBDebug
が TRUE
で判定されていた為であった。
<?php
//...
public $default = [
//...
'DBDebug' => (ENVIRONMENT !== 'production'),
//...
];
production
環境かつ DBDebug
を FALSE
で確認したところ
ErrorException
のケースでは HTTP ステータスコード 200 で FALSE
が返されるようになった。
結論
production
環境かつ Config\Database.php
の DBDebug
が FALSE
の場合には
失敗時のエラーハンドリングを行ったほうが良い。
今回は抽象モデル側でハンドリングを行うこととした。
<?php
namespace App\Models;
use CodeIgniter\Database\BaseBuilder;
use CodeIgniter\Database\ConnectionInterface;
use CodeIgniter\Database\Exceptions\DatabaseException;
abstract class Model
{
/**
* @var string
*/
protected string $table;
/**
* @var ConnectionInterface
*/
protected $db;
/**
* @var BaseBuilder
*/
protected BaseBuilder $builder;
public function __construct(?ConnectionInterface $db = null)
{
if ($db === null) {
$this->db = db_connect();
} else {
$this->db = $db;
}
$this->builder = $this->db->table($this->table);
}
/**
* @param array $data
* @return bool
*/
public function insert(array $data): bool
{
$result = $this->builder->insert($data);
if ($result === false) {
throw new DatabaseException();
} else {
return $result;
}
}
/**
* @param array $where
* @param array $data
* @return bool
*/
public function update(array $where, array $data): bool
{
$this->builder->where($where);
$result = $this->builder->update($data);
if ($result === false) {
throw new DatabaseException();
} else {
return true;
}
}
/**
* @param array $where
* @return bool|string
*/
public function delete(array $where): bool|string
{
$this->builder->where($where);
$result = $this->builder->delete();
if ($result === false) {
throw new DatabaseException();
} else {
return $result;
}
}
}
参考
- Query Builder Class — CodeIgniter 4.2.7 documentation
- Using CodeIgniter’s Model — CodeIgniter 4.2.7 documentation
- Connecting to your Database — CodeIgniter 4.2.7 documentation
- Error Handling — CodeIgniter 4.2.7 documentation
- Codeigniter Model VS Query Builder
- Codeigniter query builder class: How to correctly handle possible unexpected errors?
Discussion
これですが、本番環境だけ振る舞いが変わるのがよくないんですよ。
ほとんどのユーザーは本番環境の振る舞いをテストするテストコードを書いていないでしょうし、返り値のチェックをしていないコードは、本番環境でエラーが発生すれば異常な状態のまま処理が続くことになります。
4.3からは
DBDebug
のデフォルト値が本番環境でも true に変更されます。 また、例外クラスも統一されます。コメントありがとうございます。
わたしの認識が大きく間違っていなかったようで安心しました。
本記事冒頭に v4.3 での更新内容について追記させていただきました。