MENU
LOGIN
W3C validiation
xhtml11
html-lint
PEAR,XP,PHPなど覚書 ::: DB_DataObjectの使い方
arrow_right tips:PHP PEARその他 arrow_right PHP: :PEAR arrow_right DB_DataObjectの使い方

Alan Knowles氏作のDB_DataObjectは使いやすいSQLビルダ。自習メモ書。 マニュアルは arrow_right pearサイト OR php-library.com OR 本サイト (マニュアルと実際のコードの間には齟齬があるようなので注意)。

demo:本クラスを使った国会議員Webサイト簡易検索: (議員の苗字を、漢字で入れてください(例:小沢):フルネームは対応してません)

違っているとか、不正確だとかの突っ込みは aki@townmedia.org まで、どんどんご指摘ください。

1 ともかく実行してみる  arrow_up 目次

1-1 設定オプションについて  arrow_up 目次

マニュアルでは、 $options = &PEAR::getStaticProperty('DB_DataObject','options'); [1] と参照を使い $options = array(...); とするように推奨 [2]

1-2 簡易例  arrow_up 目次

とりあえず動かすには、オプションのうち、 DSN を記述するdatabase変数を指定すればいい。

// SQL schema;
// CREATE TABLE shohin(
// i integer,
// shohin_name text
// );
require_once('DB/DataObject.php');
$options = & PEAR::getStaticProperty('DB_DataObject','options');
$options = array(
            'database' => 'pgsql://hoge:ratta@hoge.host.com/doraemondb',
        'debug' => 1
);

$instance = new DB_DataObject;
$instance -> tableName('shohin');
$instance->get("i",1);
echo $instance->shohin_name;

2 拡張クラスを使うために:事前知識  arrow_up 目次

上だと、実用に、ほど遠い。 実際は、データベースのスキーマ定義ファイルと、テーブルごとの DB_DataObjectの拡張クラスを作成しておき、それを組み合わせて使う。

2-1 インスタンス時の必須オプション  arrow_up 目次

そのためには、以下のオプション設定が必要となる。

なお 現在のバージョン現在のPEARマニュアル の間には齟齬があるので注意が必要。

2-1-1 database  arrow_up 目次

利用するデータベースの dsn を指定する。

2-1-2 schema_location  arrow_up 目次

スキーマ定義ファイル用ディレクトリ:フルパスを指定

なお、ファイル名は、 データベース名.ini と同じである必要がある。

データベース名.ini は、[テーブル名]で区切られた,PHPのparse_ini_file形式の カラム名=数値型(1) or それ以外(2) の行を、並べる。

次述のcreateTable.phpで、自動生成可能

2-1-3 require_prefix  arrow_up 目次

マニュアルでは必須オプションだが、 廃止されているようだ。 マニュアルによれば (extends)クラスを入れるディレクトリ名: フルパスあるいは、(phpの)include(require)パスからの相対パスとなる

2-1-4 class_location  arrow_up 目次

マニュアルでは必須オプションではないが、 拡張クラスの場所を指定するためには、必須。 require_prefixの代わりの必須オプションであるといえる。

次述のcreateTable.phpで、 各クラス用*phpファイルが自動生成される

2-1-5 class_prefix  arrow_up 目次

クラス名のプレフィクス。 後述のcreateTable.phpなどのデフォルト値でもある DataObjects_ としておくのが安全。 なお、プレフィクスとテーブル名をあわせたものが、 DB_Dataobjectの拡張クラス名となる

次述のcreateTable.phpで、自動生成した各*php ファイル内のクラス名につく。

2-2 createTable.phpで、定義ファイルとクラスファイルを生成!  arrow_up 目次

2-2-1 コマンドラインで起動  arrow_up 目次

既存のデータベースのテーブルスキーマ定義ファイルおよび、テーブルごとのクラスファイルを、自動生成してくれる,すぐれもの。

php /usr/local/lib/php/DB/DataObject/createTables.php example.ini

example.iniは /usr/local/lib/php/docs/以下のDataObject用文書ディレクトリに収められているので、 それを参考にすればいい。

ためしに上のexample.iniの冒頭3行のみを次のように変更して動かしてみる。


