2009年10月31日土曜日

Zend_Db_Adapter_Abstractを継承した拡張自作Adapter

どうも、俺@遊び帰宅です。
眠いっす。

Zend Frameworkを使ってWebアプリケーションを作ってて
「あー、DBへのクエリのログ取りたいなー」ってよくあると思います。
特にトランザクションの発生するクエリに関しては、Webプログラマとしては必需品だと思います。

方法はすべてのXXController内でクエリを発行する度に
<?php
// Zend_Db_Adapter_Abstractでクエリ発行
$adapter->query("INSERT INTO foo_table (column) VALUES ('value')");

// Zend_Db_Profiler
$profiler = $adapter->getProfiler();
$queries = $profiler->getQueryProfiles(Zend_Db_Profiler::INSERT);
if (is_array($queries)) {
foreach ($queries as $query) {
file_put_contents($filename, $query->getQuery());
}
}
と、簡単なサンプルを書くとこんな感じでしょうか。

ただ、これだとクエリを発行する度にZend_Db_Profilerを生成し、ログを取得しなければなりません。
面倒くさいです。

そんな面倒くさがりな貴方にはZend_Db_Adapter_Abstractを継承した自作クラスを作成することをオススメします。
例えばPostgreSQLを使っている場合は
<?php
/**
* Zend_Db_Adapter_Pdo_Pgsqlを継承した自作アダプター
*/
class MyPdoPgsql extends Zend_Db_Adapter_Pdo_Pgsql {
/**
* @Override
*/
public function insert($table, array $bind) {
// 略 Zend_Db_Adapter_Pdo_Pgsql::insert()と同じ処理

// Zend_Db_Profilerでログる
$profiler = $adapter->getProfiler();
$queries = $profiler->getQueryProfiles(Zend_Db_Profiler::INSERT);
if (is_array($queries)) {
foreach ($queries as $query) {
file_put_contents($filename, $query->getQuery());
}
}
}


/**
* @Override
*/
public function update($table, array $bind, $where) {
// 略 Zend_Db_Adapter_Pdo_Pgsql::update()と同じ処理

// Zend_Db_Profilerでログる
$profiler = $adapter->getProfiler();
$queries = $profiler->getQueryProfiles(Zend_Db_Profiler::UPDATE);
if (is_array($queries)) {
foreach ($queries as $query) {
file_put_contents($filename, $query->getQuery());
}
}
}

public function delete($table, $where = '') {
// 以下同じ
}
}
このようにinsert/update/deleteメソッドにログ処理を書いてZend_Db_Adapterの子クラスを作成します。

あとはindex.php内の処理でZend_Db_Adapter_Abstractを生成するときに
<?php
$db = new MyPdoPgsql($options);
Zend_Db_Table_Abstract::setDefaultAdapter($db);
のようにデフォルトアダプターをセットしておけば、全てOK!!

基本的にZend FrameworkのクエリはZend_Db_Adapter_Abstractを経由して発行されるので、あとは自動でログを取ってくれます。
他にもトランザクションや例外処理も全てこの中に書けば、面倒なことを書かずに済みますね。


以上、面倒くさがり屋さんへ。

1 件のコメント:

まる さんのコメント...

ありがとうございます。勉強になりました!
Zend_Db::factoryを使っている人に追記しときます。

■ブートファイル
$db = Zend_Db::factory($config->Database);
Zend_Db_Table::setDefaultAdapter('db');

■Configファイル
[Database]
adapter = "PDO_PGSQL"
params.adapterNamespace = "My_Db_Adapter"
params.host = "localhost"
params.username = "XXX"
params.password = "XXX"
params.dbname = "XXX"

■Adapterファイル
class My_Db_Adapter_Pdo_Pgsql extends Zend_Db_Adapter_Pdo_Pgsql
{
public function query($sql, $bind = array())
{
//if(preg_match('/^(insert|update|delete)/i',$sql)) ログ出力...
return parent::query($sql, $bind);
}
}