. */ /** * Doctrine_Db_Profiler * * @author Konsta Vesterinen * @license LGPL * @package Doctrine */ class Doctrine_Db_Profiler extends Doctrine_Db_EventListener { public function onPreQuery(Doctrine_DB2 $dbh, $statement, array $args) { $this->queryStart($statement); } public function onQuery(Doctrine_DB2 $dbh, $statement, array $args, $queryId) { $this->queryEnd($queryId); } public function onPrePrepare(Doctrine_DB2 $dbh, $statement, array $args) { $this->prepareTimes[$dbh->getQuerySequence()] = microtime(true); } public function onPrepare(Doctrine_DB2 $dbh, $statement, array $args, $queryId) { $this->prepareTimes[$queryId] = (microtime(true) - $this->prepareTimes[$queryId]); } public function onPreCommit(Doctrine_DB2 $dbh) { } public function onCommit(Doctrine_DB2 $dbh) { } public function onPreRollBack(Doctrine_DB2 $dbh) { } public function onRollBack(Doctrine_DB2 $dbh) { } public function onPreBeginTransaction(Doctrine_DB2 $dbh) { } public function onBeginTransaction(Doctrine_DB2 $dbh) { } public function onPreExecute(Doctrine_Db_Statement $stmt, array $params) { $this->queryStart($stmt->getQuery(), $stmt->getQuerySequence()); } public function onExecute(Doctrine_Db_Statement $stmt, array $params) { $this->queryEnd($stmt->getQuerySequence()); } /** * Array of Zend_Db_Profiler_Query objects. * * @var Zend_Db_Profiler_Query */ protected $_queryProfiles = array(); protected $_prepareTimes = array(); /** * Stores the number of seconds to filter. NULL if filtering by time is * disabled. If an integer is stored here, profiles whose elapsed time * is less than this value in seconds will be unset from * the self::$_queryProfiles array. * * @var integer */ protected $_filterElapsedSecs = null; /** * Logical OR of any of the filter constants. NULL if filtering by query * type is disable. If an integer is stored here, it is the logical OR of * any of the query type constants. When the query ends, if it is not * one of the types specified, it will be unset from the * self::$_queryProfiles array. * * @var integer */ protected $_filterTypes = null; /** * Start a query. Creates a new query profile object (Zend_Db_Profiler_Query) * and returns the "query profiler handle". Run the query, then call * queryEnd() and pass it this handle to make the query as ended and * record the time. If the profiler is not enabled, this takes no * action and immediately runs. * * @param string $queryText SQL statement * @param int $queryType Type of query, one of the Zend_Db_Profiler::* constants * @return mixed */ public function queryStart($queryText, $querySequence = -1) { $prepareTime = (isset($this->prepareTimes[$querySequence])) ? $this->prepareTimes[$querySequence] : null; $this->_queryProfiles[] = new Doctrine_Db_Profiler_Query($queryText, $prepareTime); } /** * Ends a query. Pass it the handle that was returned by queryStart(). * This will mark the query as ended and save the time. * * @param integer $queryId * @throws Zend_Db_Profiler_Exception * @return boolean */ public function queryEnd($queryId = null) { // Check for a valid query handle. if($queryId === null) $qp = end($this->_queryProfiles); else $qp = $this->_queryProfiles[$queryId]; if($qp === null || $qp->hasEnded()) { throw new Zend_Db_Profiler_Exception('Query with profiler handle "' . $queryId .'" has already ended.'); } // End the query profile so that the elapsed time can be calculated. $qp->end(); } /** * Get a profile for a query. Pass it the same handle that was returned * by queryStart() and it will return a Zend_Db_Profiler_Query object. * * @param int $queryId * @throws Zend_Db_Profiler_Exception * @return Zend_Db_Profiler_Query */ public function getQueryProfile($queryId) { if (!array_key_exists($queryId, $this->_queryProfiles)) { throw new Zend_Db_Profiler_Exception("Query handle \"$queryId\" not found in profiler log."); } return $this->_queryProfiles[$queryId]; } /** * Get an array of query profiles (Zend_Db_Profiler_Query objects). If $queryType * is set to one of the Zend_Db_Profiler::* constants then only queries of that * type will be returned. Normally, queries that have not yet ended will * not be returned unless $showUnfinished is set to True. If no * queries were found, False is returned. * * @param string $queryType * @param bool $showUnfinished * @return mixed */ public function getQueryProfiles($queryType=null, $showUnfinished=false) { $queryProfiles = array(); foreach ($this->_queryProfiles as $key=>$qp) { /* @var $qp Zend_Db_Profiler_Query */ if ($queryType===null) { $condition=true; } else { $condition=($qp->getQueryType() & $queryType); } if (($qp->hasEnded() || $showUnfinished) && $condition) { $queryProfiles[$key] = $qp; } } if (empty($queryProfiles)) { $queryProfiles = false; } return $queryProfiles; } /** * Get the total elapsed time (in seconds) of all of the profiled queries. * Only queries that have ended will be counted. If $queryType is set to * one of the Zend_Db_Profiler::* constants, the elapsed time will be calculated * only for queries of that type. * * @param int $queryType * @return int */ public function getTotalElapsedSecs($queryType = null) { $elapsedSecs = 0; foreach ($this->_queryProfiles as $key=>$qp) { /* @var $qp Zend_Db_Profiler_Query */ is_null($queryType)? $condition=true : $condition=($qp->getQueryType() & $queryType); if (($qp->hasEnded()) && $condition) { $elapsedSecs += $qp->getElapsedSecs(); } } return $elapsedSecs; } /** * Get the total number of queries that have been profiled. Only queries that have ended will * be counted. If $queryType is set to one of the Zend_Db_Profiler::* constants, only queries of * that type will be counted. * * @param int $queryType * @return int */ public function getTotalNumQueries($queryType = null) { if (is_null($queryType)) { return sizeof($this->_queryProfiles); } $numQueries = 0; foreach ($this->_queryProfiles as $qp) { /* @var $qp Zend_Db_Profiler_Query */ is_null($queryType)? $condition=true : $condition=($qp->getQueryType() & $queryType); if ($qp->hasEnded() && $condition) { $numQueries++; } } return $numQueries; } public function pop() { return array_pop($this->_queryProfiles); } /** * Get the Zend_Db_Profiler_Query object for the last query that was run, regardless if it has * ended or not. If the query has not ended, it's end time will be Null. * * @return Zend_Db_Profiler_Query */ public function lastQuery() { if (empty($this->_queryProfiles)) { return false; } end($this->_queryProfiles); return current($this->_queryProfiles); } }