このチュートリアルでは、DB_Table クラスを単一のデータベーステーブルへのインターフェイスとして使用する方法を説明します。 このクラスの機能には、次のようなものがあります。
カラム定義やインデックス定義の情報の、オブジェクトのプロパティへの埋め込み (可搬性の高いデータ型を使用)。
スキーマからのテーブルの作成や検証。
SELECT、INSERT、UPDATE、そして DELETE コマンドに対応したシンプルな API。
SELECT コマンドでの配列構文、そしてストアドクエリ。
カラムの値の追加・更新の際のデータ型の検証。
自動インクリメント機能のエミュレート。
カラムの定義にもとづいた、 HTML_QuickForm 要素の自動作成。
このクラスのチュートリアルは 2 ページで構成されています。 このページでは、DB_Table の全機能のうち HTML_QuickForm のフォーム生成機能以外を取り扱います。 フォーム生成機能については次のページで取り上げます。 このチュートリアルは、もともと別のサイトで公開されていた DB_Table のドキュメントをもとにしています。 このドキュメントの作者は Paul M. Jones で、今でも ここ で見ることができます。元のドキュメントには DB_Table のサブクラスの定義をカスタマイズするサンプルも含まれていますが、 それはここでは扱いません。
DB_Table クラスおよび DB_Table_Database クラスは、どちらも抽象クラス DB_Table_Base を継承しています。 DB_Table_Base から継承したメソッドやプロパティについては DB_Table あるいは DB_Table_Database オブジェクトで同じように使えます。 これらの共有メソッドやプロパティは、それぞれのマニュアルページで取り上げます。
目次
通常は、DB_Table のインスタンスを直接作成することはありません。 データベース内の各テーブルに対して DB_Table のサブクラスを作成し、そのサブクラスのインスタンスを作成することになります。 テーブルのスキーマは、このオブジェクトのプロパティとして埋め込まれています。 カラムの定義は $col プロパティの配列に格納されており、インデックスは $idx プロパティの配列に格納されています。 通常は、これらのプロパティ配列はサブクラスの定義の中で行います。 これが、テーブルのスキーマ情報を記録する場所となります。
このようなデータベースゲートウェイ、つまり RDBMS の各テーブルにクラスを関連付ける方式の利点のひとつは、 各テーブルに固有のプロパティやふるまいを適切な箇所で定義できるということです。 独自の挙動や検証機能などを作成するには、 既存のクラスメソッドをオーバーライドするか、あるいは新たなメソッドを作成します。 DB_Table には、一般的に使われる SELECT クエリ用に用いる $sql プロパティ配列もあります。
このパッケージは、RDBMS 上のテーブルとそれに対応する DB_Table サブクラスのどちらか一方があれば、 もう一方を自動的に作成することができます。 同じような内容を何度も書く必要はありません。
プログラム上でのテーブルの作成: 各テーブルに対応する DB_Table のサブクラスの定義を作成し、 そのサブクラスのインスタンスを使用してデータベース上に実際のテーブルを作成します。
リフレクションおよびコード生成: DB_Table_Generator クラスを使い、既存のデータベースから DB_Table のサブクラスの定義の雛形を作成します。 この雛形には、テーブル定義のほかに関連するコードも含まれています。
$col プロパティは連想配列で、各キーがカラム名を表します。 キーに対応する値も連想配列で、ここにカラムの定義を指定します。 カラム定義の中の必須要素 'type' の値は DB_Table の データ型 の名前である必要があります。たとえば 'integer'、'decimal'、'boolean' などです。 文字列型である 'char' および 'varchar'、数値型である 'decimal' には、 さらに 'size' 要素も必須となります。これは整数値で、文字数あるいは桁数を指定します。 また、'decimal' 型の場合は 'scope' 要素も必須です。 これは、小数点以下の桁数を表します。'require' 要素に true を指定すると、SQL における NOT NULL と同じ意味になり、 このカラムには NULL 値を格納できなくなります。
例として、GuestBook テーブルを作成することを考えてみましょう。 このテーブルには、訪問者の姓と名、メールアドレス、 そして書き込み日時を記録するものとします。さらに、 各行に一意な ID を与える必要があります。 このテーブルのカラムは次のようになるでしょう。
id -- 各行で一意な整数値 (必須。つまり null は許可しない)。
fname -- 最大 32 文字までの文字列。訪問者の名前。
lname -- 最大 64 文字までの文字列。訪問者の姓。
email -- 最大 255 文字までの文字列。訪問者のメールアドレス (必須。つまり null は許可しない)。
signdate -- 訪問者が書き込んだ日付 (必須。つまり null は許可しない)。
これらのカラム定義はプロパティ配列 $col で行う必要があります。 以下に、GuestBook_Table という名前の DB_Table サブクラスにおける $col の宣言の例を示します。これが、データベースの GuestBook テーブルに対応するものとなります。
例 39-1GuestBook のカラム定義
|
プロパティ配列 $idx を使用してインデックスを宣言します。個々のインデックスは 'primary'、'unique' あるいは 'normal' のいずれかの型で宣言します。 primary や unique を指定した場合、そのキーの値はテーブル内で一意でなければならなくなります。 normal は、単に効率を上げるためだけのインデックスです。 単一カラムのインデックスおよび複数カラムのインデックスのどちらでも定義できます。
今回の例の GuestBook では、単一カラムのインデックスをふたつ作成します。まず最初は "id" カラムに対する主キーインデックスです。もうひとつは、"signdate" カラムに通常のインデックスを作成します。訪問者を日付や時刻で検索することがあると想定されるからです。 この場合の $idx プロパティの宣言は以下のようになります。
例 39-2GuestBook のインデックス定義
|
$idx 配列における各要素のキーがインデックス名となります。 対応する値は一般的には配列となり、そのインデックスの定義がここに格納されます。 インデックスの定義配列には 'type' と 'cols' の 2 つの要素が必ず存在します。 'type' の値は 'primary'、'unique' あるいは 'normal' のいずれかとなります。 'cols' 要素の値は、単一のカラム名か単一カラム名の配列、 あるいは複数のカラム名を含む配列のいずれかとなります。 単一カラムのインデックスについては別の省略形もありますが、 それはあとで説明します。
複数カラムのインデックスの例として、fname と lname カラムに対するインデックス "namefl" を定義してみます。
例 39-3複数カラムのインデックスの定義
|
単一カラムのインデックスをお手軽に宣言するための方法も準備されています。 カラム名と同じ名前で単一カラムのインデックスを作成したい場合は、 カラム名を $idx のキーにしてそのインデックスの型を表す文字列 (定義配列ではありません) を値にします。
例 39-4単一カラムインデックスを簡単に定義する方法
|
各テーブルについてひとつの整数型カラムを、 自動インクリメントのカラムとして宣言することができます。 このカラムは、通常は主キーとなります。この宣言をすることによって変化するのは、 insert() メソッドの振る舞いだけです。 insert() メソッドを実行する際に 自動インクリメントのカラムを省略したり NULL を渡したりすると、 自動生成された整数値が挿入されます。
あるカラムを自動インクリメントとして設定するには、 $auto_inc_col プロパティの値にそのカラムの名前を指定します。次の例では、 GuestBook テーブルの主キーカラムである "id" を自動インクリメントに設定します。
例 39-5自動インクリメント指定
|
個々の DB_Table オブジェクトは、DB あるいは MDB2 のデータベース接続オブジェクトをラップしています。 これらのオブジェクトは、DB_Table のコンストラクタへの最初のパラメータとして渡します。 ひとつの DB/MDB2 オブジェクトを、 複数の DB_Table オブジェクトで共用することができます。 コンストラクタの 2 番目のパラメータには、 関連付ける RDBMS のテーブル名を指定します。 オプションの 3 番目のパラメータ $create を指定すると、 コンストラクタの実行時にテーブルが存在しなければテーブルを作成します。 テーブルが存在する場合はその構造を検証します (詳しくは後ほど説明します)。
以下の例では、GuestBook サブクラスのインスタンスを作成しています。 このクラスは GuestBook テーブルをバインドします。 $auto_create = 'safe' を指定することで、 GuestBook という名前のテーブルが存在しない場合に作成させるようにしています。 テーブルが存在する場合は何もしません。
例 39-6GuestBook_Table オブジェクトの作成
|
$create に指定できる値は以下のとおりです。
false を指定すると、作成しません (デフォルト)。
'drop' を指定すると、 同名のテーブルが存在する場合はそれを削除してから改めて作成します。
'safe' を指定すると、 テーブルが存在しない場合は作成します。 存在する場合は何もしません。
'verify' を指定すると、 テーブルが存在するかどうかを調べ、そのスキーマを検証します。 検証する内容は、すべてのカラムが存在するかどうか、 すべてのカラムの型が正しいものか、 そしてすべてのインデックスが存在して正しい型であるかどうかです。
'alter' は、テーブルが存在しない場合の挙動は 'safe' と同じです。 テーブルが存在する場合はスキーマの検証を行い、 必要に応じてスキーマを変更します。
DB_Table のメソッド insert()、 update() および delete() は、データの行を追加したり更新したり削除したりするための便利なインターフェイスです。 行を追加したり更新したりする場合は、insert メソッドや update メソッドに連想配列を渡します。この配列のキーがカラム名となります。
GuestBook テーブルに行を追加するには、 insert() メソッドを使用します。 このメソッドに渡すパラメータは連想配列で、 そのキーがカラム名、そして追加する値をキーに関連づけます。
例 39-7行の追加
|
デフォルトでは、insert メソッドは自動的にデータ型の検証を行います。 また、自動インクリメントカラム以外の必須カラムについてのデータが存在するかどうかも調べます。 これらの検証に失敗した場合は、このメソッドは PEAR Error を返し、データの追加は行いません。 上の例では必須カラム 'id' の値を指定していませんが、 これは 'id' カラムが自動インクリメント型だからです。 詳しくは以下で説明します。
DB_Table は、 DB あるいは MDB2 が作成したシーケンスを使用して自動インクリメントの整数型の ID を生成することができます。insert メソッドで 自動インクリメント型のカラムの値が設定されていなかったり PHP の NULL が設定されていたりした場合は、 自動インクリメントのシーケンスの値を使用してそのカラムにデータを追加します。 上の例では、'id' カラムに対して、 シーケンスの値を取得して追加します。 しかし、insert メソッドで追加する値が指定されていた場合はそちらを使用します。
DB や MDB2 のシーケンス生成機能に直接アクセスするには DB_Table::nextID() メソッドを使用します。 このメソッドは単なるラッパーで、内部では DB あるいは MDB2 の対応するメソッドをコールしています。 次の例では、nextID() を使用して自動インクリメントの値を生成し、 その値を追加するようにしています。
例 39-8nextID() によるシーケンスへのアクセス
|
update() メソッドは、 単一の行あるいは複数行のセットのデータを用いた更新を行います。 このメソッドのパラメータは 2 つです。最初のパラメータは連装配列で、 更新するカラム名がキー、更新する値が連装配列の値となります。 2 番目の引数は、SQL の UPDATE 文で使用する WHERE 句を表す文字列です。 ただし WHERE キーワードそのものは含めません。
たとえば、すべての行で姓を "Smith" から "Jones" に変更するには次のようにします。
例 39-9行のセットの更新
|
insert の場合と同様、カラムの宣言の際に指定した型と違う型の値で更新しようとすると update は失敗します。この場合は PEAR Error を返します。
delete() メソッドは、 条件を満たす行あるいは行のセットを削除します。 唯一のパラメータは、削除する行を表す WHERE 条件の文字列です。 ただし WHERE キーワード自体はのぞきます。
たとえば、昨日以前に入力された行をすべて削除するには次のようにします。
例 39-10行のセットの削除
|
DB_Table は、配列形式を使用して SQL の SELECT 文を構築します。SELECT 文の各句 (たとえば SELECT、 FROM、WHERE 句など) がそれぞれ個別の要素となります。 これにより、クエリの変更が簡単にできるようになります。 たとえば返される結果の行数を制限するために WHERE 句を追加するといったことも簡単です。 クエリの内容を表す配列は、プロパティ配列 $sql に格納されるようになります。
クエリをデータベースに送信する方法は二通りあります。 select() メソッドは結果セットを配列で返し、 selectResult() メソッドは結果セットを DB_Result あるいは MDB2_Result_Common のオブジェクトで返します。 これらのメソッドはすべて DB_Table_Base 基底クラスから継承したものであり、DB_Table_Database オブジェクトのメソッドとしても使用可能です。
SQL の select 文は "クエリ配列" として定義されます。 クエリ配列で使用できる要素のキーのほとんどは、 SELECT 文の句に使用するキーワードを小文字にしたものとなります (たとえば 'select'、'from'、'where' など)。 また、それに対応する値はその句の残りの部分 (キーワード以外の部分) となります。クエリ配列のキーに使用できる SELECT コマンドの句は次のとおりです。
'select' - SELECT 句 (デフォルトは '*')
'from' - 取得するテーブル (デフォルトはこのテーブルの名前、つまり $this->table)
'join' - FROM 句に追加する join 句
'where' - WHERE 句
'group' - GROUP BY 句
'having' - HAVING 句
'order' - ORDER BY 句
'select'、'from'、'where'、'group'、'having' そして 'order' の各要素の値は、SQL 文のそれぞれの句に対応する文字列となります。 ただし、それぞれのキーワード SELECT、FROM、WHERE、GROUP BY、HAVING そして ORDER はのぞきます。もし 'join' 要素が存在した場合、 その値を単純に 'FROM' 要素の後に続けます。つまり、ここでは 'JOIN'、'INNER JOIN' あるいは 'LEFT JOIN' といったキーワードも含める必要があります。
クエリ配列で使用できるその他のキーは、select() メソッドからの返り値をどのような形式にするかを指定するものです。 たとえば以下のようなものがあります。
'get' - select() メソッドが結果を返す方法を指定します。 使用できる値は以下の一覧を参照ください (デフォルトは 'all')。
'fetchmode' - 'get' が 'all'、あるいは未設定の場合に select() が結果セットの行をどのように返すかを設定します。
'fetchmode_object_class' - 行をオブジェクトとして返す場合に、 行をカプセル化する際に使用するオブジェクトのクラス名を指定します。
'all' - 結果セットのすべての行を、行の配列として返します (これはデフォルトの設定です)。個々の行は、 カラム名をキーとする連想配列 (デフォルト) あるいは数値添字配列のいずれかとなります。
'assoc' - 結果を連想配列で返します。結果セットの最初のカラムが連想配列のキー、 2 番目のカラムが連想配列の値となります。
'col' - 最初のカラムのみを数値添字配列で返します。
'row' - 最初の行のみを連想配列で返します。カラム名が連想配列のキー、 そしてカラムの値が連想配列の値となります。
'one' - 最初の行の最初のカラムの値のみを返します。
'get' 要素を 'all' とすると (デフォルトでこのようになります)、 DB_Table::select() メソッドが返す配列の各行は カラム名をキーとする連想配列か数値添字配列、 あるいはカラム名をプロパティに対応させたオブジェクトのいずれかとなります。 返される行のデータ構造を決めるのは、クエリの 'fetchmode' 要素です。もしこれが設定されていない場合は、 DB_Table オブジェクトの $fetchmode プロパティを使用します。同様に、行をオブジェクトとして返す場合に そのオブジェクトのクラス名を決めるのはクエリの 'fetchmode_object_class' 要素です。これが設定されていない場合は DB_Table オブジェクトの $fetchmode_object_class プロパティを使用します。
クエリの 'fetchmode' 要素や 'fetchmode_object_class' 要素、 あるいは DB_Table のプロパティ $fetchmode や $fetchmode_object_class を使用すると、 内部で使用している DB や MDB2 オブジェクトの 'fetchmode' プロパティや 'fetchmode_object_class' プロパティ (DB) あるいは 'fetchmode' オプションや 'fetchmode_object_class' オプション (MDB2) を一時的にリセットすることができます。 指定する値は、それぞれ DB_FETCHMODE_* 定数や MDB2_FETCHMODE_* 定数の値でなければなりません。 もともと DB/MDB2 オブジェクトのプロパティやオプションに設定されていた値は、 select() メソッドが値を返す前に復元されます。
よく使われるクエリや、より複雑なクエリを作成する際の元となる "ベースライン" クエリなどは、パブリックプロパティ配列 $sql に格納しておくとよいでしょう。$sql プロパティは連想配列で、 クエリの名前が連想配列のキー、クエリの配列が連想配列の値となります。 保存されたクエリを実行するには、そのクエリに対応するキーの名前を select*() メソッドの引数として指定します。
$sql プロパティは DB_Table_Base クラスから継承したものです。したがって、クエリを DB_Table の $sql プロパティに保存して特定のテーブルへのインターフェイスとすることもできますし、 DB_Table_Database オブジェクトの $sql プロパティに保存してデータベース全体で使用することもできます。 ひとつのテーブルしか使用しないアプリケーションやクエリでは、 DB_Table オブジェクトの $sql プロパティを上の例のように使うと便利です。そのオブジェクトの select*() メソッドで、名前を指定してクエリを実行することができます。 しかし、より複雑なアプリケーションやクエリなどでは、すべてのクエリを DB_Table_Database オブジェクトの $sql プロパティに格納するほうが便利です。そして、このオブジェクトの select*() メソッドでクエリを発行するようにします。
例 39-11DB_Table サブクラスの定義中でのベースラインクエリの定義 GuestBook テーブルで使用する 3 種類の SELECT 文を定義して保存しましょう。 これらを元にして、より複雑なクエリを作成することにします。
|
select() メソッドは、 クエリを発行してその結果セットを配列で返します。 selectResult() メソッドは、 結果を DB_Result/MDB2_Result_Common オブジェクトで返します。 selectCount() メソッドは、 クエリが返す結果の行数を整数値で返します。 実際の結果セットは返しません。
これらのメソッドのインターフェイスは、どれも同じです。 まず最初のパラメータは必須で、ここにはクエリ配列かあるいは $sql プロパティ配列のキーを指定します。キーを指定した場合は、 それに対応するクエリ配列を使用するようになります。 残りのパラメータはすべてオプションで、 クエリをデータベースに発行する前に手を加えるためのものです。 2 番目のパラメータ $filter は、SQL の論理式を含む文字列で、 SELECT コマンドの WHERE 句に AND で連結されます。 3 番目のパラメータ $order を指定した場合は、 それを用いて 'ORDER BY' 句を作成します。この場合、クエリの 'order' 要素の内容は無視されます。 4 番目と 5 番目のパラメータである $start と $count には整数値を指定し、結果セットから返す最初の行の位置と最大の行数を指定します。
例 39-12保存されているクエリの発行
|
次の例は、保存されているクエリを filter、 order、start および count パラメータで修正するものです。
例 39-13Filter、Order、および Limit パラメータの使用法
|
select() で結果の行を連想配列で返すようにするには、 クエリ配列の 'fetchmode' 要素か DB_Table オブジェクトの $fetchmode プロパティを変更して DB_FETCHMODE_ASSOC か MDB2_FETCHMODE_ASSOC の適切なほうを指定しなければなりません。
例 39-14Fetchmode を指定し、結果を連想配列で返すようにする
|
select() で、 カラム名に対応するプロパティを持つオブジェクトで結果の行を返すようにするには、 クエリ配列の 'fetchmode' 要素か DB_Table オブジェクトの $fetchmode プロパティを変更して DB_FETCHMODE_OBJECT か MDB2_FETCHMODE_OBJECT の適切なほうを指定しなければなりません。 ユーザ定義のクラスが指定されなかった場合は、 次の例のようにすべての行が stdClass のインスタンスとして返されます。
例 39-15行を stdClass のオブジェクトで返す
|
結果セットの行をカプセル化するクラスを指定するには、クエリ配列の 'fetchmode_object_class' 要素あるいは $fetchmode_object_class プロパティでクラス名を指定します。
例 39-16結果の行をユーザ定義クラスのオブジェクトで返す
|
DB_Table は、自動的にデータの検証を行うことができ、 追加したり更新したりするデータが対応するカラムの型と整合性があるかどうかを調べることができます。 データ型の検証は、追加や更新の際にデフォルトで行われます。 追加や更新の際の検証を有効にしたり無効にしたりするには、それぞれ autoValidInsert() メソッドおよび autoValidUpdate() メソッドを使用します。 これらのメソッドには boolean 型のパラメータを指定し、 true の場合は検証機能が有効に、false の場合は無効にします。
追加したり更新したりするデータの型の検証を実施亜に行うのは、それぞれ validInsert() メソッドあるいは validUpdate() メソッドとなります。 これらのメソッドにはひとつのパラメータを指定します。 このパラメータに渡すのは、カラム名がキーとなる連想配列です。 検証に成功した場合は true、失敗した場合は PEAR_Error オブジェクトを返します。 これらのメソッドは、自動検証を有効にしている場合に insert() メソッドや update() メソッドの内部から自動的にコールされます。 自動検証機能をカスタマイズするには、これらのメソッドをオーバーライドして実装します。
単一のカラムの型を検証するのが isValid() メソッドです。 このメソッドの最初のパラメータには、検証したい値を指定します。 そして 2 番目のパラメータには、検証したい DB_Table データ型の名前を指定します。 このメソッドは、行の検証用の 2 つのメソッドの内部からコールされます。
表 39-1さまざまなメソッド