1 <?xml version="1.0" encoding="UTF-8"?>
3 <!-- EN-Revision: 20766 -->
4 <sect1 id="zend.db.table.row">
6 <title>Zend_Db_Table_Row</title>
8 <sect2 id="zend.db.table.row.introduction">
13 <classname>Zend_Db_Table_Row</classname> は、<classname>Zend_Db_Table</classname> オブジェクトの個々の行を含むクラスです。
14 テーブルクラスに対してクエリを実行すると、返される結果は
15 <classname>Zend_Db_Table_Row</classname> オブジェクトのセットとなります。
16 このオブジェクトを使用して新しい行を作成し、
17 それをデータベースのテーブルに追加することもできます。
21 <classname>Zend_Db_Table_Row</classname> は、
22 <ulink url="http://www.martinfowler.com/eaaCatalog/rowDataGateway.html">
23 行データゲートウェイ</ulink>パターンを実装したものです。
28 <sect2 id="zend.db.table.row.read">
33 <classname>Zend_Db_Table_Abstract</classname> は <methodname>find()</methodname> や
34 <methodname>fetchAll()</methodname> といったメソッドを提供します。
35 これらはそれぞれ <classname>Zend_Db_Table_Rowset</classname> 型のオブジェクトを返します。
36 また <methodname>fetchRow()</methodname> メソッドは、
37 <classname>Zend_Db_Table_Row</classname> 型のオブジェクトを返します。
40 <example id="zend.db.table.row.read.example">
44 <programlisting language="php"><![CDATA[
46 $row = $bugs->fetchRow($bugs->select()->where('bug_id = ?', 1));
52 <classname>Zend_Db_Table_Rowset</classname> オブジェクトには、複数の
53 <classname>Zend_Db_Table_Row</classname> オブジェクトが含まれます。
54 詳細については <link linkend="zend.db.table.rowset">table rowset</link> についての章を参照ください。
57 <example id="zend.db.table.row.read.example-rowset">
59 <title>行セット内の行を読み込む例</title>
61 <programlisting language="php"><![CDATA[
63 $rowset = $bugs->fetchAll($bugs->select()->where('bug_status = ?', 1));
64 $row = $rowset->current();
69 <sect3 id="zend.db.table.row.read.get">
71 <title>行からのカラムの値の読み込み</title>
74 <classname>Zend_Db_Table_Row_Abstract</classname> にはアクセサがあり、
75 行のカラムをオブジェクトのプロパティとして参照できます。
78 <example id="zend.db.table.row.read.get.example">
80 <title>行からカラムを読み込む例</title>
82 <programlisting language="php"><![CDATA[
84 $row = $bugs->fetchRow($bugs->select()->where('bug_id = ?', 1));
86 // bug_description カラムの値を出力します
87 echo $row->bug_description;
95 初期のバージョンの <classname>Zend_Db_Table_Row</classname> では、
96 これらのアクセサをデータベースのカラムと対応させる際に
97 <emphasis>inflection (変形)</emphasis>
102 現在の <classname>Zend_Db_Table_Row</classname> では変形を実装していません。
103 使用するアクセサ名は、データベース内のカラム名と正確に一致します。
110 <sect3 id="zend.db.table.row.read.to-array">
112 <title>行データの配列としての取得</title>
115 行のデータに対して配列としてアクセスするには、行オブジェクトの
116 <methodname>toArray()</methodname> メソッドを使用します。
117 これは、カラム名とその値を関連付けた連想配列を返します。
120 <example id="zend.db.table.row.read.to-array.example">
122 <title>toArray() メソッドの使用例</title>
124 <programlisting language="php"><![CDATA[
126 $row = $bugs->fetchRow($bugs->select()->where('bug_id = ?', 1));
128 // 行オブジェクトから カラム名/値 の連想配列を取得します
129 $rowArray = $row->toArray();
132 foreach ($rowArray as $column => $value) {
133 echo "カラム: $column\n";
141 <methodname>toArray()</methodname> が返す配列は、更新できません。
143 それをデータベースに保存することはできません。
148 <sect3 id="zend.db.table.row.read.relationships">
150 <title>関連するテーブルからのデータの取得</title>
153 <classname>Zend_Db_Table_Row_Abstract</classname> クラスには、関連するテーブルから
154 行や行セットを取得するメソッドが存在します。
155 テーブルのリレーションについての詳細な情報は
156 <link linkend="zend.db.table.relationships">リレーションシップ</link>
164 <sect2 id="zend.db.table.row.write">
166 <title>データベースへの行の書き込み</title>
168 <sect3 id="zend.db.table.row.write.set">
170 <title>行のカラムの値の変更</title>
173 個々のカラムの値をアクセサで設定する方法は、
174 カラムを読み込む場合と同様で、オブジェクトのプロパティを使用します。
178 カラムのアクセサによる値の設定は、アプリケーション内の行データのカラムの値は変更しますが、
179 それだけではまだデータベースにコミットされていません。コミットするには
180 <methodname>save()</methodname> メソッドを使用します。
183 <example id="zend.db.table.row.write.set.example">
185 <title>行のカラムの内容を変更する例</title>
187 <programlisting language="php"><![CDATA[
189 $row = $bugs->fetchRow($bugs->select()->where('bug_id = ?', 1));
191 // ひとつあるいは複数のカラムの値を変更します
192 $row->bug_status = 'FIXED';
194 // データベース内の行を、新しい値で UPDATE します
202 <sect3 id="zend.db.table.row.write.insert">
204 <title>新しい行の挿入</title>
207 指定したテーブルに新しい行を作成するには、テーブルクラスの
208 <methodname>createRow()</methodname> メソッドを使用します。
209 取得した行のフィールドに対してはオブジェクト指向のインターフェイスでアクセスできますが、
210 <methodname>save()</methodname> メソッドをコールするまでは
211 実際にデータベースの内容が変更されることはありません。
214 <example id="zend.db.table.row.write.insert.example">
216 <title>テーブルに新しい行を作成する例</title>
218 <programlisting language="php"><![CDATA[
220 $newRow = $bugs->createRow();
222 // アプリケーションに応じて適切にカラムの値を設定します
223 $newRow->bug_description = '...説明...';
224 $newRow->bug_status = 'NEW';
226 // 新しい行をデータベースに INSERT します
233 <methodname>createRow()</methodname> メソッドのオプションの引数として、連想配列を渡すことができます。
234 この連想配列では、新しい行のフィールドに代入する値を指定します。
237 <example id="zend.db.table.row.write.insert.example2">
239 <title>テーブルに新しい行を作成し、値を代入する例</title>
241 <programlisting language="php"><![CDATA[
243 'bug_description' => '...説明...',
244 'bug_status' => 'NEW'
248 $newRow = $bugs->createRow($data);
250 // 新しい行をデータベースに INSERT します
259 <classname>Zend_Db_Table</classname> の初期のリリースでは、<methodname>createRow()</methodname>
260 メソッドは <methodname>fetchNew()</methodname> という名前でした。
261 今後は新しい名前を用いることを推奨しますが、
262 過去との互換性を確保するため古い名前も使用できるようになっています。
269 <sect3 id="zend.db.table.row.write.set-from-array">
271 <title>複数のカラムの値の変更</title>
274 <classname>Zend_Db_Table_Row_Abstract</classname> の
275 <methodname>setFromArray()</methodname> メソッドを使用すると、
276 ひとつの行の複数のカラムを一度に設定できます。
277 このメソッドには、カラム名と値を関連付けた連想配列を指定します。
278 このメソッドは、新しい行の値を設定する場合や
279 既存の行を更新する場合のどちらでも有用でしょう。
282 <example id="zend.db.table.row.write.set-from-array.example">
284 <title>setFromArray() で新しい行の値を設定する例</title>
286 <programlisting language="php"><![CDATA[
288 $newRow = $bugs->createRow();
292 'bug_description' => '...説明...',
293 'bug_status' => 'NEW'
296 // すべてのカラムの値を一度に設定します
297 $newRow->setFromArray($data);
299 // 新しい行をデータベースに INSERT します
307 <sect3 id="zend.db.table.row.write.delete">
312 行オブジェクトで <methodname>delete()</methodname> メソッドをコールできます。
313 これは、その行オブジェクトの主キーに対応するデータベースの行を削除します。
316 <example id="zend.db.table.row.write.delete.example">
318 <title>行の削除の例</title>
320 <programlisting language="php"><![CDATA[
322 $row = $bugs->fetchRow('bug_id = 1');
331 変更を適用するのに <methodname>save()</methodname> をコールする必要はありません。
332 これは、データベースに対して即時に適用されます。
339 <sect2 id="zend.db.table.row.serialize">
341 <title>行のシリアライズと復元</title>
345 あとで使用するということはよくありがちです。
346 オブジェクトの内容を、オフラインで保存しやすい形式 (たとえばファイルなど)
347 に変換するような処理のことを <emphasis>シリアライズ</emphasis> といいます。
348 <classname>Zend_Db_Table_Row_Abstract</classname> 型のオブジェクトは、
352 <sect3 id="zend.db.table.row.serialize.serializing">
354 <title>行のシリアライズ</title>
357 <acronym>PHP</acronym> の <methodname>serialize()</methodname> 関数を使用して、
358 行オブジェクトのバイトストリームを含む文字列を作成します。
361 <example id="zend.db.table.row.serialize.serializing.example">
363 <title>行のシリアライズの例</title>
365 <programlisting language="php"><![CDATA[
367 $row = $bugs->fetchRow('bug_id = 1');
370 $serializedRow = serialize($row);
372 // これで、$serializedRow をファイルなどに書き出すことができます
379 <sect3 id="zend.db.table.row.serialize.unserializing">
381 <title>シリアライズした行データの復元</title>
384 <acronym>PHP</acronym> の <methodname>unserialize()</methodname> 関数を使用して、
385 オブジェクトのバイトストリームを含む文字列を復元します。
386 この関数は、もとのオブジェクトを返します。
391 <emphasis>接続が切断された</emphasis> 状態であることに注意しましょう。
392 行オブジェクトやそのプロパティを読み込むことはできますが、
393 その値を変更することはできません。また、データベース接続を必要とするようなメソッド
394 (たとえば従属テーブルに対するクエリなど) も実行できません。
397 <example id="zend.db.table.row.serialize.unserializing.example">
399 <title>シリアライズした行の復元の例</title>
401 <programlisting language="php"><![CDATA[
402 $rowClone = unserialize($serializedRow);
404 // これでオブジェクトのプロパティを使用できますが、読み込み専用です
405 echo $rowClone->bug_description;
412 <title>復元した行は、なぜ切断された状態なのですか?</title>
415 シリアライズしたオブジェクトは、可読形式の文字列となります。
416 データベースのアカウントやパスワードといった情報を
417 暗号化せずにプレーンテキストにシリアライズして保存すると、
419 そのようなデータを無防備な状態でテキストファイルに保存したりしたくはないでしょう。
420 またメールなどで攻撃者に覗き見られることも好まないはずです。
422 正しい認証情報を知らない限りデータベースにアクセスすることはできません。
429 <sect3 id="zend.db.table.row.serialize.set-table">
431 <title>生きたデータとしての行の復活</title>
435 <methodname>setTable()</methodname> メソッドを使用します。このメソッドへの引数としては、
436 <classname>Zend_Db_Table_Abstract</classname> 型のオブジェクトを作成して渡します。
437 テーブルオブジェクトを作成するには、データベースとの接続が必要です。
438 そのテーブルと行を関連付けることで、行がデータベースにアクセスできるようになります。
439 それ以降は、行オブジェクトの値を変更してデータベースに保存できるようになります。
442 <example id="zend.db.table.row.serialize.set-table.example">
444 <title>行の復活の例</title>
446 <programlisting language="php"><![CDATA[
447 $rowClone = unserialize($serializedRow);
453 $rowClone->setTable($bugs);
455 // これで、行の内容を変更して保存できます
456 $rowClone->bug_status = 'FIXED';
466 <sect2 id="zend.db.table.row.extending">
468 <title>行クラスの拡張</title>
471 <classname>Zend_Db_Table_Row</classname> は、<classname>Zend_Db_Table_Row_Abstract</classname>
473 <classname>Zend_Db_Table_Row_Abstract</classname> を継承した具象クラスを新たに作成し、
474 それを用いて行のインスタンスを作成できます。
475 独自の行クラスを指定するには、テーブルクラスの protected
476 メンバである <varname>$_rowClass</varname> を使用するか、
477 テーブルオブジェクトのコンストラクタの引数の配列で指定します。
480 <example id="zend.db.table.row.extending.example">
482 <title>独自の行クラスの指定</title>
484 <programlisting language="php"><![CDATA[
485 class MyRow extends Zend_Db_Table_Row_Abstract
490 // 独自の行を、テーブルクラスの全インスタンスで
491 // デフォルトとして使用するように設定します
492 class Products extends Zend_Db_Table_Abstract
494 protected $_name = 'products';
495 protected $_rowClass = 'MyRow';
498 // あるいは、テーブルクラスの特定のインスタンスでのみ
499 // 独自の行クラスを使用するように設定します
500 $bugs = new Bugs(array('rowClass' => 'MyRow'));
505 <sect3 id="zend.db.table.row.extending.overriding">
509 行を作成する際にアプリケーション固有のロジックを初期化したい場合は、
510 その作業を <methodname>init()</methodname> メソッドに移動します。
511 このメソッドは、行のメタデータの処理がすべて終わった後にコールされます。
513 <methodname>__construct()</methodname> メソッドを使うよりもこちらのほうを推奨します。
516 <example id="zend.db.table.row.init.usage.example">
517 <title>init() メソッドの使用例</title>
519 <programlisting language="php"><![CDATA[
520 class MyApplicationRow extends Zend_Db_Table_Row_Abstract
524 public function init()
526 $this->_role = new MyRoleClass();
533 <sect3 id="zend.db.table.row.extending.insert-update">
535 <title>Zend_Db_Table_Row における Insert、Update および Delete の独自ロジックの定義</title>
538 行クラスは、<constant>INSERT</constant> や <constant>UPDATE</constant>、
539 <constant>DELETE</constant> の操作の前に、対応する protected メソッド
540 <methodname>_insert()</methodname>、<methodname>_update()</methodname>
541 および <methodname>_delete()</methodname> をコールします。
542 行クラスのサブクラスで、これらのメソッドに独自ロジックを追加できます。
546 特定のテーブルに対して独自のロジックを必要とし、
547 それがそのテーブル上のすべての操作に対して発生するのなら、
549 <methodname>insert()</methodname>、<methodname>update()</methodname> および
550 <methodname>delete()</methodname> で実装したほうがよいでしょう。
551 しかし、独自のロジックを行クラスで実装したほうがよい場合もあります。
556 テーブルクラスよりも行クラスで行ったほうがよい例を、
560 <example id="zend.db.table.row.extending.overriding-example1">
562 <title>行クラスでの独自ロジックの例</title>
565 独自ロジックが、そのテーブルのすべての操作に適用されるとは限りません。
568 その行クラスを指定してテーブルクラスのインスタンスを作成します。
569 指定しなければ、テーブルクラスはデフォルトの行クラスを使用します。
573 このテーブルでは、データに対する操作内容を <classname>Zend_Log</classname>
575 ただし、それはアプリケーションの設定でログ記録を有効にしている場合のみとします。
578 <programlisting language="php"><![CDATA[
579 class MyLoggingRow extends Zend_Db_Table_Row_Abstract
581 protected function _insert()
583 $log = Zend_Registry::get('database_log');
584 $log->info(Zend_Debug::dump($this->_data,
585 "INSERT: $this->_tableClass",
591 // $loggingEnabled はサンプルとして使用するプロパティで、
592 // これはアプリケーションの設定によって決まるものとします
593 if ($loggingEnabled) {
594 $bugs = new Bugs(array('rowClass' => 'MyLoggingRow'));
602 <example id="zend.db.table.row.extending.overriding-example2">
604 <title>挿入するデータの記録を複数のテーブルで行う行クラスの例</title>
607 複数のテーブルで、共通の独自ロジックを使用することもあるでしょう。
608 同じロジックをすべてのテーブルクラスで実装するのではなく、
609 その場合はその動作を行クラスで定義しましょう。
610 そして各テーブルでその行クラスを使用するのです。
614 この例では、ログ記録用のコードは全テーブルクラスで同一です。
617 <programlisting language="php"><![CDATA[
618 class MyLoggingRow extends Zend_Db_Table_Row_Abstract
620 protected function _insert()
622 $log = Zend_Registry::get('database_log');
623 $log->info(Zend_Debug::dump($this->_data,
624 "INSERT: $this->_tableClass",
630 class Bugs extends Zend_Db_Table_Abstract
632 protected $_name = 'bugs';
633 protected $_rowClass = 'MyLoggingRow';
636 class Products extends Zend_Db_Table_Abstract
638 protected $_name = 'products';
639 protected $_rowClass = 'MyLoggingRow';
647 <sect3 id="zend.db.table.row.extending.inflection">
649 <title>Zend_Db_Table_Row における変形の定義</title>
652 テーブルのクラス名を <acronym>RDBMS</acronym> のテーブル名とあわせるために、
653 <emphasis>inflection (変形)</emphasis>
654 と呼ばれる文字列変換を使用することを好む方もいます。
658 <classname>Zend_Db</classname> クラス群は、デフォルトでは変形をサポートしていません。
660 linkend="zend.db.table.extending.inflection">語尾変化の拡張</link>
665 変形をさせたい場合は、変換処理を自前で実装する必要があります。そのためには、
666 独自の行クラスで <methodname>_transformColumn()</methodname> メソッドをオーバーライドし、
667 テーブルクラスでクエリを実行する際にその独自行クラスを使用します。
670 <example id="zend.db.table.row.extending.inflection.example">
672 <title>変換処理の定義例</title>
675 これにより、カラム名を変形させたものでアクセスできるようになります。
676 行クラスの <methodname>_transformColumn()</methodname>
677 メソッドを使用して、データベースのテーブル内のカラム名を変更しています。
680 <programlisting language="php"><![CDATA[
681 class MyInflectedRow extends Zend_Db_Table_Row_Abstract
683 protected function _transformColumn($columnName)
685 $nativeColumnName = myCustomInflector($columnName);
686 return $nativeColumnName;
690 class Bugs extends Zend_Db_Table_Abstract
692 protected $_name = 'bugs';
693 protected $_rowClass = 'MyInflectedRow';
697 $row = $bugs->fetchNew();
699 // キャメルケース形式のカラム名を使用します。
700 // 変換関数により、これをデータベース内での実際の形式に
702 $row->bugDescription = 'New description';
709 Zend Framework では、そのような関数は用意していません。