2010年2月3日水曜日

Zend_Db_Table(その5) 検索その2

find()メソッドでは、主キーのみにしか条件に設定できないため、他の条件を指定する場合は、fetchAll()メソッドやfetchRow()メソッドで、Zend_Db_Table_Selectクラスを指定する。

Zend_Db_Table_Selectクラスは、テーブルクラスのselect()メソッドを使うと取得できる。

(コード例)
$table=new Hoge();

$select=$table->select();

Zend_Db_Table_Selectクラスに対して、条件を設定する。
SQLで記述するところを
 from() : テーブル名や取得する項目を指定する。
 where():検索条件をANDで指定する。
 orwhere() :検索条件をORで指定する。
 order() :ソート順を指定する
 limit():取得件数を制限する


(コード例)
$table=new Hoge();
$select=$table->select();
//テーブルからidとnameを取得対象とする
%select->from($table->name(),array("id","name");
//id項目に制限を追加
$select->where("id>?", 100);
//name項目に制限を追加(OR)
$select->orwhere("name like ?","%hoge%");
//sort順をidの降順に設定
$select->order("id DESC");
//取得するレコードを11番目から100行取得
$select->limit(100,10);
//検索実行
$rows=$table->fetchAll($select);

Zend_Db_Table_Selectへの条件を指定する順番は意識しなくてもいい。
where()などの戻り値はZend_Db_Table_Selectオブジェクトになるので、以下のような記述もできる。

(コード例)
$table=new Hoge();
$table->fetchAll($select=$table->select()->where("id>?",100)->orwhere("name like"."%hoge%")->limit(100,10)->order("id DESC"));

※2行目は区切りなしで記述している。


他のテーブルとの結合(join)もできる。

(コード例)
$table=new Hoge();
$select=$table->select()->from()->setIntegrityCheck(false)->join("テーブル名","テーブル名.id=hoge.id",array())->where("id>?",100);

leftjoin()メソッドやrightjoin()メソッドを使うと、外部結合の指定も可能。
他のテーブルを結合する場合、取得する項目に他のテーブルの項目を混ぜることができ、joinメソッドの3つ目の引数で指定する。
その場合、setIntegrityCheck(false)としておかないと、例外がスローされる。

他のテーブルの項目を混在して取得したZend_Db_Table_Rowに対してはupdateメソッドを使った更新を行うことができずに例外がスローされる。

2010年2月1日月曜日

Zend_Db_Table利用時のメタデータのキャッシュ設定

Zend_Db_Tableでは、実行するたびにテーブルのメタ情報を作成している。
テーブルメタデータをキャッシュすることで、パフォーマンスをあげることができる。
やり方はマニュアルに書いてあるけど、なんとなくメモ。
 
キャッシュはZend_Cacheを利用。

ファイルへメタデータをキャッシュする場合は、以下のように設定する。

// (1)キャッシュを作成
$cache = Zend_Cache::factory('Core', 'File',
    array('automatic_serialization' => true),
    array('cache_dir' => APPLICATION_PATH . '/data/cache')
);
//(2) すべてのテーブルオブジェクトで上記のキャッシュ設定Zend_Db_Table_Abstract::setDefaultMetadataCache($cache);


メタデータをテーブルクラスに直接記述してさらにパフォーマンスをあげることができるそうです。
テストまでは、キャッシュを使って、運用時は直接メタデータを書いたほうがいいかのな。

2010年1月31日日曜日

Zend Framework1.10.0のZend_Toolを試してみた

Zend Framework 1.10.0でZend_Toolを利用してみたので、とりあえずメモ。

事前にzf.shコマンドをパスに通しておく。

Ubuntu9.10の環境で試しているので、とりあえず以下でパスを通して実行
$export $PATH=$PATH:zf.shが存在するパス
$zf.sh

エラーが出ずに動けばOK.

(1)プロジェクトを作成する。

sampleという名のプロジェクトを作成するには、

$zf.sh create project sample

と指定する。
実行が完了すると以下のディレクトリやファイルが生成される。
[生成されるディレクトリやファイル]
sample/
    application/
        Bootstrap.php    <=メソッドなしのクラス
        configs/
            application.ini
        controllers/
            IndexController.php
            ErrorController.php
        layouts/    <=空
        models/    <=空
        views/
            helpers/
            scripts/
                index/
                    index.phtml
                error/
                    error.phtml  
    public/
        index.php
        .htaccess
  
    tests/    <=PhpUnitの関連ファイル
    library/    <=空


Index、Errorの2つのコントローラが実行できるようになっている。
VIEWは以前のバージョンで試していたときは、ショートタグ形式だったけどがPHPの指定に変更になっていた。
普段ショートタグは使用してなくて、書き換えていたので、この変更はうれしい。


とりえず生成したものをブラウザからアクセスできるように設定する。
自動生成したものには、ZendFrameworkのライブラリ一式は、library配下におくことが前提になっている。
このため、Zend Frameworkのファイルをコピーするか、他にすでに配置されているようならば、シンボリックリンクを張っておく。

次に公開領域にプロジェクトのpublicディレクトリのシンボリックリンクを作成する。
#apacheの設定で、公開領域でシンボリックリンクを利用できるように設定しておく
#個人的にはあまり好きじゃないけど、とりあえず、動かすだけなので。

$cd /var/www
$ln -s ~/sample/public sample

ブラウザからアクセスするとzfで自動生成したファイルが表示される。
http://xxxxxx/sample/


Controllerの追加などは、プロジェクトディレクトリ直下でコマンド操作する。
$cd sample


(2)レイアウトを追加
1.10.0からZend_ToolでLayoutの有効・無効が設定できるようになった。

$zf.sh enable layout

コマンドを実行すると

a)layouts/script/layout.phtmlが作成される
b)application.iniに
 resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts/"
 と追加される。

(3)アクションを追加

$zf.sh create action アクション名 コントローラ名

コマンドを実行すると
a)IndexControllerにsampleAction()が追加される
b)views/scripts/index/sample.phtmlが作成される
viewには、コントローラ名と、アクション名が表示されるようになっている。

※コマンドの説明では、
Action
zf create action name controller-name[=index] view-included[=1] module

とあって、 indexがデフォルトだと思って実行してみたけど、追加するコントローラがないと怒られる。
実はコントローラの指定では、Indexと最 初は大文字で指定しないとNGなようで、ハマッた。


(4)モデルを作成
これも1.10.0から追加されたもの

$zf.sh create model modelsample

コマンド実行すると
a)applications/models/Modelsample.php が作成される

単に空のクラスが作成されるだけ。
ディレクトリによる階層分けを試してみたけど、うまく指定できなかった。



(5)コントローラーの追加
$zf.sh create controller sample

コマンドを実行すると、
a)applications/controllers/SampleController.phpが作成される
メソッドはinit()とindexAction()が空の状態で生成される。
b)views/scripts/db/index.phtmlが作成される

(6)DBアダプターの設定をapplication.iniに追加
これも1.10.0から追加された。

$zf.sh configure dbadapter "host=ホスト名&adapter=Pdo_Pgsql&username=ユーザ名&password=パスワード&dbname=データベース名"

コマンドを実行すると
a)application.iniに指定内容がZend_Application_Resource_Dbが利用できる形で反映される。

DBパラメータ指定箇所は単に展開されるだけなので、正しいパラメータ名を記述する必要がある。

[パラメータ名]
host
adapter
dbname
username
password


※section-nameを指定して、application.ini内の任意のセクションに設定を追加できると思うのだけど、うまくいかなかった。

(7)テーブルクラスを追加
これも1.10.0で追加された。

zf.sh create db-table account account_tb -f

コマンドを実行すると

a)models/DbTable/Acctount.phpが作成される

