9.5. Zend_Db_Table

9.5.1. テーブルクラスについて

Zend_Db_Table クラスは、データベースのテーブルへの オブジェクト指向のインターフェイスです。 テーブルに対するさまざまな共通操作のためのメソッドを提供します。 基底クラスは拡張可能なので、独自のロジックを組み込むこともできます。

Zend_Db_Table は、 テーブルデータゲートウェイ パターンを実装したものです。また、そのほかにも 行データゲートウェイ パターンを実装したクラスも含んでいます。

9.5.2. テーブルクラスの定義

データベース内でアクセスしたいテーブルそれぞれについて、 Zend_Db_Table_Abstract を継承したクラスを定義します。

9.5.2.1. テーブル名およびスキーマの定義

そのクラスが定義しているデータベースのテーブルを定義するには、 protected な変数 $_name を使用します。 これは文字列で、データベースでのテーブル名を指定する必要があります。

例 9.38. テーブル名を明示的に指定することによるテーブルクラスの宣言

<?php

class Bugs extends Zend_Db_Table_Abstract
{
    protected $_name = 'bugs';
}

テーブル名を指定しなかった場合のデフォルトは、クラス名となります。 このデフォルトを使用する場合は、クラス名をデータベースでのテーブル名と一致させる必要があります。

例 9.39. テーブル名を暗黙的に指定することによるテーブルクラスの宣言

<?php

class bugs extends Zend_Db_Table_Abstract
{
    // テーブル名とクラス名が一致します
}

?>

テーブルのスキーマについても、protected 変数 $_schema で宣言することができます。 あるいは $_name プロパティでテーブル名の前にスキーマ名をつなげて指定することもできます。 $_name で指定したスキーマのほうが、 $_schema プロパティで指定したスキーマよりも優先されます。 RDBMS によってはスキーマのことを「データベース」や「表領域」 などということもありますが、同じように使用できます。 スキーマを、テーブル名の一部として宣言することもできます。

例 9.40. テーブルクラスでのスキーマの宣言

<?php

// 一つ目の方法

class Bugs extends Zend_Db_Table_Abstract
{
    protected $_schema = 'bug_db';
    protected $_name   = 'bugs';
}

// 二つ目の方法

class Bugs extends Zend_Db_Table_Abstract
{
    protected $_name = 'bug_db.bugs';
}

// スキーマを $_name と $_schema の両方で指定した場合は、
// $_name で指定したものが優先されます

class Bugs extends Zend_Db_Table_Abstract
{
    protected $_name   = 'bug_db.bugs';
    protected $_schema = 'ignored';
}

?>

スキーマ名とテーブル名は、コンストラクタの設定ディレクティブでも指定することができます。 これは、$_name$_schema といったプロパティで設定したデフォルト値を上書きします。 name ディレクティブで指定したスキーマ名は、 schema オプションで指定したスキーマ名より優先されます。

例 9.41. インスタンス作成時のテーブル名とスキーマ名の指定

<?php

class Bugs extends Zend_Db_Table_Abstract
{
}

// 最初の方法

$tableBugs = new Bugs(array('name' => 'bugs', 'schema' => 'bug_db'));

// もうひとつの方法