database        = pgsql://hogeratta@127.0.0.1/mydb
schema_location = /tmp/DataObjects
class_location  = /tmp/DataObjects

この結果、/tmp/DataObjectsディレクトリには以下のファイルが生成された。

2-2-2 生成された定義ファイルとクラスファイル  arrow_up 目次

Attached.php
Category_list.php
Cp.php
Cp_type.php
Dayrange.php
Event.php
Event_type.php
Kjrank.php
Postcode.php
Resource.php
Skrank.php
Ymd.php
mydb.ini

ちなみに、もともとのデータベース(mydb)のテーブルは次のようである。 テーブル名.php および、 データベース名.ini のファイルが一括出力されているのがわかるだろう。 (postgresqlのpsqlでリスト)

 Schema |     Name      | Type  |  Owner   
--------+---------------+-------+----------
 public | attached      | table |  hogeratta
 public | category_list | table |  hogeratta
 public | cp            | table |  hogeratta
 public | cp_type       | table |  hogeratta
 public | dayrange      | table |  hogeratta
 public | event         | table |  hogeratta
 public | event_type    | table |  hogeratta
 public | kjrank        | table |  hogeratta
 public | postcode      | table |  hogeratta
 public | resource      | table |  hogeratta
 public | skrank        | table |  hogeratta
 public | ymd           | table |  hogeratta
(12 rows)

3 ファイルの中身例  arrow_up 目次

3-1 郵便番号データテーブルを例に  arrow_up 目次

前述のうち、 郵便局のWebサイト などで配布されている全国郵便番号データを入れた postcodeテーブル のクラスであるPostcode.phpの中身を例示してみる

/**
* Table Definition for postcode
*/
require_once 'DB/DataObject.php';
class DataObjects_Postcode extends DB_DataObject
{
###START_AUTOCODE
/* the code below is auto generated do not remove the above tag */
var $__table = 'postcode';                        // table name
var $pub_auth_code;                   // varchar(-1)
var $old_post_code;                   // text(-1)
var $new_post_code;                   // varchar(-1)
var $ken_kana;                        // text(-1)
var $town_kana;                       // text(-1)
var $zone_kana;                       // text(-1)
var $ken_kanji;                       // text(-1)
var $town_kanji;                      // text(-1)
var $zone_kanji;                      // text(-1)
var $zone_two_flag;                   // bool(1)
var $zone_aza_flag;                   // bool(1)
var $zone_has_chome_flag;             // bool(1)
var $zone_overlap_flag;               // bool(1)
var $data_change_flag;                // varchar(-1)
var $data_change_reason_flag;         // varchar(-1)
/* ZE2 compatibility trick*/
function __clone() { return $this;}
/* Static get */
function staticGet($k,$v=NULL) {
return DB_DataObject::staticGet('DataObjects_Postcode',$k,$v);
}
/* the code above is auto generated do not remove the tag below */
###END_AUTOCODE
}

一方、テーブルのスキーマ定義ファイルであるmydb.iniファイルのpostcodeテーブル部分は、 次のように出力されている。 右辺の数値の意味は次述する。また、postcode__keysは、テーブル定義でprimary keyが指定されていると、この項目にそのキーが記述される(このテーブルでは、primary keyが指定されていないので、なにも記されていない)。

[postcode]
pub_auth_code = 2
old_post_code = 2
new_post_code = 2
ken_kana = 2
town_kana = 2
zone_kana = 2
ken_kanji = 2
town_kanji = 2
zone_kanji = 2
zone_two_flag = 18
zone_aza_flag = 18
zone_has_chome_flag = 18
zone_overlap_flag = 18
data_change_flag = 2
data_change_reason_flag = 2

[postcode__keys]

3-2 スキーマ定義ファイルの中身  arrow_up 目次

[テーブル名]
タプル名  = データタイプ値 (+データタイプ値)
[テーブル名__keys]
同上

データタイプの数値は、以下のようになっている(DetaObject.phpの定数部分参照) TODO は、まだ実装されていないようだ。