$_nameにテーブル名が指定される状態でコードが生成される。
テーブル名を指定しないとエラーになる。
テーブル名とクラス名の規約に一致していればいいはずなので、指定なしでもいいような・・・。


マニュアルを見ると、データベースを指定して、データベースの自動生成できるようなことが書いてある。
コマンド例をいろいろ試してみたけど、できなかった。まだ、実装されていないのだろうか?

ついでに、コマンドのヘルプでは、db-tableと指定することになっているけど、リファレンスでは、dbtableになっており、どちらの指定でも生成はされていた。


DbTalbeが自動的にDB内のテーブルをスキャンして生成してくれるようになるとずいぶん楽になるんだけど、もうすこしといったところか。

2010年1月29日金曜日

Zend Framework 1.10.0リリース

Zend Framework 1.10.0リリースがリリースされてました。

気になるのは、
Zend_Application resourcesで、Log, Mailが追加されている
Zend_ToolでModel generation, DbAdapter setup, Layouts and Form Generationが追加されている(っぽい)
ところか。

Zend_Db_Table(その4) 検索その1

テーブルからデータ取得をするために3つのメソッドが用意されている

find() :主キーを利用して検索
fetchRow() :条件を指定して一行だけ検索
fetchAll() :条件を指定して複数行検索

fetchRow()以外はZend_Db_Table_Rowsetで取得できる。
fetchRow()は条件にマッチしたら、Zend_Db_Table_Row、マッチなかったらnullが取得できる。

--------コード例--------
$table=new Hoge();
//主キーを利用した検索
$rows=$table->find($key);
//条件を指定して検索(一行だけ)
$row=$table->fetchRow($table->select()->where("col=?",$value);
//条件を指定して検索(複数行)
$rows=$table->fetchAll($table->select()->where("col=?",$value);
-------ここまで-------


foreach文で、Zend_Db_Table_Rowを取得できる。
--------コード例--------
$table=new Hoge();
$rows=$table->fetchAll($table->select()->where("col=?",$value);
foreach($rows as $row){
 $row->name;
$row->id;
}
-------ここまで-------
Zend_Db_Table_Rowsetでは、count()メソッドで件数を取得できる。



配列で取得したいなら、toArray()メソッドを使えば、列を連想配列に変換したものの配列を取得できる

--------コード例--------
$table=new Hoge();
$rows=$table->fetchAll($table->select()->where("col=?",$value);

$data_array=$rows->toArray();
foreach($data_array as $key=>$value){
echo "キー=".$key."\n";
echo "値=".$value."\n";
}
-------ここまで-------

current()メソッドを使うと最初の行だけ取得できる。
find()を利用する場合はRowsetが必ずで返るので、以下のようにして、Rowを取得する。
Rowsetが0件の場合、current()の戻り値はnullになる。
--------コード例--------
$table=new Hoge();
$rows=$table->find($key);
$data=$rows->current();
-------ここまで-------

2010年1月27日水曜日

Zend_Db_Table(その3) テーブルクラスの定義

Zend_Db_Tableを継承したクラスを定義する。
対象となるテーブルが規約にクラス名と同じであり、主キーがシーケンスのように自動インクリメントすキーを持つテーブルであれば、クラス定義や具象クラスを利用するだけでで使用できる。

--------テーブル例--------
CREATE TABLE HOGE
(
ID SERIAL NOT NULL UNIQUE,
NAME TEXT,
PRIMARY KEY (ID)
) ;
CREATE TABLE HOGECHILD
(

CID SERIAL NOT NULL UNIQUE,
PARENT_ID INTEGER NOT NULL REFERENCES HOGE,
NAME VARCHAR(10) NOT NULL,
PRIMARY KEY (CID)
)
--------ここまで--------

--------コード例--------
class Hoge extends Zend_Db_Table_abstract{
}
$table=new Hoge();
$result=$table->find(1);//主キーによる検索
-------ここまで---------

(クラスを定義しない方法 1.9以上)
--------コード例--------
$table = new Zend_Db_Table('hoge');
-------ここまで---------

(テーブル名をクラス名と分ける場合)
--------コード例--------
class Hoge extends Zend_Db_Table_Abstract{
protected $_name="hoge";
}
-------ここまで---------

(主キーが自動インクリメントするキーの場合)
--------コード例--------
class Hoge extends Zend_Db_Table_Abstract{
protected $_sequence=true;
}
-------ここまで---------

(主キーが自然キーの場合)
--------コード例--------
class Hoge extends Zend_Db_Table_Abstract{
protected $_sequence=false;
}
-------ここまで---------

(プラリマリーキーを指定する場合)
--------コード例--------
class Hoge extends Zend_Db_Table_Abstract{
protected $_primary="id";
protected $_sequence=true;
}
-------ここまで---------


テーブル間の関係(リレーション)をクラスに定義しておくと、Zend_Db_Rowクラスから、親テーブルや子テーブルへのアクセスが簡単に利用できる。
テーブルに親、子供テーブルが存在する場合は、親、子に対する関係を記述する。

(従属するテーブルが存在する場合)
--------コード例--------
class Hoge extends Zend_Db_Table_Abstract{
protected $_sequence=true;
//テーブル名ではなく、Zend_Db_Tableを継承したクラス名を記述する
protected $_dependentTables=array(
'HogeChild'
);
}
-------ここまで---------

(親テーブルが存在する場合)
--------コード例--------
class HogeChild extends Zend_Db_Table_Abstract{
protected $_sequence=true;
//refTableClassの要素はテーブル名ではなく、Zend_Db_Tableを継承したクラス名を記述する
protected $_referenceMap=array(
'Rule1'=>array(
'columns'=>'parent_id',
'refTableClass'=>'Hoge',
'refColumns'=>'id'
)
);}
-------ここまで---------

2010年1月24日日曜日

Zend_Db_Table(その2) 接続準備編

Zend_Db_Tableに接続先となるDBの情報を指定する必要がある。
※指定するのはZend_Db_Adapterクラス、でZend_Db::Factory()で生成すればいい。


Zend_Db_Tableの継承クラスに指定する方法はいくつかあるので、必要に応じて使い分ける。

a)Zend_Db_Tableのコンストラクタで接続先情報を指定する
b)Zend_Db_Table::_setupDatabaseAdapter()をオーバーライドして、接続先情報を設定する。
c)Zend_Db_Table_Abstract::setDefaultAdapter($db)ですべてZend_Db_Table継承クラスに対して、接続先を指定する。
※a),b)の指定が優先される。
b)は接続先が他のテーブルと異なる、かつ、接続先の設定変更しないような場合に使う。

通常のアプリケーションでは、テーブルがひとつということはほとんどないので、c)の方法でBootstrapで記述しておけばいい。
------コード例-------
$db=Zend_Db::factory('Pdo_Pgsql', array(
 host=>'localhost',//接続先ホスト
 username=>'dbuser',//DBユーザ名
 password=>'dbpass',//DBパスワード
 dbname=>'DB NAME'//DB名
));
Zend_Db_Table_Abstract::setDefaultAdapter($db)
------ここまで-------

Zend_Db::factory()メソッドで指定する場合、配列で直接指定するほかにZend_Configを利用して外部iniファイルに設定を記述することもできる。

Zend_Applicationを利用する場合は、リソースプラグイン(Zend_Application_Resource_Db)を利用できるので、以下のように記述しておけば、勝手にデフォルトアダプターとして設定してくれるので便利

-------application.iniでの記述例---------
resources.db.adapter = pdo_pgsql
resources.db.params.host = localhost
resources.db.params.username = dbuser
resources.db.params.password = dbpassword
resources.db.params.dbname = dbname
resources.db.isDefaultTableAdapter = true
-------ここまで----------