正しくはDQLがログに出るのだけど、あった方が調査とかし易いのでログに書き出してみた。
FuelPHP+Doctrine2の構成は
http://qiita.com/gyhino@github/items/188d207d26f608269b3a
を引き続き使う。
要件
- ログにSQL(DQL)が出力される
- ログにクエリの実行時間が出力される
Doctrine2でSQLをログに出すためにはどうしたらいい?
Doctrine2にはSQLLogger
を設定することができ、それを使うことで簡単にSQLを出力する事ができる。
SQLLogger
はInterfaceとして提供されているだけなので、自分で好きに実装する。
https://github.com/doctrine/dbal/blob/master/lib/Doctrine/DBAL/Logging/SQLLogger.php
FuelPHPのログにSQLを出すために改修をする
今回Doctrine2を扱うのに利用しているライブラリにもSQLLogger
が用意されている。
https://github.com/aspendigital/fuel-doctrine2/blob/master/classes/Fuel/Doctrine/Logger.php
ライブラリ内でprofiling
が有効になっている場合これを使う様に実装されている。
しかし、このSQLLogger
の実装はプロファイラにSQLと実行時間が表示されるようになるだけで、ログには書き出されない。
なので、これを拡張する形で進める。
Fuel\Doctrine\Loggerの拡張
SQLと処理時間をログに出すにはこんな感じで拡張をする。
<?php
namespace Sample\Doctrine;
class SQLLogger extends \Fuel\Doctrine\Logger
{
protected $startTime;
protected $lastSql;
public function startQuery($sql, array $params = null, array $types = null)
{
parent::startQuery($sql, $params, $types);
$this->startTime = microtime(true);
$this->lastSql = $sql;
}
public function stopQuery()
{
parent::stopQuery();
\Log::info(json_encode(array(
'sql' => $this->lastSql,
'elapsedTime' => sprintf('%.10f', (microtime(true) - $this->startTime)),
)));
}
}
namespaceをAutoloaderに設定して読み込まれるようにする
今後のことを考え、PSR-0準拠で読み込むようにする。
<?php
//...
// SQLLoggerが属するネームスペースをFuelPHPのAutoloaderに追加
Autoloader::add_namespace('Sample\Doctrine', APPPATH.'classes'.DIRECTORY_SEPARATOR.'doctrine'.DIRECTORY_SEPARATOR, true);
Autoloader::add_classes(array(
));
// Register the autoloader
Autoloader::register();
//...
拡張したSQLLoggerをDoctrine2に渡す設定をする
拡張したところで設定しないと使われないので、設定をする。
<?php
return array(
'doctrine2' => array(
'proxy_dir' => APPPATH.'classes'.DIRECTORY_SEPARATOR.'proxy',
'proxy_namespace' => 'Proxy',
'metadata_path' => APPPATH.'classes'.DIRECTORY_SEPARATOR.'entity',
'init_callback' => function($manager, $connection)
{
// Doctrineセットアップ時の一番最後に呼ばれるコールバック
$manager
->getConnection()
->getConfiguration()
->setSQLLogger(new Sample\Doctrine\SQLLogger($connection));
},
),
//...
);
※profiling
が無効の時は考慮できていないので、おそらく正しく動かない
おしまい
おしまい。