スキーマ定義ファイル右辺の数値の意味
数値 実装or未実装
数値型 1 実装
文字型 2 実装
日付型 4 TODO
時刻型 8 TODO
ブール 16 TODO
テクスト 32 TODO
Blob 64 実装
非ヌル 128 実装
MYSQLの日付 256 実装

いずれにせよ、createTable.phpで生成されるiniファイルについては 「手動でいぢる必要わ、ない」 とマニュアルに宣言されているので、中身は気にしないことにしたい(藁

4 拡張クラスを使う  arrow_up 目次

4-1 factoryメソッド  arrow_up 目次

createTable.phpで作ったファイル・クラスを用いてみる。 拡張クラスを呼び出すには、 factory メソッドを使う。

require_once('DB/DataObject.php');
$options = &PEAR::getStaticProperty('DB_DataObject','options');
$options = array(
          'database'=>'pgsql://hogeratta@127.0.0.1/mydb',
          'schema_location'  => '/tmp/DataObjects',
          'class_location'   => '/tmp/DataObjects',
          'class_prefix'     => 'DataObjects_',
          'debug'=>1
             );

$p = DB_DataObject::factory('postcode');
$p -> whereAdd("town_kanji  LIKE '石垣市'");
$p -> whereAdd("zone_kanji  LIKE '新川'");
$p -> find();
$p -> fetch();
echo $p -> new_post_code.':'.$p -> ken_kanji.':'
      .$p -> town_kanji.':'.$p -> zone_kanji;

上のコードを実行すると, /tmp/DataObjects/Postcode.phpの DataObjects_Postcode クラスが呼び出され、 SELECT * FROM postcode WHERE town_kanji LIKE '石垣市' AND zone_kanji LIKE '新川' クエリが発行されて、実行結果は下記のようになる。

9070024:沖縄県:石垣市:新川

4-2 各種method覚え  arrow_up 目次

以下$p = DB_DataObject::factory('postcode');を前提として、いくつかのメソッドについてのメモ。

4-2-1 countを使う  arrow_up 目次

$p -> keys('*');
     //mydb.iniでpostcode__keys(primary key)が
     //指定されていないので、明示的にkeyが必要
echo $p -> count().'件';

結果は、

121208件

なお上記のように、primary keyが指定されていれば、 $p->keys('something'); は必要ない。

4-2-2 limit  arrow_up 目次

$object->limit(開始値,取得レコード件数); で取得範囲を指定する。DBMSによってSQL文実装が違うため [3] その相違を吸収してくれそうな予感。

$p -> whereAdd("town_kanji  LIKE '石垣市'");
$p -> limit(3,6);
$p -> find();
while($p->fetch())
{
     echo $p->zone_kanji."<br />";
}

結果は次のようになる [4]

伊原間
大川
大浜
川平
崎枝
白保

4-2-3 selectAddでカラム指定  arrow_up 目次

select文デフォルトは、* 。 項目を選択したい場合は、selectAddで明示的に指定する必要がある。 なお、その場合、一旦、 $object->selectAdd(); と初期化が必要。

$p->selectAdd();
$p->selectAdd('town_kanji');

発行されるSQL文は

SELECT town_kanji FROM postcode

5 テーブルの関連付け覚え  arrow_up 目次

複数テーブルの関連付けに関する覚え。 join とは限らない

5-1 例示テーブルの作成  arrow_up 目次

例示のために、入江輝之氏作成の 国会議員名簿 を利用して、下記の二つのテーブルを作る。

5-1-1 国会議員名簿テーブル:representative  arrow_up 目次

representative.sql (衆参両院なのにrepresentativeというのは変だけど、とりあえず許してね^^;)

5-1-2 政党テーブル:party  arrow_up 目次

party.sql

5-1-3 2テーブルを関連づけるカラム  arrow_up 目次

representativeテーブルの政党名略称カラム(たとえば自民党): party と partyテーブルの name_abbr

5-2 getLinkメソッドによる検索結果取得  arrow_up 目次

getLinkメソッドを使えば2つのSQL文が発行されて、目標の検索結果を得ることが出来る。

$newobj = $object->getLink(
          'オブジェクトのテーブルのうち関係付けたいカラム',
          '関係付け対象のテーブル名',
          '同テーブルのキーになるカラム名'
        );

これで$newobjが得られる

$Rep = DB_DataObject::factory('representative');
$Rep -> whereAdd("name  LIKE '%石原%'");  
$Rep -> find();
  while($Rep->fetch()){
        $party =  $Rep->getLink('party','party','name_abbr');
        echo $party->url;
}

上記で、「石原」という名前の議員の政党のWebページのURLが得られる。 実際は、下記の2つのSQL文が発行されている

SELECT * FROM representative WHERE name LIKE '%石原%'
SELECT * FROM party WHERE party.name_abbr = '自民党'

5-3 Automatic Table LinkingとgetLinksメソッド  arrow_up 目次

databasename.links.ini を作ることによって、上の過程を自動化できる。

giinという名称のデータベースならば、 giin.links.ini ファイルを schema_location のディレクトリに格納しておく。 あとは、getLink s メソッドを発行すると、前述のgetLinkメソッドと同等の結果が得られる。 ただし、getLinkと違い、オブジェクトを直接返すわけではなく、 $object->_対象テーブル名 にオブジェクトが格納される(この場合なら_party)。

[representative]
party = party:name_abbr    
$Rep = DB_DataObject::factory('representative');
$Rep -> whereAdd("name  LIKE '%石原%'");  
$Rep -> find();
  while($Rep->fetch()){
        $Rep->getLinks();
        echo $Rep->_party->url;
  }

5-4 joinAddとselectAs  arrow_up 目次

上で見たように、getLink(s)は、複数テーブルのキーを複数のSQL文を発行するにとどまる。 一方、selectAsとjoinAddを使うと、join文を作成できるようだ・・・・。ここんとこ、むづかしくて動作が、まだ、理解できていない [5] 。 が、とりあえず giin.links.ini を作っておき、下記のように書くと

$rep = DB_DataObject::factory('representative');
$party = DB_DataObject::factory('party');
$rep -> whereAdd("representative.name  LIKE '%石原%'");  
$rep -> joinAdd($party);
$rep -> find(); 
while($rep->fetch())
{
        echo $rep->url;
} 

次のようなSQLが発行され、じょいん、される。

SELECT * FROM representative 
INNER JOIN party ON party.name_abbr=representative.party 
WHERE representative.name LIKE '%石原%' 

ただし、このままだと、同じカラム名は上書きされてしまうので(たとえばrepresentative.nameは、party.nameに上書きされる)、 selectAsメソッドを用いて、別名をつけることが出来る。

$rep = DB_DataObject::factory('representative');
$party = DB_DataObject::factory('party');
$rep -> whereAdd("representative.name  LIKE '%石原%'");  
$rep->selectAs();
                        //これで、representativeのカラム名を
                        //そのまま確保
$rep->joinAdd($party);
$rep->selectAs($party,'party_%s');
                       //partyテーブルのカラム名を
                       //party_をプレフィクスとした別名で確保
$rep -> find(); 
while($rep->fetch())
{
        echo $rep-> party_url;//party_url別名として表示
} 

発行されるSQLは

SELECT representative.house as house,
       representative.name as name , 
       ....中略.....
       party.name as party_name , 
       party.name_abbr as party_name_abbr,
       ....以下略
脚注

[1 ]DataObject.phpの例ではsetStaticPropertyと誤記されている

[2 ]でも、中では、$GLOBALS['_DB_DATAOBJECT']['CONFIG']の値を使っているから、いまのところ(今の版では)StaticPropertyの意味がどこにあるかわからず、 $GLOBALS['_DB_DATAOBJECT']['CONFIG']=array(....);としても同じだと思われる 。

[3 ]PostgreSQLならSQL文で直接limit,offsetキーワードを書ける

[4 ]PostgresSQLの場合、SELECT * FROM postcode WHERE town_kanji LIKE '石垣市' LIMIT 6 OFFSET 3、というSQLが発行される

[5 ]なお、マニュアル的には、 Builds a Join Query, by adding another dataobject to this one. Be careful when using this, raw queries may be clearer than using joinAdd. なメソッド。