CodeIgniterのモデルの使用

モデル

CodeIgniterのモデルは、データベース内の**単一テーブル**の操作をより便利にするために一般的に使用される便利な機能と追加機能を提供します。

レコードの検索、レコードの更新、レコードの削除など、データベーステーブルとやり取りする標準的な方法の多くについて、すぐに使えるヘルパーメソッドが用意されています。

モデルへのアクセス

モデルは通常、**app/Models**ディレクトリに保存されます。ディレクトリ内の場所と一致する名前空間を持つ必要があります(例:namespace App\Models)。

新しいインスタンスを作成するか、model()ヘルパー関数を使用して、クラス内でモデルにアクセスできます。

<?php

// Create a new class manually.
$userModel = new \App\Models\UserModel();

// Create a shared instance of the model.
$userModel = model('UserModel');
// or
$userModel = model('App\Models\UserModel');
// or
$userModel = model(\App\Models\UserModel::class);

// Create a new class with the model() function.
$userModel = model('UserModel', false);

// Create shared instance with a supplied database connection.
$db        = db_connect('custom');
$userModel = model('UserModel', true, $db);

model()は内部的にFactories::models()を使用します。最初の引数の詳細については、クラスの読み込みを参照してください。

CodeIgniterのモデル

CodeIgniterは、いくつかの優れた機能を提供するモデルクラスを提供しています。これには以下が含まれます。

このクラスは、独自のモデルを構築するための堅実な基盤を提供し、アプリケーションのモデルレイヤーを迅速に構築できます。

モデルの作成

CodeIgniterのモデルを利用するには、CodeIgniter\Modelを拡張する新しいモデルクラスを作成するだけです。

<?php

namespace App\Models;

use CodeIgniter\Model;

class UserModel extends Model
{
    // ...
}

この空のクラスは、データベース接続、QueryBuilder、およびいくつかの追加の便利なメソッドへの便利なアクセスを提供します。

initialize()

モデルに追加の設定が必要な場合は、initialize()メソッドを拡張できます。これは、モデルのコンストラクタの直後に実行されます。これにより、コンストラクタパラメーターを繰り返すことなく、追加の手順を実行できます(たとえば、他のモデルを拡張する場合など)。

<?php

namespace App\Models;

use Modules\Authentication\Models\UserAuthModel;

class UserModel extends UserAuthModel
{
    /**
     * Called during initialization. Appends
     * our custom field to the module's model.
     */
    protected function initialize()
    {
        $this->allowedFields[] = 'middlename';
    }
}

データベースへの接続

クラスが最初にインスタンス化されるときに、コンストラクタにデータベース接続インスタンスが渡されず、モデルクラスに$DBGroupプロパティが設定されていない場合、データベース設定で設定されているデフォルトのデータベースグループに自動的に接続されます。

モデルごとに使用するグループを変更するには、$DBGroupプロパティをクラスに追加します。これにより、モデル内の$this->dbへの参照は、適切な接続を通じて行われます。

<?php

namespace App\Models;

use CodeIgniter\Model;

class UserModel extends Model
{
    protected $DBGroup = 'group_name';
}

「group_name」をデータベース設定ファイルから定義されたデータベースグループの名前に置き換えます。

モデルの設定

モデルクラスには、クラスのメソッドをシームレスに動作させるために設定できるいくつかのオプションがあります。最初の2つは、使用するテーブルと必要なレコードをどのように見つけるかを決定するために、すべてのCRUDメソッドで使用されます。

<?php

namespace App\Models;

use CodeIgniter\Model;

class UserModel extends Model
{
    protected $table      = 'users';
    protected $primaryKey = 'id';

    protected $useAutoIncrement = true;

    protected $returnType     = 'array';
    protected $useSoftDeletes = true;

    protected $allowedFields = ['name', 'email'];

    protected bool $allowEmptyInserts = false;

    // Dates
    protected $useTimestamps = false;
    protected $dateFormat    = 'datetime';
    protected $createdField  = 'created_at';
    protected $updatedField  = 'updated_at';
    protected $deletedField  = 'deleted_at';

    // Validation
    protected $validationRules      = [];
    protected $validationMessages   = [];
    protected $skipValidation       = false;
    protected $cleanValidationRules = true;

    // Callbacks
    protected $allowCallbacks = true;
    protected $beforeInsert   = [];
    protected $afterInsert    = [];
    protected $beforeUpdate   = [];
    protected $afterUpdate    = [];
    protected $beforeFind     = [];
    protected $afterFind      = [];
    protected $beforeDelete   = [];
    protected $afterDelete    = [];
}