$tableBugs = new Bugs(array('name' => 'bug_db.bugs');

// スキーマを 'name' と 'schema' の両方で指定した場合は、
// 'name' で指定したものが優先されます

$tableBugs = new Bugs(array('name' => 'bug_db.bugs', 'schema' => 'ignored');

?>

スキーマ名を指定しなかった場合のデフォルトは、 そのデータベースアダプタが接続しているスキーマとなります。

9.5.2.2. テーブルの主キーの定義

すべてのテーブルは主キーを持つべきです。 主キーカラムを宣言するには、protected 変数 $_primary を使用します。 これは、単一のカラムの名前を表す文字列か、 もし主キーが複合キーの場合はカラム名の配列となります。

例 9.42. 主キーを指定する例

<?php

class Bugs extends Zend_Db_Table_Abstract
{
    protected $_name = 'bugs';
    protected $_primary = 'bug_id';
}

?>

主キーを指定しなかった場合は、Zend_Db_Table_Abstract は describeTable() メソッドの情報に基づいて主キーを見つけます。

9.5.2.3. テーブルの設定メソッドのオーバーライド

テーブルクラスのインスタンスを作成する際に、 コンストラクタ内でいくつかの protected メソッドをコールします。 これにより、テーブルのメタデータを初期化します。 これらのメソッドを拡張して、メタデータを明示的に定義することも可能です。 その場合は、メソッドの最後で親クラスの同名のメソッドをコールすることを忘れないようにしましょう。

例 9.43. _setupTableName() メソッドのオーバーライドの例

<?php

class Bugs extends Zend_Db_Table_Abstract
{
    protected function _setupTableName()
    {
        $this->_name = 'bugs';
        parent::_setupTableName();
    }
}

?>

オーバーライドできるメソッドは、次のとおりです。

  • _setupDatabaseAdapter() は、アダプタが設定されているかどうかを調べ、 必要に応じてレジストリからデフォルトのアダプタを取得します。 このメソッドをオーバーライドすると、 データベースアダプタを別の場所から取得できます。

  • _setupTableName() は、デフォルトのテーブル名をクラス名に設定します。 このメソッドをオーバーライドすると、 この処理の前にテーブル名を指定することができます。

  • _setupMetadata() はテーブル名が "schema.table" 形式の場合にスキーマを設定し、 describeTable() をコールしてメタデータ情報を取得します。 このメソッドが返す配列のカラム $_cols の情報をデフォルトで使用します。 このメソッドをオーバーライドすると、カラムを指定することができます。

  • _setupPrimaryKey() はデフォルトの主キーを describeTable() から取得した内容に設定し、配列 $_cols に主キーカラムが含まれているかどうかを調べます。 このメソッドをオーバーライドすると、主キーカラムを指定することができます。

9.5.3. テーブルのインスタンスの作成

テーブルクラスを使用する前に、コンストラクタでそのインスタンスを作成します。 コンストラクタの引数はオプションの配列となります。 テーブルのコンストラクタのオプションのうち、最も重要なのは データベースアダプタのインスタンスとなります。 これは RDBMS への有効な接続を表します。 データベースアダプタをテーブルクラスに指定する方法は三通りあります。 それぞれについて、以下で説明します。

9.5.3.1. データベースアダプタの指定

データベースアダプタをテーブルクラスに指定する最初の方法は、 Zend_Db_Adapter_Abstract 型のオブジェクトをオプションの配列で渡すことです。 配列のキーは 'db' となります。

例 9.44. アダプタオブジェクトを使用した、テーブルの作成の例

<?php

$db = Zend_Db::factory('PDO_MYSQL', $options);

$table = new Bugs(array('db' => $db));

?>

9.5.3.2. デフォルトのデータベースアダプタの設定

データベースアダプタをテーブルクラスに指定する二番目の方法は、 デフォルトのデータベースアダプタとして Zend_Db_Adapter_Abstract 型のオブジェクトを宣言することです。そのアプリケーション内で、 これ以降に作成したテーブルインスタンスについてこれが用いられます。 これを行うには、静的メソッド Zend_Db_Table_Abstract::setDefaultAdapter() を使用します。引数は、Zend_Db_Adapter_Abstract 型のオブジェクトとなります。

例 9.45. デフォルトアダプタを使用した、テーブルの作成の例

<?php

$db = Zend_Db::factory('PDO_MYSQL', $options);
Zend_Db_Table_Abstract::setDefaultAdapter($db);

// その後...

$table = new Bugs();

?>

これは、たとえば起動ファイルなどでデータベースアダプタオブジェクトを作成し、 それをデフォルトのアダプタとして保存しておく場合などに便利です。 これにより、アプリケーション全体で共通のアダプタを使用することが保証されます。 しかし、デフォルトのアダプタのインスタンスは、ひとつだけしか設定できません。

9.5.3.3. データベースアダプタのレジストリへの保存

データベースアダプタをテーブルクラスに指定する三番目の方法は、 文字列ををオプションの配列で渡すことです。 配列のキーは、この場合も 'db' となります。 この文字列は、静的な Zend_Registry インスタンスのキーとして使用します。 このキーのエントリが Zend_Db_Adapter_Abstract 型のオブジェクトとなります。

例 9.46. レジストリのキーを使用した、テーブルの作成の例

<?php

$db = Zend_Db::factory('PDO_MYSQL', $options);
Zend_Registry::set('my_db', $db);

// その後...

$table = new Bugs(array('db' => 'my_db'));

?>

デフォルトアダプタの指定と同様、これにより、 アプリケーション全体で共通のアダプタを使用することが保証されます。 レジストリには複数のアダプタインスタンスを保存できるため、 より柔軟に使用できます。指定したアダプタインスタンスは 特定の RDBMS やデータベースインスタンスに固有のものとなります。 複数のデータベースにアクセスする必要がある場合は、 複数のアダプタが必要です。

9.5.4. テーブルへの行の挿入

テーブルオブジェクトを使用して、そのオブジェクトの元になっているテーブルに 行を挿入することができます。そのためには、テーブルオブジェクトの insert() メソッドを使用します。引数は連想配列で、 カラム名と値の対応を指定します。

例 9.47. テーブルへの挿入の例

<?php

$table = new Bugs();

$data = array(
    'created_on'      => '2007-03-22',
    'bug_description' => 'Something wrong',
    'bug_status'      => 'NEW'
);

$table->insert($data);

?>

デフォルトでは、配列内の値はリテラル値として扱われ、 パラメータを使用して挿入されます。これを SQL の式として扱いたい場合は、 文字列ではない形式で指定する必要があります。その際には Zend_Db_Expr 型のオブジェクトを使用します。

例 9.48. 式をテーブルに挿入する例

<?php

$table = new Bugs();

$data = array(
    'created_on'      => new Zend_Db_Expr('CURDATE()'),
    'bug_description' => 'Something wrong',
    'bug_status'      => 'NEW'
);

?>

上の例では、テーブルには自動インクリメントの主キーがあるものとします。 これは Zend_Db_Table_Abstract のデフォルトの挙動ですが、 それ以外の形式の主キーも扱えます。以下の節では、 さまざまな形式の主キーを扱う方法を説明します。

9.5.4.1. 自動インクリメントのキーを持つテーブルの使用

自動インクリメントの主キーは、SQL の INSERT 文で主キー列を省略した場合に一意な整数値を生成します。

Zend_Db_Table_Abstract で protected 変数 $_sequence の値を boolean の true にすると、そのテーブルは自動インクリメントの主キーを持つものとみなされます。

例 9.49. 自動インクリメントの主キーを持つテーブルを宣言する例

<?php

class Bugs extends Zend_Db_Table_Abstract
{
    protected $_name = 'bugs';

    // これは Zend_Db_Table_Abstract クラスのデフォルト設定です。
    // 特に定義する必要はありません。
    protected $_sequence = true;
}

?>

MySQL、Microsoft SQL Server そして SQLite などの RDBMS が、主キーの自動インクリメントをサポートしています。

PostgreSQL の SERIAL 記法を使用すると、 テーブル名とカラム名をもとにして暗黙的にシーケンスを定義します。 新しい行を作成した際にはこのシーケンスを用いてキーの値を生成します。 IBM DB2 には、これと同等の動作をする IDENTITY という記法があります。 これらの記法を使用する場合は、Zend_Db_Table クラスで $_sequencetrue と設定し、 自動インクリメントを有効にしてください。

9.5.4.2. シーケンスを持つテーブルの使用

シーケンスとはデータベースのオブジェクトの一種で、 一意な値を生成するものです。これを、 ひとつあるいは複数のテーブルの主キーの値として使用できます。

$_sequence に文字列を設定すると、 Zend_Db_Table_Abstract は、それがデータベースの シーケンスオブジェクトの名前であるとみなします。 シーケンスを実行して新しい値を生成し、その値を INSERT 操作で使用します。

例 9.50. シーケンスを用いたテーブルを宣言する例

<?php

class Bugs extends Zend_Db_Table_Abstract
{
    protected $_name = 'bugs';

    protected $_sequence = 'bug_sequence';
}

?>

Oracle、PostgreSQL そして IBM DB2 などの RDBMS が、 データベースでのシーケンスオブジェクトをサポートしています。

9.5.4.3. 自然キーを持つテーブルの使用

自然キーを持つテーブルもあります。自然キーとは、 テーブルやシーケンスによって自動生成されるもの以外のキーということです。 この場合は、主キーの値を指定する必要があります。

$_sequence の値を boolean の false にすると、Zend_Db_Table_Abstract はそのテーブルが自然キーを持つものとみなします。 insert() メソッドを使用する際には、 主キーカラムの値をデータの配列で指定する必要があります。 指定しなかった場合、このメソッドは Zend_Db_Table_Exception をスローします。

例 9.51. 自然キーを用いたテーブルを宣言する例

<?php

class BugStatus extends Zend_Db_Table_Abstract
{
    protected $_name = 'bug_status';

    protected $_sequence = false;
}

?>
[注意] 注意

自然キーのテーブルは、すべての RDBMS がサポートしています。 自然キーを使用するテーブルの例としては、 ルックアップテーブルや多対多リレーションの中間テーブル、 そして複合主キーを持つ大半のテーブルなどがあります。

9.5.5. テーブルの行の更新

データベースのテーブルの行を更新するには、テーブルクラスの update メソッドを使用します。 このメソッドには二つの引数を指定します。変更するカラムと それらのカラムに代入する新しい値を表す連想配列、 そして UPDATE 操作の対象となる行を指定する WHERE 句で使用する SQL 式です。

例 9.52. テーブルの行の更新の例

<?php

$table = new Bugs();

$data = array(
    'updated_on'      => '2007-03-23',
    'bug_status'      => 'FIXED'
);

$where = $table->getAdapter()->quoteInto('bug_id = ?', 1234);

$table->update($data, $where);

?>

テーブルの update() メソッドはデータベースアダプタの update() メソッドへのプロキシなので、 二番目の引数は、SQL 式の配列とすることができます。 その場合、それぞれの式が論理演算子 AND で連結されます。

[注意] 注意

SQL 式の中の値や識別子は、自動的にはクォートされません。 クォートが必要な値や識別子を使用する場合は、自分でクォートする必要があります。 データベースアダプタの quote()quoteInto() および quoteIdentifier() を使用してください。

9.5.6. テーブルからの行の削除

データベースのテーブルから行を削除するには、テーブルクラスの delete() メソッドを使用します。 このメソッドにはひとつの引数を指定します。この引数は WHERE 句で使用する SQL 式で、 これにより、削除対象となる行を指定します。

例 9.53. テーブルからの行の削除の例

<?php

$table = new Bugs();

$where = $table->getAdapter()->quoteInto('bug_id = ?', 1235);

$table->delete($where);

?>

二番目の引数は、SQL 式の配列とすることができます。 その場合、それぞれの式が論理演算子 AND で連結されます。

テーブルの delete() メソッドはデータベースアダプタの delete() メソッドへのプロキシなので、 二番目の引数は、SQL 式の配列とすることができます。 その場合、それぞれの式が論理演算子 AND で連結されます。

[注意] 注意

SQL 式の中の値や識別子は、自動的にはクォートされません。 クォートが必要な値や識別子を使用する場合は、自分でクォートする必要があります。 データベースアダプタの quote()quoteInto() および quoteIdentifier() を使用してください。

9.5.7. 主キーによる行の検索

データベースのテーブルに対して、指定した主キーの値に対応する行を問い合わせるには find() メソッドを使用します。 このメソッドの最初の引数は、テーブルの主キーに対応する 単一の値か、あるいは複数の値の配列となります。

例 9.54. 主キーの値によって行を捜す例

<?php

$table = new Bugs();

// 単一の行を探し、
// Rowset を返します
$rows = $table->find(1234);

// 複数の行を探し、
// こちらも Rowset を返します
$rows = $table->find(array(1234, 5678));

?>

単一の値を指定した場合は、このメソッドが返す行数は最大でも一行になります。 主キーの値が重複することはないので、指定した値に対応する行は テーブル内で最大でも一行だけだからです。 複数の値を配列で指定した場合は、このメソッドが返す結果の最大数は 配列で指定した値の数となります。

find() メソッドの返す行数は、主キーで指定した値より少なくなるかもしれません。 たとえば指定した値に対応する行がデータベースのテーブルに存在しなかった場合などです。 このメソッドが返す行数がゼロになる可能性もあります。 このように結果の行数が可変なので、find() メソッドが返すオブジェクトの型は Zend_Db_Table_Rowset_Abstract となります。

主キーが複合キーの場合、つまり複数のカラムから構成されるキーの場合は、 追加のカラムを find() メソッドの引数で指定します。 テーブルの主キーのカラム数と同じ数の引数を指定しなければなりません。

複合主キーのテーブルから複数行を取得するには、 各引数を配列で指定します。これらすべての配列の要素数は同じでなければなりません。 各配列の値が、その順にキー列の値として用いられます。 たとえば、すべての配列の最初の要素で複合主キーの最初の値を指定し、 すべての配列の二番目の要素で複合主キーの二番目の値を設定し、…… というようになります。

例 9.55. 複合主キーの値の指定による行の取得の例

以下の find() メソッドは、データベース内のふたつの行にマッチします。 最初の行の主キーの値は (1234, 'ABC') で、次の行の主キーの値は (5678, 'DEF') となります。

<?php

class BugsProducts extends Zend_Db_Table_Abstract
{
    protected $_name = 'bugs_products';
    protected $_primary = array('bug_id', 'product_id');
}

$table = new BugsProducts();

// 単一の行を複合主キーで探し、
// Rowset を返します
$rows = $table->find(1234, 'ABC');

// 複数の行を複合主キーで探し、
// こちらも Rowset を返します
$rows = $table->find(array(1234, 5678), array('ABC', 'DEF'));

?>

9.5.8. 行セットの問い合わせ

主キーの値以外を条件として行のセットを問い合わせるには、 テーブルクラスの fetchAll() メソッドを使用します。 このメソッドは、Zend_Db_Table_Rowset_Abstract 型のオブジェクトを返します。

例 9.56. 式から行を取得する例

<?php

$table = new Bugs();

$where = $table->getAdapter()->quoteInto('bug_status = ?', 'NEW');

$rows = $table->fetchAll($where);

?>

このメソッドの最初の引数は WHERE 句で使用する SQL 式です。 先ほど update() メソッドや delete() メソッドで説明したものと似ています。

[注意] 注意

SQL 式の中の値や識別子は、自動的にはクォートされません。 クォートが必要な値や識別子を使用する場合は、自分でクォートする必要があります。 データベースアダプタの quote()quoteInto() および quoteIdentifier() を使用してください。

二番目の引数は、単一の式あるいは複数の式の配列です。これは、 ORDER BY 句の並べ替え条件として使用します。

三番目および四番目の引数は、件数およびオフセットを表す整数値です。 クエリの結果の特定の一部を返すために使用します。 これらの値は LIMIT 句で用いられます。 LIMIT 構文をサポートしていない RDBMS では、それと同等のロジックで用いられます。

例 9.57. 式を使用した行の検索の例

<?php

$table = new Bugs();

$where  = $table->getAdapter()->quoteInto('bug_status = ?', 'NEW');

$order  = 'bug_id';

// 21 番目から 30 番目の行を返します
$count  = 10;
$offset = 20;

$rows = $table->fetchAll($where, $order, $count, $offset);

?>

これらのオプションはどれも、必須ではありません。 引数を省略した場合は、結果セットには テーブルのすべての行が含まれ、その順序は予測不可能です。

9.5.9. 単一の行の問い合わせ

主キーの値以外を条件として単一の行を問い合わせるには、 テーブルクラスの fetchRow() メソッドを使用します。 このメソッドの使用法は fetchAll() メソッドと似ており、 引数には WHERE の式および並べ替えの条件を指定します。

例 9.58. 式から単一の行を取得する例

<?php

$table = new Bugs();

$where  = $table->getAdapter()->quoteInto('bug_status = ?', 'NEW');

$order  = 'bug_id';

$row = $table->fetchRow($where, $order);

?>

このメソッドは、Zend_Db_Table_Row_Abstract 型のオブジェクトを返します。 指定した検索条件に一致する行がデータベースのテーブルにない場合は、 fetchRow() は PHP の null 値を返します。

9.5.10. テーブルのメタデータ情報の取得

Zend_Db_Table_Abstract クラスは、メタデータに関するいくつかの情報を提供します。 info() メソッドは配列を返し、その中には テーブルについての情報、カラムや主キー、その他のメタデータが含まれます。

例 9.59. テーブル名を取得する例

<?php

$table = new Bugs();

$info = $table->info();

echo "テーブル名は " . $info['name'] . " です\n";

?>

info() メソッドが返す配列のキーについて、 以下にまとめます。

  • name => テーブルの名前。

  • cols => テーブルのカラム名を表す配列。

  • primary => 主キーのカラム名を表す配列。

  • metadata => カラム名とカラムに関する情報を関連付けた連想配列。 これは describeTable() メソッドが返す情報です。

  • rowClass => このテーブルインスタンスのメソッドが返す行オブジェクトで使用する 具象クラス名。デフォルトは Zend_Db_Table_Row です。

  • rowsetClass => このテーブルインスタンスのメソッドが返す行セットオブジェクトで使用する 具象クラス名。デフォルトは Zend_Db_Table_Rowset です。

  • referenceMap => このテーブルから任意の親テーブルに対する参照の情報を含む連想配列。 項9.8.2. 「リレーションの定義」 を参照ください。

  • dependentTables => このテーブルを参照しているテーブルのクラス名の配列。 項9.8.2. 「リレーションの定義」 を参照ください。

  • schema => テーブルのスキーマ (あるいはデータベース、あるいは表領域) の名前。

9.5.11. テーブルのメタデータのキャッシュ

デフォルトでは Zend_Db_Table_Abstract の問合せ先は テーブルオブジェクトのインスタンスの テーブルメタデータ が指すデータベースとなります。 つまり、テーブルオブジェクトを作成する際にデフォルトで行われれることは、アダプタの describeTable() メソッドによってデータベースからテーブルのメタデータを取得するということになります。

同一のテーブルに対して複数のテーブルオブジェクトを作成する場合などに、 毎回テーブルのめたデータをデータベースに問い合わせることは パフォーマンスの観点からも好ましくありません。 このような場合のために、データベースから取得したテーブルメタデータをキャッシュしておくことができます。

テーブルのメタデータをキャッシュする主な方法は、次のふたつです。

  • Zend_Db_Table_Abstract::setDefaultMetadataCache() をコールする - これは、すべてのテーブルクラスで使用するデフォルトのキャッシュオブジェクトを一度で設定できます。

  • Zend_Db_Table_Abstract::__construct() を設定する - これは、特定のテーブルクラスのインスタンスでh使用するキャッシュオブジェクトを設定できます。

どちらの場合においても、メソッドの引数はひとつで、null (キャッシュを使用しない) あるいは Zend_Cache_Core のインスタンスを指定します。これらを組み合わせることで、 デフォルトのメタデータキャッシュを指定した上で 特定のテーブルオブジェクトについてのみ別のキャッシュを使用させることができます。

例 9.60. すべてのテーブルオブジェクトでのデフォルトのメタデータキャッシュの使用

次のコードは、デフォルトのメタデータキャッシュをすべてのテーブルオブジェクトで使用する方法を示すものです。

<?php

// まずキャッシュを作成します

require_once 'Zend/Cache.php';

$frontendOptions = array(
    'automatic_serialization' => true
    );

$backendOptions  = array(
    'cacheDir'                => 'cacheDir'
    );

$cache = Zend_Cache::factory('Core', 'File', $frontendOptions, $backendOptions);


// 次に、それをすべてのテーブルオブジェクトで使用するように設定します

require_once 'Zend/Db/Table/Abstract.php';

Zend_Db_Table_Abstract::setDefaultMetadataCache($cache);


// テーブルクラスも必要です

class Bugs extends Zend_Db_Table_Abstract
{
    // ...
}


// Bugs の各インスタンスは、これでデフォルトのメタデータキャッシュを用いるようになります

$bugs = new Bugs();

?>

例 9.61. 特定のテーブルオブジェクトでのメタデータキャッシュの使用

次のコードは、メタデータキャッシュを特定のテーブルオブジェクトに設定する方法を示すものです。

<?php

// まずキャッシュを作成します

require_once 'Zend/Cache.php';

$frontendOptions = array(
    'automatic_serialization' => true
    );

$backendOptions  = array(
    'cacheDir'                => 'cacheDir'
    );

$cache = Zend_Cache::factory('Core', 'File', $frontendOptions, $backendOptions);


// テーブルクラスとそのインスタンスを作成します

require_once 'Zend/Db/Table/Abstract.php';

class Bugs extends Zend_Db_Table_Abstract
{
    // ...
}

$bugs = new Bugs();


// このテーブルオブジェクトでキャッシュを使用するように設定します

$bugs->setMetadataCache($cache);

// $bugs は、メタデータ情報をキャッシュします


// あるいは、インスタンスの作成時にこのように設定することもできます

$bugs = new Bugs(array('metadataCache' => $cache));

?>
[注意] キャッシュのフロントエンドにおける自動シリアライズ

アダプタの describeTable() メソッドの返す内容は配列なので、 Zend_Cache_Core フロントエンドのオプション automatic_serializationtrue と設定しましょう。

上の例では Zend_Cache_Backend_File を使用していますが、 状況に応じて適切なバックエンドを使い分けることができます。詳細な情報は Zend_Cache を参照ください。

9.5.12. テーブルクラスのカスタマイズおよび拡張

9.5.12.1. 独自の行クラスあるいは行セットクラスの使用

デフォルトでは、テーブルクラスが返す行セットは 具象クラス Zend_Db_Table_Rowset のインスタンスであり、 行セットには具象クラス Zend_Db_Table_Row のインスタンスの集合が含まれます。 これらのいずれについても、別のクラスを使用することが可能です。 しかし、使用するクラスはそれぞれ Zend_Db_Table_Rowset_Abstract および Zend_Db_Table_Row_Abstract を継承したものでなければなりません。

行クラスおよび行セットクラスを指定するには、 テーブルのコンストラクタのオプション配列を使用します。 対応するキーは、それぞれ 'rowClass' および 'rowsetClass' となります。 ここには、クラスの名前を文字列で指定します。

例 9.62. 行クラスおよび行セットクラスの指定の例

<?php

class My_Row extends Zend_Db_Table_Row_Abstract
{
    ...
}

class My_Rowset extends Zend_Db_Table_Rowset_Abstract
{
    ...
}

$table = new Bugs(
    array(
        'rowClass'    => 'My_Row',
        'rowsetClass' => 'My_Rowset'
    )
);

$where = $table->getAdapter()->quoteInto('bug_status = ?', 'NEW')

// My_Rowset 型のオブジェクトを返します。
// その中には My_Row 型のオブジェクトの配列が含まれます。
$rows = $table->fetchAll($where);

?>

クラスを変更するには、setRowClass() メソッドおよび setRowsetClass() メソッドを使用します。 これは、それ以降に作成される行および行セットに適用されます。 すでに出来上がっている行オブジェクトや行セットオブジェクトには 何の影響も及ぼしません。

例 9.63. 行クラスおよび行セットクラスの変更の例

<?php

$table = new Bugs();

$where = $table->getAdapter()->quoteInto('bug_status = ?', 'NEW')

// Zend_Db_Table_Rowset 型のオブジェクトを返します。
// その中には Zend_Db_Table_Row 型のオブジェクトの配列が含まれます。
$rowsStandard = $table->fetchAll($where);

$table->setRowClass('My_Row');
$table->setRowsetClass('My_Rowset');

// My_Rowset 型のオブジェクトを返します。
// その中には My_Row 型のオブジェクトの配列が含まれます。
$rowsCustom = $table->fetchAll($where);

// $rowsStandard オブジェクトはまだ存在しますが、なにも変更されていません

?>

行クラスおよび行セットクラスについての詳細は 項9.6. 「Zend_Db_Table_Row」 および 項9.7. 「Zend_Db_Table_Rowset」 を参照ください。

9.5.12.2. Insert、Update および Delete 時の独自ロジックの定義

テーブルクラスの insert() メソッドや update() メソッドをオーバーライドすることができます。 これにより、データベース操作の前に実行される独自のコードを実装することができます。 最後に親クラスのメソッドをコールすることを忘れないようにしましょう。

例 9.64. タイムスタンプを処理する独自ロジック

<?php

class Bugs extends Zend_Db_Table_Abstract
{
    protected $_name = 'bugs';

    public function insert(array $data)
    {
        // タイムスタンプを追加します
        if (empty($data['created_on'])) {
            $data['created_on'] = time();
        }
        return parent::insert($data);
    }

    public function update(array $data, $where)
    {
        // タイムスタンプを追加します
        if (empty($data['updated_on'])) {
            $data['updated_on'] = time();
        }
        return parent::update($data, $where);
    }
}

?>

delete() メソッドをオーバーライドすることもできます。

9.5.12.3. Zend_Db_Table における独自の検索メソッドの定義

もし特定の条件によるテーブルの検索を頻繁に行うのなら、 独自の検索メソッドをテーブルクラスで実装することができます。 大半の問い合わせは fetchAll() を用いて書くことができますが、 アプリケーション内の複数の箇所でクエリを実行する場合には 問い合わせ条件を指定するコードが重複してしまいます。 そんな場合は、テーブルクラスでメソッドを実装し、 よく使う問い合わせを定義しておいたほうが便利です。

例 9.65. 状況を指定してバグを検索する独自メソッド

<?php

class Bugs extends Zend_Db_Table_Abstract
{
    protected $_name = 'bugs';

    public function findByStatus($status)
    {
        $where = $this->getAdapter()->quoteInto('bug_status = ?', $status);
        return $this->fetchAll($where, 'bug_id');
    }
}

?>

9.5.12.4. Zend_Db_Table における語尾変化の定義

テーブルのクラス名を RDBMS のテーブル名とあわせるために、 inflection (語尾変化) と呼ばれる文字列変換を使用することを好む方もいます。

たとえば、テーブルのクラス名が "BugsProducts" だとすると、クラスのプロパティ $_name を明示的に宣言しなかった場合は データベース内の物理的なテーブル "bugs_products" にマッチします。この関連付けでは、 "CamelCase" 形式のクラス名が小文字に変換され、単語の区切りがアンダースコアに変わります。

データベースのテーブル名を、クラス名とは独立したものにすることもできます。 その場合は、テーブルクラスのプロパティ $_name に、そのクラス名を指定します。

Zend_Db_Table_Abstract は、クラス名とテーブル名を関連付けるための語尾変化は行いません。 テーブルクラスで $_name の宣言を省略すると、 そのクラス名に正確に一致する名前のテーブルと関連付けられます。

データベースの識別子を変換することは、適当ではありません。 なぜなら、それは不明確な状態を引き起こし、 時には識別子にアクセスできなくなってしまうからです。 SQL の識別子をデータベース内にあるそのままの形式で扱うことで、 Zend_Db_Table_Abstract はシンプルで柔軟なものになっています。

語尾変化を行いたい場合は、その変換を独自に実装しなければなりません。そのためには テーブルクラスで _setupTableName() メソッドをオーバーライドします。 これを行うひとつの方法としては、Zend_Db_Table_Abstract を継承した抽象クラスを作成し、さらにそれを継承したテーブルクラスを作成するという方法があります。

例 9.66. 語尾変化を実装した抽象テーブルクラスの例

<?php

abstract class MyAbstractTable extends Zend_Db_Table_Abstract
{
    protected function _setupTableName()
    {
        if (!$this->_name) {
            $this->_name = myCustomInflector(get_class($this));
        }
        parent::_setupTableName();
    }
}

class BugsProducts extends MyAbstractTable
{
}

?>

語尾変化を行う関数を書くのはあなたの役割です。 Zend Framework にはそのような関数はありません。