PageRenderTime 50ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/ZendFramework/library/Zend/Db/Profiler.php

https://bitbucket.org/Dal-Papa/is-340-publish-base
PHP | 473 lines | 179 code | 58 blank | 236 comment | 27 complexity | 21d43c54e64551c284c4fc4bb7891e6e MD5 | raw file
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Db
  17. * @subpackage Profiler
  18. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id: Profiler.php 25127 2012-11-16 15:17:42Z rob $
  21. */
  22. /**
  23. * @category Zend
  24. * @package Zend_Db
  25. * @subpackage Profiler
  26. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  27. * @license http://framework.zend.com/license/new-bsd New BSD License
  28. */
  29. class Zend_Db_Profiler
  30. {
  31. /**
  32. * A connection operation or selecting a database.
  33. */
  34. const CONNECT = 1;
  35. /**
  36. * Any general database query that does not fit into the other constants.
  37. */
  38. const QUERY = 2;
  39. /**
  40. * Adding new data to the database, such as SQL's INSERT.
  41. */
  42. const INSERT = 4;
  43. /**
  44. * Updating existing information in the database, such as SQL's UPDATE.
  45. *
  46. */
  47. const UPDATE = 8;
  48. /**
  49. * An operation related to deleting data in the database,
  50. * such as SQL's DELETE.
  51. */
  52. const DELETE = 16;
  53. /**
  54. * Retrieving information from the database, such as SQL's SELECT.
  55. */
  56. const SELECT = 32;
  57. /**
  58. * Transactional operation, such as start transaction, commit, or rollback.
  59. */
  60. const TRANSACTION = 64;
  61. /**
  62. * Inform that a query is stored (in case of filtering)
  63. */
  64. const STORED = 'stored';
  65. /**
  66. * Inform that a query is ignored (in case of filtering)
  67. */
  68. const IGNORED = 'ignored';
  69. /**
  70. * Array of Zend_Db_Profiler_Query objects.
  71. *
  72. * @var array
  73. */
  74. protected $_queryProfiles = array();
  75. /**
  76. * Stores enabled state of the profiler. If set to False, calls to
  77. * queryStart() will simply be ignored.
  78. *
  79. * @var boolean
  80. */
  81. protected $_enabled = false;
  82. /**
  83. * Stores the number of seconds to filter. NULL if filtering by time is
  84. * disabled. If an integer is stored here, profiles whose elapsed time
  85. * is less than this value in seconds will be unset from
  86. * the self::$_queryProfiles array.
  87. *
  88. * @var integer
  89. */
  90. protected $_filterElapsedSecs = null;
  91. /**
  92. * Logical OR of any of the filter constants. NULL if filtering by query
  93. * type is disable. If an integer is stored here, it is the logical OR of
  94. * any of the query type constants. When the query ends, if it is not
  95. * one of the types specified, it will be unset from the
  96. * self::$_queryProfiles array.
  97. *
  98. * @var integer
  99. */
  100. protected $_filterTypes = null;
  101. /**
  102. * Class constructor. The profiler is disabled by default unless it is
  103. * specifically enabled by passing in $enabled here or calling setEnabled().
  104. *
  105. * @param boolean $enabled
  106. * @return void
  107. */
  108. public function __construct($enabled = false)
  109. {
  110. $this->setEnabled($enabled);
  111. }
  112. /**
  113. * Enable or disable the profiler. If $enable is false, the profiler
  114. * is disabled and will not log any queries sent to it.
  115. *
  116. * @param boolean $enable
  117. * @return Zend_Db_Profiler Provides a fluent interface
  118. */
  119. public function setEnabled($enable)
  120. {
  121. $this->_enabled = (boolean) $enable;
  122. return $this;
  123. }
  124. /**
  125. * Get the current state of enable. If True is returned,
  126. * the profiler is enabled.
  127. *
  128. * @return boolean
  129. */
  130. public function getEnabled()
  131. {
  132. return $this->_enabled;
  133. }
  134. /**
  135. * Sets a minimum number of seconds for saving query profiles. If this
  136. * is set, only those queries whose elapsed time is equal or greater than
  137. * $minimumSeconds will be saved. To save all queries regardless of
  138. * elapsed time, set $minimumSeconds to null.
  139. *
  140. * @param integer $minimumSeconds OPTIONAL
  141. * @return Zend_Db_Profiler Provides a fluent interface
  142. */
  143. public function setFilterElapsedSecs($minimumSeconds = null)
  144. {
  145. if (null === $minimumSeconds) {
  146. $this->_filterElapsedSecs = null;
  147. } else {
  148. $this->_filterElapsedSecs = (integer) $minimumSeconds;
  149. }
  150. return $this;
  151. }
  152. /**
  153. * Returns the minimum number of seconds for saving query profiles, or null if
  154. * query profiles are saved regardless of elapsed time.
  155. *
  156. * @return integer|null
  157. */
  158. public function getFilterElapsedSecs()
  159. {
  160. return $this->_filterElapsedSecs;
  161. }
  162. /**
  163. * Sets the types of query profiles to save. Set $queryType to one of
  164. * the Zend_Db_Profiler::* constants to only save profiles for that type of
  165. * query. To save more than one type, logical OR them together. To
  166. * save all queries regardless of type, set $queryType to null.
  167. *
  168. * @param integer $queryTypes OPTIONAL
  169. * @return Zend_Db_Profiler Provides a fluent interface
  170. */
  171. public function setFilterQueryType($queryTypes = null)
  172. {
  173. $this->_filterTypes = $queryTypes;
  174. return $this;
  175. }
  176. /**
  177. * Returns the types of query profiles saved, or null if queries are saved regardless
  178. * of their types.
  179. *
  180. * @return integer|null
  181. * @see Zend_Db_Profiler::setFilterQueryType()
  182. */
  183. public function getFilterQueryType()
  184. {
  185. return $this->_filterTypes;
  186. }
  187. /**
  188. * Clears the history of any past query profiles. This is relentless
  189. * and will even clear queries that were started and may not have
  190. * been marked as ended.
  191. *
  192. * @return Zend_Db_Profiler Provides a fluent interface
  193. */
  194. public function clear()
  195. {
  196. $this->_queryProfiles = array();
  197. return $this;
  198. }
  199. /**
  200. * Clone a profiler query
  201. *
  202. * @param Zend_Db_Profiler_Query $query
  203. * @return integer or null
  204. */
  205. public function queryClone(Zend_Db_Profiler_Query $query)
  206. {
  207. $this->_queryProfiles[] = clone $query;
  208. end($this->_queryProfiles);
  209. return key($this->_queryProfiles);
  210. }
  211. /**
  212. * Starts a query. Creates a new query profile object (Zend_Db_Profiler_Query)
  213. * and returns the "query profiler handle". Run the query, then call
  214. * queryEnd() and pass it this handle to make the query as ended and
  215. * record the time. If the profiler is not enabled, this takes no
  216. * action and immediately returns null.
  217. *
  218. * @param string $queryText SQL statement
  219. * @param integer $queryType OPTIONAL Type of query, one of the Zend_Db_Profiler::* constants
  220. * @return integer|null
  221. */
  222. public function queryStart($queryText, $queryType = null)
  223. {
  224. if (!$this->_enabled) {
  225. return null;
  226. }
  227. // make sure we have a query type
  228. if (null === $queryType) {
  229. switch (strtolower(substr(ltrim($queryText), 0, 6))) {
  230. case 'insert':
  231. $queryType = self::INSERT;
  232. break;
  233. case 'update':
  234. $queryType = self::UPDATE;
  235. break;
  236. case 'delete':
  237. $queryType = self::DELETE;
  238. break;
  239. case 'select':
  240. $queryType = self::SELECT;
  241. break;
  242. default:
  243. $queryType = self::QUERY;
  244. break;
  245. }
  246. }
  247. /**
  248. * @see Zend_Db_Profiler_Query
  249. */
  250. require_once 'Zend/Db/Profiler/Query.php';
  251. $this->_queryProfiles[] = new Zend_Db_Profiler_Query($queryText, $queryType);
  252. end($this->_queryProfiles);
  253. return key($this->_queryProfiles);
  254. }
  255. /**
  256. * Ends a query. Pass it the handle that was returned by queryStart().
  257. * This will mark the query as ended and save the time.
  258. *
  259. * @param integer $queryId
  260. * @throws Zend_Db_Profiler_Exception
  261. * @return string Inform that a query is stored or ignored.
  262. */
  263. public function queryEnd($queryId)
  264. {
  265. // Don't do anything if the Zend_Db_Profiler is not enabled.
  266. if (!$this->_enabled) {
  267. return self::IGNORED;
  268. }
  269. // Check for a valid query handle.
  270. if (!isset($this->_queryProfiles[$queryId])) {
  271. /**
  272. * @see Zend_Db_Profiler_Exception
  273. */
  274. require_once 'Zend/Db/Profiler/Exception.php';
  275. throw new Zend_Db_Profiler_Exception("Profiler has no query with handle '$queryId'.");
  276. }
  277. $qp = $this->_queryProfiles[$queryId];
  278. // Ensure that the query profile has not already ended
  279. if ($qp->hasEnded()) {
  280. /**
  281. * @see Zend_Db_Profiler_Exception
  282. */
  283. require_once 'Zend/Db/Profiler/Exception.php';
  284. throw new Zend_Db_Profiler_Exception("Query with profiler handle '$queryId' has already ended.");
  285. }
  286. // End the query profile so that the elapsed time can be calculated.
  287. $qp->end();
  288. /**
  289. * If filtering by elapsed time is enabled, only keep the profile if
  290. * it ran for the minimum time.
  291. */
  292. if (null !== $this->_filterElapsedSecs && $qp->getElapsedSecs() < $this->_filterElapsedSecs) {
  293. unset($this->_queryProfiles[$queryId]);
  294. return self::IGNORED;
  295. }
  296. /**
  297. * If filtering by query type is enabled, only keep the query if
  298. * it was one of the allowed types.
  299. */
  300. if (null !== $this->_filterTypes && !($qp->getQueryType() & $this->_filterTypes)) {
  301. unset($this->_queryProfiles[$queryId]);
  302. return self::IGNORED;
  303. }
  304. return self::STORED;
  305. }
  306. /**
  307. * Get a profile for a query. Pass it the same handle that was returned
  308. * by queryStart() and it will return a Zend_Db_Profiler_Query object.
  309. *
  310. * @param integer $queryId
  311. * @throws Zend_Db_Profiler_Exception
  312. * @return Zend_Db_Profiler_Query
  313. */
  314. public function getQueryProfile($queryId)
  315. {
  316. if (!array_key_exists($queryId, $this->_queryProfiles)) {
  317. /**
  318. * @see Zend_Db_Profiler_Exception
  319. */
  320. require_once 'Zend/Db/Profiler/Exception.php';
  321. throw new Zend_Db_Profiler_Exception("Query handle '$queryId' not found in profiler log.");
  322. }
  323. return $this->_queryProfiles[$queryId];
  324. }
  325. /**
  326. * Get an array of query profiles (Zend_Db_Profiler_Query objects). If $queryType
  327. * is set to one of the Zend_Db_Profiler::* constants then only queries of that
  328. * type will be returned. Normally, queries that have not yet ended will
  329. * not be returned unless $showUnfinished is set to True. If no
  330. * queries were found, False is returned. The returned array is indexed by the query
  331. * profile handles.
  332. *
  333. * @param integer $queryType
  334. * @param boolean $showUnfinished
  335. * @return array|false
  336. */
  337. public function getQueryProfiles($queryType = null, $showUnfinished = false)
  338. {
  339. $queryProfiles = array();
  340. foreach ($this->_queryProfiles as $key => $qp) {
  341. if ($queryType === null) {
  342. $condition = true;
  343. } else {
  344. $condition = ($qp->getQueryType() & $queryType);
  345. }
  346. if (($qp->hasEnded() || $showUnfinished) && $condition) {
  347. $queryProfiles[$key] = $qp;
  348. }
  349. }
  350. if (empty($queryProfiles)) {
  351. $queryProfiles = false;
  352. }
  353. return $queryProfiles;
  354. }
  355. /**
  356. * Get the total elapsed time (in seconds) of all of the profiled queries.
  357. * Only queries that have ended will be counted. If $queryType is set to
  358. * one or more of the Zend_Db_Profiler::* constants, the elapsed time will be calculated
  359. * only for queries of the given type(s).
  360. *
  361. * @param integer $queryType OPTIONAL
  362. * @return float
  363. */
  364. public function getTotalElapsedSecs($queryType = null)
  365. {
  366. $elapsedSecs = 0;
  367. foreach ($this->_queryProfiles as $key => $qp) {
  368. if (null === $queryType) {
  369. $condition = true;
  370. } else {
  371. $condition = ($qp->getQueryType() & $queryType);
  372. }
  373. if (($qp->hasEnded()) && $condition) {
  374. $elapsedSecs += $qp->getElapsedSecs();
  375. }
  376. }
  377. return $elapsedSecs;
  378. }
  379. /**
  380. * Get the total number of queries that have been profiled. Only queries that have ended will
  381. * be counted. If $queryType is set to one of the Zend_Db_Profiler::* constants, only queries of
  382. * that type will be counted.
  383. *
  384. * @param integer $queryType OPTIONAL
  385. * @return integer
  386. */
  387. public function getTotalNumQueries($queryType = null)
  388. {
  389. if (null === $queryType) {
  390. return count($this->_queryProfiles);
  391. }
  392. $numQueries = 0;
  393. foreach ($this->_queryProfiles as $qp) {
  394. if ($qp->hasEnded() && ($qp->getQueryType() & $queryType)) {
  395. $numQueries++;
  396. }
  397. }
  398. return $numQueries;
  399. }
  400. /**
  401. * Get the Zend_Db_Profiler_Query object for the last query that was run, regardless if it has
  402. * ended or not. If the query has not ended, its end time will be null. If no queries have
  403. * been profiled, false is returned.
  404. *
  405. * @return Zend_Db_Profiler_Query|false
  406. */
  407. public function getLastQueryProfile()
  408. {
  409. if (empty($this->_queryProfiles)) {
  410. return false;
  411. }
  412. end($this->_queryProfiles);
  413. return current($this->_queryProfiles);
  414. }
  415. }