File indexing completed on 2025-01-19 05:21:03
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Db 0017 * @subpackage Profiler 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @license http://framework.zend.com/license/new-bsd New BSD License 0020 * @version $Id$ 0021 */ 0022 0023 0024 /** 0025 * @category Zend 0026 * @package Zend_Db 0027 * @subpackage Profiler 0028 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0029 * @license http://framework.zend.com/license/new-bsd New BSD License 0030 */ 0031 class Zend_Db_Profiler 0032 { 0033 0034 /** 0035 * A connection operation or selecting a database. 0036 */ 0037 const CONNECT = 1; 0038 0039 /** 0040 * Any general database query that does not fit into the other constants. 0041 */ 0042 const QUERY = 2; 0043 0044 /** 0045 * Adding new data to the database, such as SQL's INSERT. 0046 */ 0047 const INSERT = 4; 0048 0049 /** 0050 * Updating existing information in the database, such as SQL's UPDATE. 0051 * 0052 */ 0053 const UPDATE = 8; 0054 0055 /** 0056 * An operation related to deleting data in the database, 0057 * such as SQL's DELETE. 0058 */ 0059 const DELETE = 16; 0060 0061 /** 0062 * Retrieving information from the database, such as SQL's SELECT. 0063 */ 0064 const SELECT = 32; 0065 0066 /** 0067 * Transactional operation, such as start transaction, commit, or rollback. 0068 */ 0069 const TRANSACTION = 64; 0070 0071 /** 0072 * Inform that a query is stored (in case of filtering) 0073 */ 0074 const STORED = 'stored'; 0075 0076 /** 0077 * Inform that a query is ignored (in case of filtering) 0078 */ 0079 const IGNORED = 'ignored'; 0080 0081 /** 0082 * Array of Zend_Db_Profiler_Query objects. 0083 * 0084 * @var array 0085 */ 0086 protected $_queryProfiles = array(); 0087 0088 /** 0089 * Stores enabled state of the profiler. If set to False, calls to 0090 * queryStart() will simply be ignored. 0091 * 0092 * @var boolean 0093 */ 0094 protected $_enabled = false; 0095 0096 /** 0097 * Stores the number of seconds to filter. NULL if filtering by time is 0098 * disabled. If an integer is stored here, profiles whose elapsed time 0099 * is less than this value in seconds will be unset from 0100 * the self::$_queryProfiles array. 0101 * 0102 * @var integer 0103 */ 0104 protected $_filterElapsedSecs = null; 0105 0106 /** 0107 * Logical OR of any of the filter constants. NULL if filtering by query 0108 * type is disable. If an integer is stored here, it is the logical OR of 0109 * any of the query type constants. When the query ends, if it is not 0110 * one of the types specified, it will be unset from the 0111 * self::$_queryProfiles array. 0112 * 0113 * @var integer 0114 */ 0115 protected $_filterTypes = null; 0116 0117 /** 0118 * Class constructor. The profiler is disabled by default unless it is 0119 * specifically enabled by passing in $enabled here or calling setEnabled(). 0120 * 0121 * @param boolean $enabled 0122 * @return void 0123 */ 0124 public function __construct($enabled = false) 0125 { 0126 $this->setEnabled($enabled); 0127 } 0128 0129 /** 0130 * Enable or disable the profiler. If $enable is false, the profiler 0131 * is disabled and will not log any queries sent to it. 0132 * 0133 * @param boolean $enable 0134 * @return Zend_Db_Profiler Provides a fluent interface 0135 */ 0136 public function setEnabled($enable) 0137 { 0138 $this->_enabled = (boolean) $enable; 0139 0140 return $this; 0141 } 0142 0143 /** 0144 * Get the current state of enable. If True is returned, 0145 * the profiler is enabled. 0146 * 0147 * @return boolean 0148 */ 0149 public function getEnabled() 0150 { 0151 return $this->_enabled; 0152 } 0153 0154 /** 0155 * Sets a minimum number of seconds for saving query profiles. If this 0156 * is set, only those queries whose elapsed time is equal or greater than 0157 * $minimumSeconds will be saved. To save all queries regardless of 0158 * elapsed time, set $minimumSeconds to null. 0159 * 0160 * @param integer $minimumSeconds OPTIONAL 0161 * @return Zend_Db_Profiler Provides a fluent interface 0162 */ 0163 public function setFilterElapsedSecs($minimumSeconds = null) 0164 { 0165 if (null === $minimumSeconds) { 0166 $this->_filterElapsedSecs = null; 0167 } else { 0168 $this->_filterElapsedSecs = (integer) $minimumSeconds; 0169 } 0170 0171 return $this; 0172 } 0173 0174 /** 0175 * Returns the minimum number of seconds for saving query profiles, or null if 0176 * query profiles are saved regardless of elapsed time. 0177 * 0178 * @return integer|null 0179 */ 0180 public function getFilterElapsedSecs() 0181 { 0182 return $this->_filterElapsedSecs; 0183 } 0184 0185 /** 0186 * Sets the types of query profiles to save. Set $queryType to one of 0187 * the Zend_Db_Profiler::* constants to only save profiles for that type of 0188 * query. To save more than one type, logical OR them together. To 0189 * save all queries regardless of type, set $queryType to null. 0190 * 0191 * @param integer $queryTypes OPTIONAL 0192 * @return Zend_Db_Profiler Provides a fluent interface 0193 */ 0194 public function setFilterQueryType($queryTypes = null) 0195 { 0196 $this->_filterTypes = $queryTypes; 0197 0198 return $this; 0199 } 0200 0201 /** 0202 * Returns the types of query profiles saved, or null if queries are saved regardless 0203 * of their types. 0204 * 0205 * @return integer|null 0206 * @see Zend_Db_Profiler::setFilterQueryType() 0207 */ 0208 public function getFilterQueryType() 0209 { 0210 return $this->_filterTypes; 0211 } 0212 0213 /** 0214 * Clears the history of any past query profiles. This is relentless 0215 * and will even clear queries that were started and may not have 0216 * been marked as ended. 0217 * 0218 * @return Zend_Db_Profiler Provides a fluent interface 0219 */ 0220 public function clear() 0221 { 0222 $this->_queryProfiles = array(); 0223 0224 return $this; 0225 } 0226 0227 /** 0228 * Clone a profiler query 0229 * 0230 * @param Zend_Db_Profiler_Query $query 0231 * @return integer or null 0232 */ 0233 public function queryClone(Zend_Db_Profiler_Query $query) 0234 { 0235 $this->_queryProfiles[] = clone $query; 0236 0237 end($this->_queryProfiles); 0238 0239 return key($this->_queryProfiles); 0240 } 0241 0242 /** 0243 * Starts a query. Creates a new query profile object (Zend_Db_Profiler_Query) 0244 * and returns the "query profiler handle". Run the query, then call 0245 * queryEnd() and pass it this handle to make the query as ended and 0246 * record the time. If the profiler is not enabled, this takes no 0247 * action and immediately returns null. 0248 * 0249 * @param string $queryText SQL statement 0250 * @param integer $queryType OPTIONAL Type of query, one of the Zend_Db_Profiler::* constants 0251 * @return integer|null 0252 */ 0253 public function queryStart($queryText, $queryType = null) 0254 { 0255 if (!$this->_enabled) { 0256 return null; 0257 } 0258 0259 // make sure we have a query type 0260 if (null === $queryType) { 0261 switch (strtolower(substr(ltrim($queryText), 0, 6))) { 0262 case 'insert': 0263 $queryType = self::INSERT; 0264 break; 0265 case 'update': 0266 $queryType = self::UPDATE; 0267 break; 0268 case 'delete': 0269 $queryType = self::DELETE; 0270 break; 0271 case 'select': 0272 $queryType = self::SELECT; 0273 break; 0274 default: 0275 $queryType = self::QUERY; 0276 break; 0277 } 0278 } 0279 0280 /** 0281 * @see Zend_Db_Profiler_Query 0282 */ 0283 // require_once 'Zend/Db/Profiler/Query.php'; 0284 $this->_queryProfiles[] = new Zend_Db_Profiler_Query($queryText, $queryType); 0285 0286 end($this->_queryProfiles); 0287 0288 return key($this->_queryProfiles); 0289 } 0290 0291 /** 0292 * Ends a query. Pass it the handle that was returned by queryStart(). 0293 * This will mark the query as ended and save the time. 0294 * 0295 * @param integer $queryId 0296 * @throws Zend_Db_Profiler_Exception 0297 * @return string Inform that a query is stored or ignored. 0298 */ 0299 public function queryEnd($queryId) 0300 { 0301 // Don't do anything if the Zend_Db_Profiler is not enabled. 0302 if (!$this->_enabled) { 0303 return self::IGNORED; 0304 } 0305 0306 // Check for a valid query handle. 0307 if (!isset($this->_queryProfiles[$queryId])) { 0308 /** 0309 * @see Zend_Db_Profiler_Exception 0310 */ 0311 // require_once 'Zend/Db/Profiler/Exception.php'; 0312 throw new Zend_Db_Profiler_Exception("Profiler has no query with handle '$queryId'."); 0313 } 0314 0315 $qp = $this->_queryProfiles[$queryId]; 0316 0317 // Ensure that the query profile has not already ended 0318 if ($qp->hasEnded()) { 0319 /** 0320 * @see Zend_Db_Profiler_Exception 0321 */ 0322 // require_once 'Zend/Db/Profiler/Exception.php'; 0323 throw new Zend_Db_Profiler_Exception("Query with profiler handle '$queryId' has already ended."); 0324 } 0325 0326 // End the query profile so that the elapsed time can be calculated. 0327 $qp->end(); 0328 0329 /** 0330 * If filtering by elapsed time is enabled, only keep the profile if 0331 * it ran for the minimum time. 0332 */ 0333 if (null !== $this->_filterElapsedSecs && $qp->getElapsedSecs() < $this->_filterElapsedSecs) { 0334 unset($this->_queryProfiles[$queryId]); 0335 return self::IGNORED; 0336 } 0337 0338 /** 0339 * If filtering by query type is enabled, only keep the query if 0340 * it was one of the allowed types. 0341 */ 0342 if (null !== $this->_filterTypes && !($qp->getQueryType() & $this->_filterTypes)) { 0343 unset($this->_queryProfiles[$queryId]); 0344 return self::IGNORED; 0345 } 0346 0347 return self::STORED; 0348 } 0349 0350 /** 0351 * Get a profile for a query. Pass it the same handle that was returned 0352 * by queryStart() and it will return a Zend_Db_Profiler_Query object. 0353 * 0354 * @param integer $queryId 0355 * @throws Zend_Db_Profiler_Exception 0356 * @return Zend_Db_Profiler_Query 0357 */ 0358 public function getQueryProfile($queryId) 0359 { 0360 if (!array_key_exists($queryId, $this->_queryProfiles)) { 0361 /** 0362 * @see Zend_Db_Profiler_Exception 0363 */ 0364 // require_once 'Zend/Db/Profiler/Exception.php'; 0365 throw new Zend_Db_Profiler_Exception("Query handle '$queryId' not found in profiler log."); 0366 } 0367 0368 return $this->_queryProfiles[$queryId]; 0369 } 0370 0371 /** 0372 * Get an array of query profiles (Zend_Db_Profiler_Query objects). If $queryType 0373 * is set to one of the Zend_Db_Profiler::* constants then only queries of that 0374 * type will be returned. Normally, queries that have not yet ended will 0375 * not be returned unless $showUnfinished is set to True. If no 0376 * queries were found, False is returned. The returned array is indexed by the query 0377 * profile handles. 0378 * 0379 * @param integer $queryType 0380 * @param boolean $showUnfinished 0381 * @return array|false 0382 */ 0383 public function getQueryProfiles($queryType = null, $showUnfinished = false) 0384 { 0385 $queryProfiles = array(); 0386 foreach ($this->_queryProfiles as $key => $qp) { 0387 if ($queryType === null) { 0388 $condition = true; 0389 } else { 0390 $condition = ($qp->getQueryType() & $queryType); 0391 } 0392 0393 if (($qp->hasEnded() || $showUnfinished) && $condition) { 0394 $queryProfiles[$key] = $qp; 0395 } 0396 } 0397 0398 if (empty($queryProfiles)) { 0399 $queryProfiles = false; 0400 } 0401 0402 return $queryProfiles; 0403 } 0404 0405 /** 0406 * Get the total elapsed time (in seconds) of all of the profiled queries. 0407 * Only queries that have ended will be counted. If $queryType is set to 0408 * one or more of the Zend_Db_Profiler::* constants, the elapsed time will be calculated 0409 * only for queries of the given type(s). 0410 * 0411 * @param integer $queryType OPTIONAL 0412 * @return float 0413 */ 0414 public function getTotalElapsedSecs($queryType = null) 0415 { 0416 $elapsedSecs = 0; 0417 foreach ($this->_queryProfiles as $key => $qp) { 0418 if (null === $queryType) { 0419 $condition = true; 0420 } else { 0421 $condition = ($qp->getQueryType() & $queryType); 0422 } 0423 if (($qp->hasEnded()) && $condition) { 0424 $elapsedSecs += $qp->getElapsedSecs(); 0425 } 0426 } 0427 return $elapsedSecs; 0428 } 0429 0430 /** 0431 * Get the total number of queries that have been profiled. Only queries that have ended will 0432 * be counted. If $queryType is set to one of the Zend_Db_Profiler::* constants, only queries of 0433 * that type will be counted. 0434 * 0435 * @param integer $queryType OPTIONAL 0436 * @return integer 0437 */ 0438 public function getTotalNumQueries($queryType = null) 0439 { 0440 if (null === $queryType) { 0441 return count($this->_queryProfiles); 0442 } 0443 0444 $numQueries = 0; 0445 foreach ($this->_queryProfiles as $qp) { 0446 if ($qp->hasEnded() && ($qp->getQueryType() & $queryType)) { 0447 $numQueries++; 0448 } 0449 } 0450 0451 return $numQueries; 0452 } 0453 0454 /** 0455 * Get the Zend_Db_Profiler_Query object for the last query that was run, regardless if it has 0456 * ended or not. If the query has not ended, its end time will be null. If no queries have 0457 * been profiled, false is returned. 0458 * 0459 * @return Zend_Db_Profiler_Query|false 0460 */ 0461 public function getLastQueryProfile() 0462 { 0463 if (empty($this->_queryProfiles)) { 0464 return false; 0465 } 0466 0467 end($this->_queryProfiles); 0468 0469 return current($this->_queryProfiles); 0470 } 0471 0472 } 0473