251 lines
8.9 KiB
PHP
251 lines
8.9 KiB
PHP
<?php
|
|
/*
|
|
* $Id$
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* This software consists of voluntary contributions made by many individuals
|
|
* and is licensed under the LGPL. For more information, see
|
|
* <http://www.phpdoctrine.com>.
|
|
*/
|
|
/**
|
|
* 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);
|
|
}
|
|
}
|