$table

このモデルが主に使用するデータベーステーブルを指定します。これは、組み込みのCRUDメソッドにのみ適用されます。独自のクエリでは、このテーブルのみを使用する必要はありません。

$primaryKey

このテーブルのレコードを一意に識別する列の名前です。これは、データベースで指定された主キーと必ずしも一致する必要はありませんが、find()などのメソッドで、指定された値を照合する列を知るために使用されます。

注記

すべてのモデルには、すべての機能を期待通りに動作させるために$primaryKeyを指定する必要があります。

$useAutoIncrement

$primaryKeyに自動インクリメント機能を使用するかどうかを指定します。falseに設定すると、テーブルのすべてのレコードの主キー値を提供する必要があります。この機能は、1対1の関係を実装する場合や、モデルにUUIDを使用する場合に役立つ場合があります。デフォルト値はtrueです。

注記

$useAutoIncrementfalseに設定する場合は、データベースの主キーをuniqueに設定してください。これにより、モデルのすべての機能が以前と同じように動作することが保証されます。

$returnType

モデルのCRUDメソッドは、Resultオブジェクトではなく、結果データを自動的に返すことで、作業を軽減します。この設定により、返されるデータの型を定義できます。有効な値は「**array**」(デフォルト)、「**object**」、またはResultオブジェクトのgetCustomResultObject()メソッドで使用できる**クラスの完全修飾名**です。クラスの特別な::class定数を使用すると、ほとんどのIDEで名前の自動補完が可能になり、リファクタリングなどの機能によりコードの理解が向上します。

$useSoftDeletes

真の場合、任意のdelete()メソッド呼び出しは、行を実際に削除する代わりに、データベース内のdeleted_atを設定します。これは、データが他の場所で参照される可能性がある場合にデータを保存したり、「ごみ箱」オブジェクトを復元できるオブジェクトを維持したり、セキュリティトレイルの一部として単にデータを保存したりするために使用できます。withDeleted()メソッドを**find*()**メソッドを呼び出す前に呼び出さない限り、真の場合、**find*()**メソッドは削除されていない行のみを返します。

これには、モデルの$dateFormat設定に従って、データベースにDATETIMEフィールドまたはINTEGERフィールドが必要です。デフォルトのフィールド名はdeleted_atですが、この名前は$deletedFieldプロパティを使用して任意の名前に設定できます。

重要

deleted_atフィールドはNULL可能である必要があります。

$allowedFields

この配列は、save()insert()、またはupdate()メソッド中に設定できるフィールド名で更新する必要があります。これ以外のフィールド名は破棄されます。これは、フォームからの入力を受け取り、それをすべてモデルに渡すことで発生する可能性のある大量代入の脆弱性を防ぐのに役立ちます。

注記

$primaryKeyフィールドは、許可されたフィールドであってはなりません。

$allowEmptyInserts

バージョン4.3.0の新機能。

空のデータの挿入を許可するかどうか。デフォルト値はfalseであり、空のデータの挿入を試行すると、「挿入するデータがありません。」という例外が発生します。

allowEmptyInserts()メソッドを使用してこの設定を変更することもできます。

日付

$useTimestamps

このブール値は、現在の日付がすべての挿入と更新に自動的に追加されるかどうかを決定します。trueの場合、$dateFormatで指定された形式で現在時刻が設定されます。これには、テーブルに適切なデータ型で**created_at**、**updated_at**、**deleted_at**という名前の列がある必要があります。$createdField$updatedField、および$deletedFieldも参照してください。

$dateFormat

この値は$useTimestampsおよび$useSoftDeletesと連携して、正しいタイプのデータ値がデータベースに挿入されるようにします。デフォルトでは、DATETIME値が作成されますが、有効なオプションは'datetime''date'、または'int'(PHPタイムスタンプ)です。$dateFormatが無効または存在しない場合に$useSoftDeletesまたは$useTimestampsを使用すると、例外が発生します。

$createdField

データレコード作成タイムスタンプに使用するデータベースフィールドを指定します。$useTimestampsが有効になっている場合でも、更新を回避するには、空文字列('')に設定します。

$updatedField

データレコード更新タイムスタンプを保持するために使用するデータベースフィールドを指定します。$useTimestampsが有効になっている場合でも、更新を回避するには、空文字列('')に設定します。

$deletedField

ソフト削除に使用するデータベースフィールドを指定します。$useSoftDeletesを参照してください。

検証

$validationRules

ルールの保存方法で説明されている検証ルールの配列、または同じセクションで説明されている検証グループの名前を含む文字列のいずれかを含みます。以下で詳しく説明します。

$validationMessages

カスタムエラーメッセージの設定で説明されているように、検証中に使用するカスタムエラーメッセージの配列を含みます。以下で詳しく説明します。

$skipValidation

すべての**挿入**と**更新**で検証をスキップするかどうか。デフォルト値はfalseであり、データは常に検証を試みます。これは主にskipValidation()メソッドで使用されますが、trueに変更して、このモデルが検証されないようにすることもできます。

$cleanValidationRules

渡されたデータに存在しない検証ルールを削除するかどうか。これは**更新**で使用されます。デフォルト値はtrueであり、渡されたデータに存在しないフィールドの検証ルールは、検証前に(一時的に)削除されます。これは、一部のフィールドのみを更新する場合の検証エラーを回避するためです。

cleanRules()メソッドを使用して値を変更することもできます。

注記

v4.2.7より前では、バグのため$cleanValidationRulesは機能しませんでした。

コールバック

$allowCallbacks

以下で定義されたコールバックを使用するかどうか。 モデルイベントを参照してください。

$beforeInsert
$afterInsert
$beforeUpdate
$afterUpdate
$beforeFind
$afterFind
$beforeDelete
$afterDelete
$beforeInsertBatch
$afterInsertBatch
$beforeUpdateBatch
$afterUpdateBatch

これらの配列を使用すると、プロパティ名に指定された時間にデータで実行されるコールバックメソッドを指定できます。モデルイベントを参照してください。

データの操作

データの検索

find()insert()update()delete()など、テーブルの基本的なCRUD操作を行うためのいくつかの関数が提供されています。

find()

主キーが最初の引数として渡された値と一致する単一行を返します。

<?php

$user = $userModel->find($user_id);

値は$returnTypeで指定された形式で返されます。

単一のprimaryKey値ではなく、primaryKey値の配列を渡すことで、複数の行を返すように指定できます。

<?php

$users = $userModel->find([1, 2, 3]);

注記

パラメータが渡されない場合、find()はそのモデルのテーブルのすべての行を返し、findAll()のように機能しますが、それほど明示的ではありません。

findColumn()

NULLまたは列値のインデックス付き配列を返します。

<?php

$user = $userModel->findColumn($column_name);

$column_nameは単一の列の名前である必要があります。そうでない場合、DataExceptionが発生します。

findAll()

すべての結果を返します。

<?php

$users = $userModel->findAll();

このクエリは、必要に応じてこのメソッドを呼び出す前にクエリビルダーコマンドを挿入することで変更できます。

<?php

$users = $userModel->where('active', 1)->findAll();

それぞれ1番目と2番目のパラメータとして、制限値とオフセット値を渡すことができます。

<?php

$users = $userModel->findAll($limit, $offset);

first()

結果セットの最初の行を返します。これはクエリビルダーと組み合わせて使用​​するのが最適です。

<?php

$user = $userModel->where('deleted', 0)->first();

withDeleted()

$useSoftDeletesがtrueの場合、**find*()**メソッドはdeleted_at IS NOT NULLの行を返しません。これを一時的に上書きするには、**find*()**メソッドを呼び出す前にwithDeleted()メソッドを使用できます。

<?php

// Only gets non-deleted rows (deleted = 0)
$activeUsers = $userModel->findAll();

// Gets all rows
$allUsers = $userModel->withDeleted()->findAll();

onlyDeleted()

withDeleted()は削除された行と削除されていない行の両方を返すのに対し、このメソッドは次の**find*()**メソッドを変更して、ソフト削除された行のみを返すようにします。

<?php

$deletedUsers = $userModel->onlyDeleted()->findAll();

データの保存

insert()

最初の引数は、データベースに新しいデータ行を作成するためのデータの連想配列です。配列の代わりにオブジェクトが渡されると、配列に変換しようとします。

配列のキーは$tableの列名と一致する必要があり、配列の値はそのキーに保存する値です。

オプションの2番目の引数はブール型であり、falseに設定されている場合、メソッドはクエリが成功したか失敗したかを示すブール値を返します。

getInsertID()メソッドを使用して、最後に挿入された行の主キーを取得できます。

<?php

$data = [
    'username' => 'darth',
    'email'    => '[email protected]',
];

// Inserts data and returns inserted row's primary key
$userModel->insert($data);

// Inserts data and returns true on success and false on failure
$userModel->insert($data, false);

// Returns inserted row's primary key
$userModel->getInsertID();

allowEmptyInserts()

バージョン4.3.0の新機能。

allowEmptyInserts() メソッドを使用すると、空のデータの挿入が可能です。デフォルトでは、空のデータの挿入を試行すると、モデルは例外をスローします。しかし、このメソッドを呼び出すと、そのチェックは実行されなくなります。

<?php

$userModel->allowEmptyInserts()->insert([]);

$allowEmptyInserts プロパティを使用して、この設定を変更することもできます。

allowEmptyInserts(false) を呼び出すことで、チェックを再び有効にできます。

update()

データベース内の既存のレコードを更新します。最初の引数は、更新するレコードの$primaryKeyです。2番目の引数として、データの連想配列を渡します。配列のキーは$table内のカラム名と一致する必要があり、配列の値はそのキーに保存する値になります。

<?php

$data = [
    'username' => 'darth',
    'email'    => '[email protected]',
];

$userModel->update($id, $data);

重要

v4.3.0以降、このメソッドはWHERE句のないSQL文を生成した場合、DatabaseExceptionを発生させます。以前のバージョンでは、$primaryKeyを指定せずに呼び出され、WHERE句のないSQL文が生成された場合でも、クエリは実行され、テーブル内のすべてのレコードが更新されていました。

最初の引数に主キーの配列を渡すことで、一度に複数のレコードを更新できます。

<?php

$data = [
    'active' => 1,
];

$userModel->update([1, 2, 3], $data);

より柔軟なソリューションが必要な場合は、パラメータを空のままにすることができます。これはクエリビルダーのupdateコマンドのように機能しますが、バリデーション、イベントなどの追加機能が備わっています。

<?php

$userModel
    ->whereIn('id', [1, 2, 3])
    ->set(['active' => 1])
    ->update();

save()

これはinsert()update()メソッドのラッパーで、主キー値と一致する配列キーがあるかどうかを基に、レコードの挿入または更新を自動的に処理します。

<?php

// Defined as a model property
$primaryKey = 'id';

// Does an insert()
$data = [
    'username' => 'darth',
    'email'    => '[email protected]',
];

$userModel->save($data);

// Performs an update, since the primary key, 'id', is found.
$data = [
    'id'       => 3,
    'username' => 'darth',
    'email'    => '[email protected]',
];
$userModel->save($data);

saveメソッドは、単純なオブジェクトでないことを認識し、そのpublicおよびprotectedプロパティを配列に取り込んで、適切なinsertまたはupdateメソッドに渡すことで、カスタムクラスの結果オブジェクトの操作をはるかに簡単にします。これにより、エンティティクラスを非常にクリーンな方法で操作できます。エンティティクラスは、ユーザー、ブログ投稿、ジョブなど、オブジェクトタイプの単一インスタンスを表す単純なクラスです。このクラスは、特定の方法で要素をフォーマットするなど、オブジェクト自体を取り巻くビジネスロジックを維持する役割を担っています。データベースへの保存方法については何も知る必要はありません。最も単純な形では、次のようになります。

<?php

namespace App\Entities;

class Job
{
    protected $id;
    protected $name;
    protected $description;

    public function __get($key)
    {
        if (property_exists($this, $key)) {
            return $this->{$key};
        }
    }

    public function __set($key, $value)
    {
        if (property_exists($this, $key)) {
            $this->{$key} = $value;
        }
    }
}

これと連携する非常に単純なモデルは次のようになります。

<?php

namespace App\Models;

use CodeIgniter\Model;

class JobModel extends Model
{
    protected $table         = 'jobs';
    protected $returnType    = \App\Entities\Job::class;
    protected $allowedFields = [
        'name', 'description',
    ];
}

このモデルはjobsテーブルのデータを使用し、すべての結果をApp\Entities\Jobのインスタンスとして返します。そのレコードをデータベースに永続化する必要がある場合は、カスタムメソッドを作成するか、モデルのsave()メソッドを使用してクラスを検査し、publicおよびprivateプロパティを取得してデータベースに保存する必要があります。

<?php

// Retrieve a Job instance
$job = $model->find(15);

// Make some changes
$job->name = 'Foobar';

// Save the changes
$model->save($job);

注記

エンティティを多く使用する場合、CodeIgniterはいくつかの便利な機能を提供する組み込みのEntityクラスを提供しており、エンティティの開発を簡素化します。

データの削除

delete()

主キー値を最初の引数として受け取り、モデルのテーブルから一致するレコードを削除します。

<?php

$userModel->delete(12);

モデルの$useSoftDeletes値がtrueの場合、deleted_atを現在の日時に更新します。2番目の引数をtrueに設定することで、強制的に完全に削除できます。

最初の引数に主キーの配列を渡すことで、一度に複数のレコードを削除できます。

<?php

$userModel->delete([1, 2, 3]);

パラメータを渡さない場合、クエリビルダーのdeleteメソッドのように動作し、事前にwhere呼び出しが必要です。

<?php

$userModel->where('id', 12)->delete();

purgeDeleted()

‘deleted_at IS NOT NULL’のすべての行を完全に削除することで、データベーステーブルをクリーンアップします。

<?php

$userModel->purgeDeleted();

モデル内バリデーション

データのバリデーション

多くの人にとって、モデルでデータをバリデーションすることは、コードの重複を避けて、データを単一の標準に維持する好ましい方法です。insert()update()、またはsave()メソッドを使用して、データベースに保存する前にすべてのデータを自動的にバリデーションする方法をモデルクラスは提供します。

重要

データを更新する場合、デフォルトでは、モデルクラスのバリデーションは提供されたフィールドのみをバリデーションします。これは、一部のフィールドのみを更新する場合のバリデーションエラーを回避するためです。

しかし、これはrequired*ルールが更新時に期待通りに動作しないことを意味します。必須フィールドをチェックする必要がある場合は、設定で動作を変更できます。詳細は$cleanValidationRulesを参照してください。

バリデーションルールの設定

最初のステップは、適用するフィールドとルールを$validationRulesクラスプロパティに入力することです。使用するカスタムエラーメッセージがある場合は、$validationMessages配列に配置します。

<?php

namespace App\Models;

use CodeIgniter\Model;

class UserModel extends Model
{
    protected $validationRules = [
        'username'     => 'required|max_length[30]|alpha_numeric_space|min_length[3]',
        'email'        => 'required|max_length[254]|valid_email|is_unique[users.email]',
        'password'     => 'required|max_length[255]|min_length[8]',
        'pass_confirm' => 'required_with[password]|max_length[255]|matches[password]',
    ];
    protected $validationMessages = [
        'email' => [
            'is_unique' => 'Sorry. That email has already been taken. Please choose another.',
        ],
    ];
}

ルールとエラーメッセージをバリデーション設定ファイル内で整理する方が良い場合は、それを行い、$validationRulesに作成したバリデーションルールグループの名前を設定するだけです。

<?php

namespace App\Models;

use CodeIgniter\Model;

class UserModel extends Model
{
    protected $validationRules = 'users';
}

関数でフィールドにバリデーションルールを設定するもう1つの方法。

class CodeIgniter\Model
CodeIgniter\Model::setValidationRule($field, $fieldRules)
パラメータ:
  • $field (string) –

  • $fieldRules (array) –

この関数は、フィールドのバリデーションルールを設定します。

使用例

<?php

$fieldName  = 'username';
$fieldRules = 'required|max_length[30]|alpha_numeric_space|min_length[3]';

$model->setValidationRule($fieldName, $fieldRules);
CodeIgniter\Model::setValidationRules($validationRules)
パラメータ:
  • $validationRules (array) –

この関数は、バリデーションルールを設定します。

使用例

<?php

$validationRules = [
    'username' => 'required|max_length[30]|alpha_numeric_space|min_length[3]',
    'email'    => [
        'rules'  => 'required|max_length[254]|valid_email|is_unique[users.email]',
        'errors' => [
            'required' => 'We really need your email.',
        ],
    ],
];
$model->setValidationRules($validationRules);

関数でフィールドにバリデーションメッセージを設定するもう1つの方法。

CodeIgniter\Model::setValidationMessage($field, $fieldMessages)
パラメータ:
  • $field (string) –

  • $fieldMessages (array) –

この関数は、フィールドごとのエラーメッセージを設定します。

使用例

<?php

$fieldName              = 'name';
$fieldValidationMessage = [
    'required' => 'Your name is required here',
];
$model->setValidationMessage($fieldName, $fieldValidationMessage);
CodeIgniter\Model::setValidationMessages($fieldMessages)
パラメータ:
  • $fieldMessages (array) –

この関数は、フィールドメッセージを設定します。

使用例

<?php

$fieldValidationMessage = [
    'name' => [
        'required'   => 'Your baby name is missing.',
        'min_length' => 'Too short, man!',
    ],
];
$model->setValidationMessages($fieldValidationMessage);

バリデーション結果の取得

これで、insert()update()、またはsave()メソッドを呼び出すたびに、データがバリデーションされます。失敗した場合は、モデルはブール値**false**を返します。

バリデーションエラーの取得

errors()メソッドを使用して、バリデーションエラーを取得できます。

<?php

if ($model->save($data) === false) {
    return view('updateUser', ['errors' => $model->errors()]);
}

これは、フィールド名とその関連するエラーを含む配列を返します。これは、フォームの一番上にすべてのエラーを表示するか、個別に表示するために使用できます。

<?php if (! empty($errors)): ?>
    <div class="alert alert-danger">
    <?php foreach ($errors as $field => $error): ?>
        <p><?= esc($error) ?></p>
    <?php endforeach ?>
    </div>
<?php endif ?>

バリデーションルールの取得

モデルのバリデーションルールは、validationRulesプロパティにアクセスすることで取得できます。

<?php

$rules = $model->validationRules;

オプションを指定してアクセサメソッドを直接呼び出すことで、そのルールのサブセットを取得することもできます。

<?php

$rules = $model->getValidationRules($options);

$optionsパラメータは、キーが'except'または'only'のいずれかで、値に関心のあるフィールド名の配列を持つ連想配列です。

<?php

// get the rules for all but the "username" field
$rules = $model->getValidationRules(['except' => ['username']]);
// get the rules for only the "city" and "state" fields
$rules = $model->getValidationRules(['only' => ['city', 'state']]);

バリデーションプレースホルダー

モデルは、渡されたデータに基づいてルールの部分を置き換えるための簡単なメソッドを提供します。これはかなり分かりにくいように聞こえますが、is_uniqueバリデーションルールで特に便利です。プレースホルダーは、$dataとして渡されたフィールド(または配列キー)の名前を波括弧で囲んだものです。これは、一致する入力フィールドの**値**に置き換えられます。例で説明します。

<?php

namespace App\Models;

use CodeIgniter\Model;

class MyModel extends Model
{
    protected $validationRules = [
        'id'    => 'max_length[19]|is_natural_no_zero',
        'email' => 'required|max_length[254]|valid_email|is_unique[users.email,id,{id}]',
    ];
}

注記

v4.3.5以降、プレースホルダーフィールド(id)のバリデーションルールを設定する必要があります。

このルールのセットでは、プレースホルダーの値と一致するidを持つ行を除いて、メールアドレスがデータベース内で一意であることを示しています。フォームのPOSTデータが次のようであったと仮定します。

<?php

$_POST = [
    'id'    => 4,
    'email' => '[email protected]',
];

すると、{id}プレースホルダーは数値**4**に置き換えられ、この修正されたルールが得られます。

<?php

namespace App\Models;

use CodeIgniter\Model;

class MyModel extends Model
{
    protected $validationRules = [
        'id'    => 'max_length[19]|is_natural_no_zero',
        'email' => 'required|max_length[254]|valid_email|is_unique[users.email,id,4]',
    ];
}

そのため、メールの一意性を検証する際に、id=4を持つデータベースの行は無視されます。

注記

v4.3.5以降、プレースホルダー(`id`)の値が検証に合格しなかった場合、プレースホルダーは置換されません。

これは、ランタイムでより動的なルールを作成するためにも使用できます。ただし、渡される動的なキーがフォームデータと競合しないように注意する必要があります。

フィールドの保護

マスアサインメント攻撃からの保護に役立つため、Modelクラスは、挿入と更新時に変更できるすべてのフィールド名を$allowedFieldsクラスプロパティにリストすることを**必須**としています。これらに追加で提供されたデータは、データベースに到達する前に削除されます。これは、タイムスタンプや主キーが変更されないことを保証するのに最適です。

<?php

namespace App\Models;

use CodeIgniter\Model;

class MyModel extends Model
{
    protected $allowedFields = ['name', 'email', 'address'];
}

これらの要素を変更する必要がある場合もあります。これは、テスト、マイグレーション、またはシード中に発生することがよくあります。このような場合は、保護のオンとオフを切り替えることができます。

<?php

$model->protect(false)
    ->insert($data)
    ->protect(true);

ランタイムでの戻り値タイプの変更

find*()メソッドを使用する場合、クラスプロパティ$returnTypeとして、データの戻り値形式を指定できます。ただし、異なる形式でデータを取得したい場合もあるでしょう。Modelは、まさにそれを行うためのメソッドを提供します。

注記

これらのメソッドは、次のfind*()メソッド呼び出しの戻り値タイプのみを変更します。その後、デフォルト値にリセットされます。

asArray()

