1: <?php
2: /**
3: * This class is so that you could access the query profile data within
4: * your view containing the information on the latest queries without
5: * having to pass the entire AMysql object onto the view.
6: *
7: * The problem with simply calling $amysql->getQueriesData() is that you
8: * may be using a framework that doesn't allow you to set a hook for after
9: * resolving the controllers, but before rendering a view. With this class,
10: * you can just fetch it by $amysql->getProfiler(), assign it to view, and
11: * access the latest profiler data with $profiler['queriesData'] and
12: * $profiler['totalTime'].
13: *
14: * Enable the profiler by setting the AMysql object's profileQueries
15: * proterty to true.
16: *
17: * Visit https://github.com/amcsi/amysql
18: * @author Szerémi Attila
19: * @license MIT License; http://www.opensource.org/licenses/mit-license.php
20: */
21: class AMysql_Profiler implements ArrayAccess
22: {
23: protected $amysql;
24:
25: /**
26: * The total time all the queries have taken so far.
27: *
28: * @var float
29: * @access protected
30: */
31: protected $totalTime = 0.0;
32: protected $queries = array();
33: protected $queriesData = array();
34:
35: public function __construct(AMysql_Abstract $amysql)
36: {
37: $this->amysql = $amysql;
38: }
39:
40: /**
41: * @deprecated Profiling is always enabled and cannot be turned off.
42: *
43: * @param mixed $enabled
44: * @access public
45: * @return $this
46: */
47: public function setEnabled($enabled)
48: {
49: return $this;
50: }
51:
52: /**
53: * Gets the profile data as an HTML table with by a template shipped with
54: * this library.
55: * Can also be called with the help of ArrayAccess via $this['asHtml']
56: *
57: * @access public
58: * @return string
59: */
60: public function getAsHtml()
61: {
62: if (!$encoding) {
63: $encoding = $this->defaultEncoding;
64: }
65: $tplBaseDir = dirname(__FILE__) . '/../tpl';
66: $filename = "$tplBaseDir/profileTemplate.php";
67: $profiler = $this;
68: ob_start();
69: include $filename;
70: $html = ob_get_clean();
71: return $html;
72: }
73:
74: /**
75: * Gets the profile data as an array.
76: * Can also be called with the help of ArrayAccess via $this['asArray']
77: *
78: * @access public
79: * @return array
80: */
81: public function getAsArray()
82: {
83: return array(
84: 'totalTime' => $this['totalTime'],
85: 'queriesData' => $this['queriesData']
86: );
87: }
88:
89: public function offsetExists($key)
90: {
91: return in_array(
92: $key,
93: array(
94: 'asHtml', 'totalTime', 'queriesData'
95: )
96: );
97: }
98:
99: /**
100: * Adds a query and a profile for it to the list of queries.
101: * Used by AMysql_Statement. Do not call externally!
102: *
103: * @param string $query The SQL query.
104: * @param float $queryTime The time the query took.
105: * @access public
106: * @return $this
107: */
108: public function addQuery($query, $queryTime)
109: {
110: $this->queries[] = $query;
111: $data = array (
112: 'query' => $query,
113: 'time' => $queryTime,
114: 'backtrace' => array(),
115: );
116: if ($this->amysql->includeBacktrace) {
117: $opts = 0;
118: if (defined('DEBUG_BACKTRACE_IGNORE_ARGS')) {
119: $opts |= DEBUG_BACKTRACE_IGNORE_ARGS;
120: }
121: $data['backtrace'] = debug_backtrace($opts);
122: }
123: $this->queriesData[] = $data;
124: if (is_numeric($queryTime)) {
125: $this->totalTime += $queryTime;
126: }
127: return $this;
128: }
129:
130: /**
131: * Gets the list of SQL queries performed so far by AMysql_Statement
132: * objects connected by this object.
133: *
134: * @access public
135: * @return array
136: */
137: public function getQueries()
138: {
139: return $this->queries;
140: }
141:
142: /**
143: * Returns an arrays of profiled query data. Each value is an array that consists
144: * of:
145: * - query - The SQL query performed
146: * - time - The amount of seconds the query took (float)
147: *
148: * If profileQueries wss off at any query, its time value will be null.
149: *
150: * @return array[]
151: */
152: public function getQueriesData()
153: {
154: return $this->queriesData;
155: }
156:
157: /**
158: * Resets the data in the profiler. Not recommended.
159: * Use AMysql_Abstract::useNewProfiler() instead if possible.
160: *
161: * @access public
162: * @return void
163: */
164: public function reset()
165: {
166: $this->totalTime = 0.0;
167: $this->queriesData = array();
168: return $this;
169: }
170:
171: public function offsetGet($key)
172: {
173: switch ($key) {
174: case 'totalTime':
175: return $this->totalTime;
176: break;
177: case 'queriesData':
178: return $this->getQueriesData();
179: break;
180: case 'asHtml':
181: return $this->getAsHtml();
182: break;
183: case 'asArray':
184: return $this->getAsArray();
185: break;
186: default:
187: trigger_error("Invalid key: `$key`.");
188: break;
189: }
190: }
191:
192: public function offsetSet($key, $value)
193: {
194: trigger_error("Access denied. Cannot set key `$key`.", E_USER_WARNING);
195: }
196:
197: public function offsetUnset($key)
198: {
199: trigger_error(
200: "Access denied. Cannot unset key `$key`.",
201: E_USER_WARNING
202: );
203: return false;
204: }
205:
206: public function __get($key)
207: {
208: return $this->offsetGet($key);
209: }
210: }
211: