yii は、追加、削除、変更、検索を実装します
1. データ アクセス オブジェクト (DAO)
Yii
DAO は、PHP データ オブジェクト (PDO) に基づいて構築されます。これは、
MySQL、PostgreSQL など、多くの一般的な DBMS に統合されたデータ アクセスを提供する拡張機能です。したがって、Yii DAO を使用するには、PDO 拡張機能と特定の PDO データベースドライバー (PDO_MYSQL など)
をインストールする必要があります。
Yii DAO には主に次の 4 つのクラスが含まれています:
CDbConnection: データベース接続を表します。
CDbCommand: データベースを通じて実行される SQL ステートメントを表します。
CDbDataReader: クエリ結果セットからの行の前方専用ストリームを表します。
CDbTransaction: データベース トランザクションを表します。
1. データベース接続を確立します
でデータベース接続を確立するには、CDbConnection
インスタンスを作成し、アクティブ化します。データベースに接続するには、接続情報を指定するデータ ソース名 (DSN) が必要です。ユーザー名とパスワードも使用できます。データベースへの接続中にエラー
が発生した場合 (例: 間違った DSN または無効なユーザー名/パスワード)、例外がスローされます。
$connection=new CDbConnection($dsn,$username,$password);
// 接続を確立します。 try...catch を使用すると、スローされる可能性のある例外をキャッチできます
$connection->active=true;
....
$connection - >active=false; //接続を閉じます
DSN の形式は、使用される PDO データベース ドライバーによって異なります。通常、DSN には PDO ドライバーの名前、コロン、ドライバー固有の接続構文が含まれます。詳細については、PDO ドキュメントを参照してください。以下は、一般的に使用される DSN 形式のリストです。
* SQLite: sqlite:/path/to/dbfile
* MySQL: mysql:host=localhost;dbname=testdb
* PostgreSQL: pgsql:host=localhost; port=5432;dbname=testdb
* SQL Server: mssql:host=localhost;dbname=testdb
* Oracle: oci:dbname=//localhost:1521/testdb
CDbConnection は CApplicationComponent を継承しているため、アプリケーションコンポーネントとして使用することもできます。これを行うには、アプリケーション構成で db (または他の名前) アプリケーション コンポーネントを次のように構成します:
array(
....
'components ' =>array(
....
'db'=>array(
'class'=>'CDbConnection',
'connectionString'=>'mysql:host=localhost;dbname=testdb',
'username'=>'root',
'password'=>パスワード',
'emulatePrepare'=>true, // 一部の MySQL インストールで必要
),
),
)
これで、Yii::app()->db を通じてデータベース接続にアクセスできるようになります。 CDbConnection::autoConnect を false に特別に設定しない限り、これは自動的にアクティブ化されます。こうすることで、この単一の DB 接続をコード内の多くの場所で共有できます。
2. SQL ステートメントの実行
データベース接続が確立されたら、CDbCommand を使用して SQL ステートメントを実行できます。 CDbCommand インスタンスを作成するには、指定した SQL ステートメントを引数として CDbConnection::createCommand() を呼び出します。
$connection=Yii::app()->db; // すでに "db" 接続を確立していると仮定します
// そうでない場合は、明示的に確立する必要があるかもしれません接続:
// $connection=new CDbConnection($dsn,$username,$password);
$command=$connection->createCommand($sql);
// 必要に応じて、この SQL ステートメントは次の方法で変更できます:
// $command->text=$newSQL;
SQL ステートメントは CDbCommand を介して渡されます。次の 2 つの方法でメソッドが実行されます:
execute(): INSERT、UPDATE、DELETE などの非クエリ SQL ステートメントを実行します。成功すると、この実行によって影響を受けた行数が返されます。
query(): SELECT など、複数行のデータを返す SQL ステートメントを実行します。成功すると、結果のデータ行を反復処理できる CDbDataReader インスタンスが返されます。簡単にするために、(Yii) はクエリ結果を直接返す一連の queryXXX() メソッドも実装します。
SQL ステートメントの実行中にエラーが発生した場合、例外がスローされます。
$rowCount=$command->execute(); // クエリなしの SQL を実行します
$dataReader=$command->query(); // SQL クエリを実行します
$rows=$command->queryAll(); // クエリを実行して結果のすべての行を返します
$row=$command->queryRow(); // クエリを実行して返します結果
$column=$command->queryColumn(); // クエリを実行し、結果の最初の列を返します
$value=$command->queryScalar ( ; その後、
CDbDataReader::read() を繰り返し呼び出すことで、結果の行を取得できます。 PHP の foreach 言語構造で
CDbDataReader を使用して、データを 1 行ずつ取得することもできます。
$dataReader=$command->query();
// false が返されるまで read() を繰り返し呼び出します
while(($row=$dataReader->read())!==false) { ... }
// foreach を使用してデータ内の各行を走査します
foreach($dataReader as $row) { ... }
// すべての行を一度に配列に抽出します
$rows=$dataReader->readAll();
注: query() とは異なり、すべての queryXXX() メソッドはデータを直接返します。たとえば、queryRow() は、クエリ結果の最初の行を表す配列を返します。
4. トランザクションを使用する
Yii では CDbTransaction インスタンスとして表示されるトランザクションは、次の状況で開始できます:
* トランザクションを開始します。
* クエリは 1 つずつ実行します。データベースへの更新は外部からは見えません。
* トランザクションをコミットします。トランザクションが成功すると、更新が表示されます。
* クエリの 1 つが失敗すると、トランザクション全体がロールバックされます。
上記のワークフローは、次のコードを通じて実装できます:
$transaction=$connection->beginTransaction();
try
{
$connection->createCommand($sql1)->execute();
$connection->createCommand($sql2)->execute();
/ /.... 他の SQL 実行
$transaction->commit();
}
catch(Exception $e) // クエリが失敗した場合, 例外がスローされます
{
$transaction->rollBack();
}
5. バインディングパラメータ
SQL インジェクション攻撃を回避し、SQL ステートメントを繰り返し実行する効率を向上させるために、オプションのパラメーター プレースホルダーを使用して SQL ステートメントを「準備」できます。パラメーターがバインドされると、これらのプレースホルダーは実際のパラメーターに置き換えられます。
パラメータ
数値プレースホルダーは、名前を付けることも (一意のトークンとして表示される)、名前を付けないこともできます (疑問符として表示されます)。 CDbCommand::bindParam() または
CDbCommand::bindValue()
を呼び出して、これらのプレースホルダーを実際のパラメーターに置き換えます。これらのパラメータを引用符で囲む必要はありません。基礎となるデータベース ドライバがこれを処理します。パラメータのバインドは、SQL ステートメントが実行される前に完了する必要があります。
// 2 つのプレースホルダー「:username」と「:email」を含む SQL
$sql="INSERT INTO tbl_user (username, email) VALUES(:username, :email)";
$command=$connection->createCommand($sql);
// プレースホルダー ":username" を実際のユーザー名に置き換えます
$command-> bindParam(":username",$username,PDO::PARAM_STR);
// プレースホルダー「:email」を実際のメールに置き換えます
$ command->bindParam(": email",$email,PDO::PARAM_STR);
$command->execute();
// 新しいパラメータ セットを使用して別の 1 行を挿入
$command->bindParam(":username",$username2,PDO::PARAM_STR);
$command->bindParam(":email",$email2,PDO ::PARAM_STR);
$command->execute();
メソッドbindParam()とbindValue()は非常に似ています。唯一の違いは、前者はパラメータのバインドに PHP 変数を使用するのに対し、後者は値を使用することです。メモリ内の大きなデータ ブロック パラメータの場合、パフォーマンス上の理由から、前者を最初に使用する必要があります。
6. 列のバインド
クエリ結果を取得する場合、PHP 変数を使用して列をバインドすることもできます。これにより、クエリ結果の行が取得されるたびに最新の値が自動的に入力されます。
$sql="SELECT ユーザー名、メール FROM tbl_user";
$dataReader=$connection->createCommand($sql)->query();
// $username 変数を使用して最初の列 (ユーザー名) をバインドします
$dataReader->bindColumn(1,$username);
// $email 変数を使用して2 番目の列 (メール)
$dataReader->bindColumn(2,$email);
while($dataReader->read()!==false)
{
// $username と $email には、現在の行にユーザー名と電子メールが含まれています
}
7. テーブルのプレフィックス
を使用して、
テーブル プレフィックスを使用し、CDbConnection::tablePrefix プロパティを目的のテーブル プレフィックスに構成します。次に、
{{TableName}} を使用して SQL ステートメント内のテーブルの名前を表します。TableName はプレフィックスのないテーブル名を指します。たとえば、データベースに tbl_user
という名前のテーブルが含まれており、 tbl_ がテーブル プレフィックスとして構成されている場合、次のコードを使用してユーザー関連のクエリを実行できます:
$sql= 'SELECT * FROM {{user}}';
$users=$connection->createCommand($sql)->queryAll();
2 Active Record
Yii DAO はデータベース関連のほぼすべてのタスクを処理できますが、通常の CRUD (作成、読み取り、
) を実行するために時間の 90% を費やすことになるでしょう。更新および削除の SQL ステートメント)操作。また、コードに SQL ステートメントが混在すると、メンテナンスが困難になります。これらの問題を解決するには、Active
Record を使用できます。
アクティブ レコード (AR) は、一般的なオブジェクト リレーショナル マッピング (ORM) テクノロジです。各 AR
クラスはデータ テーブル (またはビュー) を表し、AR インスタンスはクラスの属性として AR クラスに反映されます。一般的な CRUD 操作は AR
のメソッドとして実装されます。したがって、よりオブジェクト指向的な方法でデータにアクセスできます。たとえば、次のコードを使用して、tbl_post テーブルに新しい行を挿入できます。
$post=新しい投稿;
$post->title='サンプル投稿';
$post->content='投稿本文の内容';
$post->save();
注: AR は、データベース関連のすべてのタスクを解決することを目的としたものではありません。その最適なアプリケーションは、データ テーブルを PHP 構造にモデル化し、複雑な SQL ステートメントを含まないクエリを実行することです。 複雑なクエリシナリオの場合は、Yii DAO を使用する必要があります。
1. データベース接続を確立する
AR はデータベース関連の操作を実行するためにデータベース接続に依存します。デフォルトでは、db アプリケーション コンポーネントが必要な CDbConnection データベース接続インスタンスを提供すると想定します。次のアプリケーション構成は例を示しています。
return array(
'components'=>array(
'db'=>array(
'class'=>'system.db.CDbConnection','connectionString'=>'sqlite:path/to/dbfile',// テーブル構造のキャッシュをオンにする(スキーマ キャッシュ) パフォーマンスを向上させるため // 'schemaCachingDuration'=>3600,),),);ヒント: Active Record はテーブルのメタデータに依存して列情報を決定するため、メタデータの読み取りと解析には時間がかかります。 データベースのテーブル構造がほとんど変更されない場合は、CDbConnection::schemaCachingDuration 属性をゼロより大きい値に構成して、 テーブル構造のキャッシュを有効にする必要があります。 db 以外のアプリケーション コンポーネントを使用する場合、または AR を使用して複数のデータベースを処理する場合は、CActiveRecord::getDbConnection() をオーバーライドする必要があります。 CActiveRecord クラスは、すべての AR クラスの基本クラスです。 ヒント: AR を通じて複数のデータベースを使用するには 2 つの方法があります。データベースの構造が異なる場合は、異なる AR 基本クラスを作成して、異なる getDbConnection() を実装できます。それ以外の場合は、静的変数 CActiveRecord::db を動的に変更することをお勧めします。 2. AR クラスの定義 データ テーブルにアクセスするには、まず CActiveRecord を統合して AR クラスを定義する必要があります。各 AR クラスは個別のデータ テーブルを表し、AR インスタンスはそのテーブル内の行を表します。 次の例は、tbl_post テーブルを表す AR クラスの最も単純なコードを示しています。 class Post extends CActiveRecord{public static function model( $ className=__CLASS__){returnparent::model($className);} public function tableName ( ){return 'tbl_post';}}ヒント: AR クラスは複数のクラスで参照されることが多いため、 place を使用すると、AR クラスを 1 つずつインポートする代わりに、AR クラスを含むディレクトリ全体をインポートできます。 たとえば、すべての AR クラス ファイルが protected/models ディレクトリにある場合、アプリケーションを次のように構成できます: return array('import'=>array(
'application.models.*',
),
);
デフォルトでは、AR クラスの名前はデータテーブル。異なる場合は、tableName() メソッドをオーバーライドします。
テーブル プレフィックス関数を使用するには、AR クラスの tableName() メソッドを次のようにオーバーライドできます:
public function tableName()
{
return ' {{post}}';
}
つまり、Yii が自動的にプレフィックスを追加し、完全なテーブル名を返します。
データテーブル行の列の値は、対応する AR インスタンスのプロパティとしてアクセスできます。たとえば、次のコードはタイトル列 (属性) を設定します:
$post=new Post;
$post->title='サンプル投稿';
Post クラスで属性 title を明示的に定義したことはありませんが、上記のコードを通じてアクセスできます。これは、title が tbl_post テーブルの
列であり、CActiveRecord が PHP の __get() マジック メソッドを通じてアクセス可能なプロパティにするためです。存在しない列に同じ方法でアクセスしようとすると、
例外がスローされます。
テーブルに主キーがない場合は、次のように対応する AR クラスの PrimaryKey() メソッドをオーバーライドして、どの列を主キーとして使用するかを指定する必要があります。
public functionprimaryKey()
{
return 'id';
// 複合主キーの場合は、次のような配列を返します。
// return array('pk1', 'pk2');
}
3. レコードを作成します
データに新しい行を挿入します。 table に対応する AR クラスのインスタンスを作成し、テーブルの列に関連する属性を設定してから、save() メソッドを呼び出して挿入を完了する必要があります:
$post=new Post;
$post- >title='サンプル投稿';
$post->content='サンプル投稿のコンテンツ';
$post->create_time= time();
$post->save();
テーブルの主キーが自動インクリメントの場合、挿入完了後に AR インスタンスには更新された主キーが含まれます。上の例では、明示的に変更していないにもかかわらず、 id 属性は新しく挿入された投稿の主キー値を反映します。
テーブル構造内で列が静的なデフォルト値 (文字列、数値など) で定義されている場合。その後、AR インスタンスの対応する属性には、インスタンスの作成時にこのデフォルト値が自動的に含まれます。このデフォルト値を変更する 1 つの方法は、AR クラスでこの属性を明示的に定義することです:
class Post extends CActiveRecord
{
public $title='タイトルを入力してください' ;
....
}
$post=new Post;
echo $post->title; // ここで表示: タイトルを入力してください
レコードがデータベースに保存 (挿入または更新) される前に、そのプロパティを CDbExpression タイプに割り当てることができます。たとえば、MySQL の NOW() 関数によって返されたタイムスタンプを保存するには、次のコードを使用できます:
$post=new Post;
$post->create_time=new CDbExpression('NOW()'); //CDbExpression クラスはデータベース式の値を計算します
/ / $post->create_time='NOW()';
// 'NOW()' は文字列として扱われるため、機能しません。
$post->save();
ヒント
: AR を使用すると、多くの SQL ステートメントを記述せずにデータベース操作を実行できるため、
AR がバックグラウンドでどのような SQL ステートメントを実行するのか疑問に思うことがよくあります。これは、Yii のロギング機能を有効にすることで実現できます。たとえば、アプリケーション構成で CWebLogRoute を有効にすると、各 Web ページの最後に実行された SQL ステートメントが表示されます。
アプリケーション構成で CDbConnection::enableParamLogging を true に設定して、SQL ステートメントにバインドされたパラメーター値も記録されるようにすることもできます
。
4. レコードの読み取り
データ テーブル内のデータを読み取るには、次の方法で find series メソッドの 1 つを呼び出すことができます。
// Find満足度指定された条件の結果の最初の行
$post=Post::model()->find($condition,$params);
// 指定された条件で値を検索します主キー
$post=Post::model()->findByPk($postID,$condition,$params);
// 指定された属性を持つ行を検索しますvalue
$post=Post::model()->findByAttributes($attributes,$condition,$params);
// 指定された SQL を通じて結果の最初の行を検索しますステートメント
$post=Post::model()->findBySql($sql,$params);
上記のように、Post::model() を通じて find メソッドを呼び出します。 。静的メソッド model() はすべての AR クラスに必要であることに注意してください。このメソッドは、クラスレベルのメソッド (静的クラス メソッドのようなもの) にアクセスするためのオブジェクト コンテキスト内の AR インスタンスを返します。
find メソッドは、クエリ条件を満たす行を見つけた場合、データ テーブル行の対応する列の値を属性に含む Post インスタンスを返します。その後、通常のオブジェクト プロパティと同様に、ロードされた値を読み取ることができます (例: echo $post->title;)。
指定されたクエリ基準を使用してもデータベース内で何も見つからない場合、find メソッドは null を返します。
find を呼び出すとき、$condition と $params を使用してクエリ条件を指定します。ここで、$condition は SQL ステートメント内の WHERE 文字列にすることができ、$params は $condation 内のプレースホルダーに値をバインドする必要があるパラメーターの配列です。例:
// postID=10 の行を検索
$post=Post::model()->find('postID=:postID', array(':postID) ' =>10));
注: 上記の例では、特定の DBMS の postID 列への参照をエスケープする必要がある場合があります。 たとえば、PostgreSQL を使用している場合、PostgreSQL はデフォルトで列名の大文字と小文字が区別されないため、この式を「postID」=:postID として記述する必要があります。
$condition を使用して、より複雑なクエリ条件を指定することもできます。文字列を使用する代わりに、 $condition を CDbCriteria のインスタンスにすることができます。これにより、WHERE に限定されない条件を指定できます。例:
$criteria=new CDbCriteria;
$criteria->select='title'; // 'title' 列のみを選択します
$criteria- > 条件='postID=:postID';
$criteria->params=array(':postID'=>10);
$post=Post::model( )- >find($criteria); // $params は不要になりました
CDbCriteria をクエリ条件として使用する場合、$params パラメータは CDbCriteria で指定できるため不要になることに注意してください。上と同じように。
CDbCriteria の代わりに、配列を find メソッドに渡すこともできます。配列のキーと値はそれぞれ、条件の属性名と値に対応します。上記の例は次のように書き換えることができます。 find(array(
'select'=>'title',
'condition'=>'postID=:postID',
'params'=> ;array(':postID' =>10),
));
クエリ条件が指定された値による複数の列の一致に関するものである場合、次のように使用できます。 findByAttributes()。 $attributes
引数を、列名でインデックス付けされた値の配列にします。一部のフレームワークでは、このタスクは findByNameAndTitle
のようなメソッドを呼び出すことで実現できます。このアプローチは魅力的に見えますが、多くの場合、混乱、競合、および列名の大文字と小文字の区別などの問題が発生します。
複数のデータ行が指定されたクエリ条件に一致する場合、以下の findAll メソッドを使用してそれらをすべて戻すことができます。すでに説明したように、それぞれに独自の検索メソッドがあります。
// 指定された条件を満たすすべての行を検索します
$posts=Post::model()->findAll($condition,$params);
/ / 指定された主キーを持つすべての行を検索します
$posts=Post::model()->findAllByPk($postIDs,$condition,$params);
// 行を検索します指定された属性値のすべての行を使用します
$posts=Post::model()->findAllByAttributes($attributes,$condition,$params);
// によってすべてを検索します指定された SQL ステートメント Line
$posts=Post::model()->findAllBySql($sql,$params);
クエリ条件に一致するものがない場合、findAll は空の配列を返します。 。これは、何も見つからない場合に null を返す find とは異なります。
上記の find メソッドと findAll メソッドに加えて、便宜上、(Yii) は次のメソッドも提供します:
// 指定された条件を満たす行の数を取得します
$n=Post: :model()->count($condition,$params);
// 指定された SQL を通じて結果の行数を取得します
$n=Post: :model()-> countBySql($sql,$params);
// 指定された条件を持つ行が少なくとも 1 つあるかどうかを確認します
$exists=Post::model( )->exists($condition,$ params);
5. レコードを更新します
AR インスタンスが列の値を入力した後、値を変更してデータ テーブルに保存できます。 。
$post=Post::model()->findByPk(10);
$post->title='新しい投稿のタイトル';
$post ->save(); // 変更をデータベースに保存します
Positive
ご覧のとおり、同じ save() メソッドを使用して挿入操作と更新操作を実行します。 new 演算子を使用して AR インスタンスが作成された場合、save()
を呼び出すと、新しいデータ行がデータ テーブルに挿入されます。AR インスタンスが find メソッドまたは findAll メソッドの結果である場合は、save( を呼び出します)。 )
はテーブル内の既存の行を更新します。実際、CActiveRecord::isNewRecord を使用して、AR インスタンスが新しいかどうかを示します。
最初にデータテーブルをロードせずに、データテーブル内の 1 つ以上の行を直接更新することもできます。 AR は、この目的を達成するために、次の便利なクラスレベルのメソッドを提供します。
// 指定された条件を満たす行を更新
Post::model()->updateAll($attributes,$ condition, $params);
//指定された条件と主キーに一致する行を更新します
Post::model()->updateByPk($pk,$attributes,$condition, $params);
//指定された条件を満たす行の count 列を更新します
Post::model()->updateCounters($counters,$condition,$params);
上記のコードでは、$attributes は列名でインデックス付けされた列値を含む配列であり、$counters は列名でインデックス付けされた値の増分可能な配列です。前の段落。
6. レコードの削除
AR インスタンスにデータ行が入力されている場合は、このデータ行を削除することもできます。
$post=Post::model()->findByPk(10); // ID が 10 の投稿があるとします
$post->delete(); // データ テーブルからこの行を削除します
削除後、AR インスタンスは変更されませんが、データ テーブル内の対応する行が失われることに注意してください。
以下のクラスレベルのコードを使用すると、最初に行をロードせずに行を削除できます。
//指定された条件を満たす行を削除します
Post::model()->deleteAll($condition,$params);
//指定された条件と主キー行に一致する行
Post::model()->deleteByPk($pk,$condition,$params);
7. データ検証
行の挿入時または更新時に、列の値が対応するルールに準拠しているかどうかを確認する必要があることがよくあります。列の値がエンドユーザーによって提供される場合、これはさらに重要になります。全体として、クライアントから送信されるデータは決して信頼できません。
AR は、save() が呼び出されたときにデータ検証を自動的に実行します。検証は、AR クラスの rules() メソッドで指定されたルールに基づいて行われます。検証ルールの詳細については、「検証ルールの宣言」セクションを参照してください。以下は、レコードを保存するときに必要な一般的なワークフローです。
if($post->save())
{
// データは有効で、正常に挿入/更新されました
}
else
{
// データが無効です。getErrors() を呼び出してエラー情報を抽出します
}
データが挿入または更新されるかどうかは、最終的なユーザーによって決定されます。 ユーザーが HTML フォームを送信するとき、それを対応する AR 属性に割り当てる必要があります。これは同様の方法で実現できます:
$post->title=$_POST['title'];
$post->content=$_POST['content'] ;
$post->save();
列が多い場合、この種のコピーでは非常に長いリストが表示されることがあります。これは、次に示すように属性プロパティを使用することで簡素化できます。詳細については、「安全な属性の割り当て」セクションと「アクションの作成」セクションを参照してください。
// $_POST['Post'] が値として列名インデックス列値を持つ配列であると仮定します
$post->attributes=$_POST['Post'];
$post->save();
8. レコードの比較
テーブル レコードと同様に、AR インスタンスは主キーの値によって識別されます。したがって、2 つの AR インスタンスを比較するには、それらが同じ AR クラスに属していると仮定して、主キー値を比較するだけで済みます。ただし、より簡単な方法は、CActiveRecord::equals() を呼び出すことです。
他のフレームワークの AR 実装とは異なり、Yii は AR で複数の主キーをサポートします。複合主キーは 2 つ以上のフィールドで構成されます。同様に、主キーの値は Yii では配列として表されます。 PrimaryKey 属性は、AR インスタンスの主キー値を与えます。
9. カスタマイズ
CActiveRecord には、ワークフローをカスタマイズするためにサブクラスでオーバーライドできるいくつかのプレースホルダー メソッドが用意されています。
beforevalidate と afterValidate: これら 2 つは、データの有効性を検証する前後に呼び出されます。
beforeSave と afterSave: これら 2 つは、AR インスタンスを保存する前と後に呼び出されます。
beforeDelete と afterDelete: これら 2 つは、AR インスタンスが削除される前後に呼び出されます。
afterConstruct: これは、new 演算子を使用して各 AR インスタンスが作成された後に呼び出されます。
beforeFind: これは、AR ファインダーがクエリ (find()、findAll() など) を実行するために使用される前に呼び出されます。
afterFind: これは、クエリの結果として作成された AR インスタンスごとに呼び出されます。
10. AR を使用してトランザクションを処理する
各 AR インスタンスには、CDbConnection のインスタンスである dbConnection という名前のプロパティが含まれているため、必要に応じて Yii DAO が提供する AR を使用できます。 トランザクション関数:
$model=Post::model();
$transaction=$model->dbConnection->beginTransaction();
試してみる
{
// 検索と保存は、別のリクエストによって介入される可能性がある 2 つのステップです
// このようにトランザクションを使用して、その一貫性と整合性を確保します
$ post=$model->findByPk(10);
$post->title='新しい投稿タイトル';
$post->save() ;
$transaction->commit();
}
catch(Exception $e)
{
$transaction ->rollBack( );
}
11. 名前付きスコープ
名前付きスコープは、他の名前付き範囲と組み合わせて使用され、アクティブ レコードに適用される名前付きクエリ ルールを表します。クエリ。
名前付きスコープは、主に CActiveRecord::scopes() メソッドで名前とルールのペアの形式で宣言されます。次のコードは、Post モデル クラスで 2 つの名前付き範囲 (公開済みと最近) を宣言します。
class Post extends CActiveRecord
{
......
public functionscopes()
{
return array(
'published'=>array(
'condition'=>'status=1',
),
'recently'=>array(
'order'=>'create_time DESC',
'limit'=>5,
),
);
}
}
各名前付き範囲は、CDbCriteria インスタンスの初期化に使用できる配列として宣言されます。たとえば、最近名前を付けた範囲は、order 属性が create_time DESC、limit 属性が 5 であることを指定します。クエリ ルールに変換された後、最後の 5 つの投稿が返されます。
名前付き範囲は、主に find メソッド呼び出しの修飾子として使用されます。複数の名前付き範囲を連結して、より限定的なクエリ結果セットを形成できます。たとえば、最近公開された投稿を検索するには、次のようなコードを使用できます。
$posts=Post::model()->published()->recently()->findAll();
一般に、名前付き範囲は find メソッド呼び出しの左側に表示される必要があります。それぞれがクエリ ルールを提供し、find メソッド呼び出しに渡されるルールを含む他のルールと結合されます。最終的な結果は、クエリに一連のフィルターを追加するようなものです。
名前付き範囲は、更新メソッドと削除メソッドでも使用できます。たとえば、次のコードは最近公開されたすべての投稿を削除します:
Post::model()->published()->recently()->delete();
注 : 名前付きスコープはクラスレベルのメソッドにのみ使用できます。つまり、このメソッドは ClassName::model() を使用して呼び出す必要があります。
12. パラメータ化された名前付き範囲
名前付き範囲はパラメータ化できます。たとえば、最近名前を付けたスコープで指定された投稿の数をカスタマイズしたいとします。これを実現するには、CActiveRecord::scopes メソッドで名前付きスコープを宣言する代わりに、この名前付きスコープと同じ名前のメソッドを定義する必要があります。 :
最近公開関数($limit=5)
{
$this->getDbCriteria()->mergeWith(array(
'order' =>'create_time DESC',
'limit'=>$limit,
));
return $this;
}
次に、次のステートメントを使用して、最新の 3 つの投稿を取得できます。
$posts=Post::model()->published()->recently(3)->findAll();
上記のコードでは、パラメーター 3 を指定すると、デフォルトで最新の 5 つの投稿が取得されます。
13. デフォルトの名前付けスコープ
モデル
型クラスは、すべての (関連するものを含む)
クエリに適用されるデフォルトの名前付けスコープを持つことができます。このモデルについて。たとえば、複数の言語をサポートする Web サイトでは、現在のユーザーが指定した言語でのみコンテンツが表示される場合があります。この Web サイトのコンテンツに関するクエリが多数ある可能性があるため、この問題を解決するために、デフォルトの
を使用して名前付き範囲を定義できます。この目的を達成するには、次のように CActiveRecord::defaultScope メソッドをオーバーライドします。
class Content extends CActiveRecord
{
public functiondefaultScope()
{
return array(
'condition'=>" language='".Yii::app()-> language."'",
) ;
}
}
これで、次のメソッドが呼び出されると、上で定義したクエリ ルールが自動的に使用されます:
$contents=Content ::model()->findAll();
デフォルトの名前付き範囲は SELECT クエリにのみ適用されることに注意してください。 INSERT、UPDATE、および DELETE クエリは無視されます。
3. リレーショナル アクティブ レコード (関連クエリ)
このセクションでは、アクティブ レコード (AR) を通じて単一のデータ テーブルからデータを取得する方法をすでに理解しています。 AR を使用して関連するデータ テーブルに接続し、データを取得する方法を紹介します。
関連付けられた AR を使用する前に、まずデータベース内の関連付けられたデータ テーブル間の主キーと外部キーの関連付けを確立する必要があります。AR は、データベース内のデータ テーブルの関連付けを定義するメタ情報を分析して、データの接続方法を決定する必要があります。データベース。
1. アソシエーションの宣言方法
アソシエーション クエリに AR を使用する前に、各 AR クラス間にどのような種類のアソシエーションがあるかを AR に伝える必要があります。
AR クラス間の関連付けは、データベース内のこのクラスによって表されるデータ テーブル間の関連付けを直接反映します。リレーショナル データベースの観点から見ると、2 つのデータ テーブル A と B の間には、1 対多、1 対 1、および多対多の 3 つの関連付けが考えられます。 AR には、4 種類の関連付けがあります。
BELONGS_TO: データ テーブル A と B の間の関係が 1 対多である場合、B は A に属していると言います。
HAS_MANY: データテーブル A と B の間の関係が多対 1 である場合、B には多くの A がある (B には多くの A がある) と言います。
HAS_ONE: これは、「HAS_MANY」関係の特殊なケースです。A が 1 つしか持たない場合、B は 1 つの A を持ちます (B は 1 つの A を持ちます)。
MANY_MANY:
これは、リレーショナル データベースの多対多の関係に相当します。ほとんどのリレーショナル データベースは多対多の関係を直接サポートしていないため、通常、多対多の関係を 2 つの 1 対多の関係に分解するには、別の関連付けテーブルが必要です。 AR 用語で理解すると、MANY_MANY 関係は BELONGS_TO と HAS_MANY で構成されていると考えることができます。
AR でのリレーションシップの宣言は、親クラス CActiveRecord の relationship() メソッドをオーバーライドすることで実現されます。このメソッドは、関係定義を含む配列を返します。配列内のキー値の各セットは関連付けを表します:
'VarName'=>array('RelationType', 'ClassName', 'ForeignKey', ..追加オプション)
の VarName はこの関連付けの名前であり、関連付けの 4 つのタイプを表す 4 つの定数があります
Type: self::BELONGS_TO、self::HAS_ONE、self::HAS_MANY、self::MANY_MANY;
ClassName は、この関係が関連付けられる方法を指定する AR クラスのクラス名です。この関連付けは、どの外部キーが接続されているかを示します。次の追加の
オプションでは、いくつかの追加設定を追加できます。これについては後で紹介します。
次のコードは、ユーザーと投稿の間の関連付けを定義する方法を示しています。
class Post extends CActiveRecord {
public function relationship() {
return array(
'author'=>array(
self::BELONGS_TO,
'ユーザー',
'著者ID'
),
'カテゴリ'=>array(
self::MANY_MANY,'カテゴリ','PostCategory(postID, categoryID)'),);}} class ユーザー拡張 CActiveRecord {public function relationship() {return array ('投稿'=>array(self::HAS_MANY,'投稿','著者ID'),'プロファイル'=>array(self::HAS_ONE,'プロファイル','オーナーID'),);}} は と言いました: 外部キーは 2 つのキーで構成される場合がありますまたは より多くのフィールドで構成され、複数のフィールド名はカンマまたはスペースで区切ることができ、 はここにまとめて記述されます。多対多のリレーションシップの場合、外部キーで関連付けテーブルをマークする必要があります。たとえば、Post クラスの category 関連付けでは、外部キーを PostCategory(postID, categoryID) として記述する必要があります。 )。 AR クラスでアソシエーションを宣言すると、各アソシエーションが属性として AR クラスに追加され、属性名がアソシエーションの名前になります。関連するクエリを実行すると、これらの属性は関連する AR クラスのインスタンスに設定されます。たとえば、Post インスタンスを取得するためにクエリを実行する場合、その $author 属性は Post 作成者を表す User クラスのインスタンスです。 2. 関連付けクエリ 関連付けクエリを実行するには、 を入力します。最も簡単な方法は、関連付けられた AR オブジェクトの特定の関連付けられた属性にアクセスすることです。この属性に以前にアクセスしたことがない場合は、関連クエリが開始され、現在の AR オブジェクトの主キーを介して 関連テーブルに接続され、関連付けられたオブジェクトの値が取得され、これらのデータが保存されます。プロパティ内のオブジェクト。この方法は「遅延読み込み」と呼ばれ、特定の属性にアクセスした場合にのみ、関連するデータがデータベースから取得されることを意味します。次の例では、遅延読み込みプロセスについて説明します: // ID が 10 の投稿を取得します$post=Post::model()->findByPk(10);
// 投稿の作成者を取得します: ここでリレーショナル クエリが実行されます$author=$post->author;クエリがない場合は、さまざまなリレーショナル ケースが発生しますBELONGS_TO は HAS_ONE に関連付けられており、結果がない場合は null を返し、MANY_MANY は結果がない場合は空の配列を返します。 遅延読み込みメソッドは非常に便利ですが、場合によっては効率的ではありません。たとえば、N 件の投稿の作成者情報を取得したい場合、遅延メソッドを使用すると、N 個の接続クエリが実行されます。この時点では、いわゆる積極的な読み込み方法を使用する必要があります。 積極的な読み込みメソッドは、メインの AR インスタンスとそれに関連する AR インスタンスを取得します。これは、with() メソッドと find または findAll メソッド を使用して行われます。たとえば、$posts=Post::model()->with('author')->findAll();on
上記のコードは Post インスタンスの配列を返します。遅延読み込みメソッドとは異なり、各 Post インスタンスの author プロパティには、このプロパティにアクセスする前に、関連付けられた
User インスタンスが設定されています。投稿ごとに結合クエリを実行する代わりに、熱心な読み込みメソッドにより、単一の結合クエリですべての投稿とその作成者が取得されます!with() メソッドで複数の関連付け名を指定できます。たとえば、次のコードは、投稿と投稿者およびカテゴリを取得します: $posts=Post::model()->with('author','categories')->findAll() ;ネストされた熱心な読み込みも使用できます。関連名のリストを使用する代わりに、次のように階層的な方法で関連名を with() メソッドに渡します。 $posts=Post::model()->with('author.profile','author.posts','categories')->findAll();上記のコードは取得しますすべての投稿とその作成者およびカテゴリ。また、各作成者のプロフィールと投稿も取得します。次のように CDbCriteria::with 属性を指定することで、積極的な読み込みを実行することもできます。$criteria=new CDbCriteria;$criteria->with=array('author.profile','author.posts','カテゴリ',);$posts=Post::model()->findAll($criteria);または$posts=Post::model()- >findAll(array('with'=>array('author.profile','author.posts', 'カテゴリ',) );3. 関連クエリ オプション追加のパラメータを指定できることは前述しました。アソシエーション宣言内で、名前と値のペアとして指定されるこれらのオプションは、アソシエーション クエリをカスタマイズするために使用されます。 select: 関連付けられた AR クラスをクエリするフィールドのリスト。 '*. ' は、すべてのフィールドを意味します。クエリされたフィールド名は、エイリアス式で曖昧さを解消できます (例: COUNT(??.name) AS nameCount)。エイリアスを使用して参照する必要があります (例: ??.id=10)。 params: SQL ステートメントにバインドされるパラメーター ()。 🎜>on: ON サブステートメント。ここで指定した条件は、AND 演算子を使用して結合条件に追加されます。ORDER BY サブステートメントのデフォルトは空であることに注意してください。
with: このオブジェクトと一緒にロードされる必要がある子関連オブジェクトのリスト 注 、不適切に使用すると、無限の関連付けループが形成される可能性があります。
joinType: デフォルトは LEFT OUTER JOIN です。
aliasToken: デフォルトは列プレフィックス「??.」です。テーブル。デフォルトは null で、テーブルの別名と関連付け名が同じであることを意味します。
together: 関連するデータ テーブルをメイン テーブルおよび他のテーブルに強制的に接続するかどうか。このオプションは、HAS_MANY および MANY_MANY 関連付けに対してのみ意味があります。このオプションが false に設定されている場合、...(ここの元のテキストは間違っています!) デフォルトは空です。このオプションのフィールド名は明確化されています。
having: HAVING サブステートメント。デフォルトは空です。列は別名を使用して参照されることに注意してください。
index: 返された配列のインデックス タイプ。返された配列がキーワードインデックス付きの配列であるか、数値インデックス付きの配列であるかを決定します。このオプションを設定しないと、配列には数値のインデックスが付けられます。このオプションは、HAS_MANY および MANY_MANY に対してのみ意味があります
さらに、次のオプションは、特定の関連付けの遅延読み込みで使用できます:
グループ: GROUP BY 句。デフォルトは空です。列はエイリアス (例: ??.age) を使用して参照する必要があることに注意してください。 このオプションは、HAS_MANY および MANY_MANY 関連付けにのみ適用されます。
having: HAVING 句。デフォルトは空です。列はエイリアス (例: ??.age) を使用して参照する必要があることに注意してください。このオプションは、HAS_MANY および MANY_MANY 関連付けにのみ適用されます。
limit: クエリされる行数を制限します。このオプションは、BELONGS_TO 関連付けには使用できません。
オフセット: オフセット。このオプションは、BELONGS_TO 関連付けには使用できません。
次に、上記のオプションのいくつかを使用して、User の投稿関連付け宣言を変更します。
class User extends CActiveRecord
{
パブリック関数 relationship()
{
return array(
'posts'=>array(self::HAS_MANY, '投稿', 'author_id',
'order'=>'posts.create_time DESC',
'with'=>category'),
' profile'=>array(self::HAS_ONE, 'Profile', 'owner_id'),
);
}
}
今$author->posts にアクセスすると、ユーザーの投稿が公開時間の降順で並べ替えられ、各投稿インスタンスもそのカテゴリとともに読み込まれます。