次のfind*()メソッドからのデータを連想配列として返します。

<?php

$users = $userModel->asArray()->where('status', 'active')->findAll();

asObject()

次のfind*()メソッドからのデータを標準オブジェクトまたはカスタムクラスインスタンスとして返します。

<?php

// Return as standard objects
$users = $userModel->asObject()->where('status', 'active')->findAll();

// Return as custom class instances
$users = $userModel->asObject('User')->where('status', 'active')->findAll();

大量データの処理

大量のデータを処理する必要があり、メモリ不足のリスクがある場合があります。これを簡単に処理するために、chunk()メソッドを使用して、より小さなデータチャンクを取得し、その上で作業を行うことができます。最初の引数は、単一のチャンクで取得する行数です。2番目の引数は、データの各行に対して呼び出されるクロージャです。

これは、cronジョブ、データエクスポート、その他の大量タスクで最も効果的に使用されます。

<?php

$userModel->chunk(100, static function ($data) {
    // do something.
    // $data is a single row of data.
});

クエリビルダーの使用

モデルのテーブルに対するクエリビルダーの取得

CodeIgniter Modelには、そのモデルのデータベース接続に対するクエリビルダーのインスタンスが1つあります。必要に応じて、クエリビルダーの**共有**インスタンスにアクセスできます。

<?php

$builder = $userModel->builder();

このビルダーは、モデルの$tableを使用して既に設定されています。

注記

クエリビルダーのインスタンスを取得したら、クエリビルダーのメソッドを呼び出すことができます。ただし、クエリビルダーはモデルではないため、モデルのメソッドを呼び出すことはできません。

別のテーブルに対するクエリビルダーの取得

別のテーブルにアクセスする必要がある場合は、クエリビルダーの別のインスタンスを取得できます。テーブル名をパラメーターとして渡しますが、これは**共有**インスタンスを返さないことに注意してください。

<?php

$groupBuilder = $userModel->builder('groups');

クエリビルダーとモデルのメソッドの混合

クエリビルダーのメソッドとモデルのCRUDメソッドを同じチェーン呼び出しで使用して、非常にエレガントな使用方法を実現できます。

<?php

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

この場合、モデルによって保持されているクエリビルダーの共有インスタンスで動作します。

重要

モデルはクエリビルダーに対する完璧なインターフェースを提供しません。モデルとクエリビルダーは、目的の異なる別々のクラスです。同じデータが返されるとは期待しないでください。

クエリビルダーが結果を返す場合、結果はそのまま返されます。その場合、結果はモデルのメソッドによって返される結果とは異なり、期待したものと異なる場合があります。モデルのイベントはトリガーされません。

予期しない動作を防ぐために、結果を返すクエリビルダーのメソッドを使用せず、メソッドチェーンの最後にモデルのメソッドを指定してください。

注記

モデルのデータベース接続にもシームレスにアクセスできます。

<?php

$user_name = $userModel->escape($name);

モデルイベント

モデルの実行中には、実行する複数のコールバックメソッドを指定できるいくつかのポイントがあります。これらのメソッドは、データの正規化、パスワードのハッシュ、関連エンティティの保存などに使用できます。

モデルの実行における以下のポイントに影響を与えることができ、それぞれクラスプロパティを介して行われます。

注記

$beforeInsertBatch$afterInsertBatch$beforeUpdateBatch、および$afterUpdateBatchは、v4.3.0以降で使用できます。

コールバックの定義

コールバックを指定するには、最初に使用するモデルに新しいクラスメソッドを作成します。

このクラスメソッドは、常に$data配列を唯一のパラメーターとして受け取ります。

$data配列の正確な内容はイベントによって異なりますが、元のメソッドに渡された主要なデータを含むdataという名前のキーは常に含まれています。insert*()またはupdate*()メソッドの場合、それはデータベースに挿入されているキーと値のペアです。メインの$data配列には、メソッドに渡された他の値も含まれており、イベントパラメーターで詳しく説明されています。

コールバックメソッドは、他のコールバックが完全な情報を持つように、元の$data配列を返す必要があります。

<?php

namespace App\Models;

use CodeIgniter\Model;

class MyModel extends Model
{
    protected function hashPassword(array $data)
    {
        if (! isset($data['data']['password'])) {
            return $data;
        }

        $data['data']['password_hash'] = password_hash($data['data']['password'], PASSWORD_DEFAULT);
        unset($data['data']['password']);

        return $data;
    }
}

実行するコールバックの指定

メソッド名を適切なクラスプロパティ($beforeInsert$afterUpdateなど)に追加することにより、コールバックの実行時期を指定します。複数のコールバックを単一のイベントに追加でき、それらは順番に処理されます。複数のイベントで同じコールバックを使用できます。

<?php

namespace App\Models;

use CodeIgniter\Model;

class MyModel extends Model
{
    protected $beforeInsert = ['hashPassword'];
    protected $beforeUpdate = ['hashPassword'];
}

さらに、各モデルは、$allowCallbacksプロパティを設定することにより、クラス全体でコールバックを許可(デフォルト)または拒否できます。

<?php

namespace App\Models;

use CodeIgniter\Model;

class MyModel extends Model
{
    protected $allowCallbacks = false;
}

allowCallbacks()メソッドを使用して、単一のモデル呼び出しに対してこの設定を一時的に変更することもできます。

<?php

$model->allowCallbacks(false)->find(1); // No callbacks triggered
$model->find(1); // Callbacks subject to original property value

イベントパラメーター

各コールバックに渡される正確なデータは少し異なるため、各イベントに渡される$dataパラメーターの内容の詳細を以下に示します。

イベント

$dataの内容

beforeInsert

data = 挿入されているキーと値のペア。insert()メソッドにオブジェクトまたはエンティティクラスが渡された場合、最初に配列に変換されます。

afterInsert

id = 新しい行の主キー(失敗した場合は0)。data = 挿入されているキーと値のペア。result = クエリビルダーを介して使用されたinsert()メソッドの結果。

beforeUpdate

id = 更新されている行の主キーの配列。data = 更新されているキーと値のペア。update()メソッドにオブジェクトまたはエンティティクラスが渡された場合、最初に配列に変換されます。

afterUpdate

id = 更新されている行の主キーの配列。data = 更新されているキーと値のペア。result = クエリビルダーを介して使用されたupdate()メソッドの結果。

beforeFind

呼び出し元のmethodの名前、singletonが要求されたかどうか、およびこれらの追加フィールド

  • first()

追加フィールドなし

  • find()

id = 検索対象の行の主キー。

  • findAll()

limit = 検索する行数。offset = 検索中にスキップする行数。

afterFind

beforeFind と同様ですが、結果として得られたデータ行(複数可)を含みます。結果が見つからない場合は null を返します。

beforeDelete

id = delete() メソッドに渡される行の主キー。purge = ソフト削除行をハード削除するかどうかを示すブール値。

afterDelete

id = delete() メソッドに渡される行の主キー。purge = ソフト削除行をハード削除するかどうかを示すブール値。result = クエリビルダーの delete() コールの結果。data = 使用されていません。

beforeInsertBatch

data = 挿入される値の連想配列。オブジェクトまたはエンティティクラスが insertBatch() メソッドに渡された場合、最初に配列に変換されます。

afterInsertBatch

data = 挿入される値の連想配列。result = クエリビルダーで使用される insertbatch() メソッドの結果。

beforeUpdateBatch

data = 更新される値の連想配列。オブジェクトまたはエンティティクラスが updateBatch() メソッドに渡された場合、最初に配列に変換されます。

afterUpdateBatch

data = 更新されるキーと値のペア。result = クエリビルダーで使用される updateBatch() メソッドの結果。

Find* データの変更

beforeFind メソッドと afterFind メソッドはどちらも、モデルからの通常のレスポンスを上書きする修正されたデータセットを返すことができます。afterFind では、戻り値の配列内の data に対して行われた変更は、自動的に呼び出し元のコンテキストに返されます。beforeFind が find ワークフローをインターセプトするには、追加のブール値 returnData も返す必要があります。

<?php

namespace App\Models;

use CodeIgniter\Model;

class MyModel extends Model
{
    protected $beforeFind = ['checkCache'];

    // ...

    protected function checkCache(array $data)
    {
        // Check if the requested item is already in our cache
        if (isset($data['id']) && $item = $this->getCachedItem($data['id'])) {
            $data['data']       = $item;
            $data['returnData'] = true;

            return $data;
        }

        // ...
    }
}

手動モデルの作成

アプリケーションのモデルを作成するために、特別なクラスを拡張する必要はありません。データベース接続のインスタンスを取得するだけで済みます。これにより、CodeIgniter のモデルが提供する機能をバイパスし、完全にカスタムエクスペリエンスを作成できます。

<?php

namespace App\Models;

use CodeIgniter\Database\ConnectionInterface;

class UserModel
{
    protected $db;

    public function __construct(ConnectionInterface $db)
    {
        $this->db = $db;
    }
}