Passed
Push — master ( 8b6794...b54c42 )
by Paul
07:34
created

Application::getQueries()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 29
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 24
nc 2
nop 0
dl 0
loc 29
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
namespace GeminiLabs\BlackBar;
4
5
use GeminiLabs\BlackBar\Profiler;
6
7
final class Application
8
{
9
	const DEBUG = 'debug';
10
	const ID = 'blackbar';
11
	const LANG = '/languages/';
12
13
	protected $errors = array();
14
	protected $file;
15
	protected $profiler;
16
17
	public function __construct()
18
	{
19
		$this->file = realpath( dirname( __DIR__ ).'/'.static::ID.'.php' );
20
		$this->profiler = new Profiler;
21
	}
22
23
	/**
24
	 * @return void
25
	 * @action admin_enqueue_scripts
26
	 * @action wp_enqueue_scripts
27
	 */
28
	public function enqueueAssets()
29
	{
30
		wp_enqueue_script( static::ID, $this->url( 'assets/main.js' ));
31
		wp_enqueue_style( static::ID, $this->url( 'assets/main.css' ), array( 'dashicons' ));
32
		wp_enqueue_style( static::ID.'-syntax', $this->url( 'assets/syntax.css' ));
33
	}
34
35
	/**
36
	 * @param int $errno
37
	 * @param string $errstr
38
	 * @param string $errfile
39
	 * @param int $errline
40
	 * @return void
41
	 */
42
	public function errorHandler( $errno, $errstr, $errfile, $errline )
43
	{
44
		$errorCodes = array(
45
			2 => 'Warning',
46
			8 => 'Notice',
47
			2048 => 'Strict',
48
			8192 => 'Deprecated',
49
		);
50
		$errname = array_key_exists( $errno, $errorCodes )
51
			? $errorCodes[$errno]
52
			: 'Unknown';
53
		$hash = md5( $errno.$errstr.$errfile.$errline );
54
		if( array_key_exists( $hash, $this->errors )) {
55
			$this->errors[$hash]['count']++;
56
		}
57
		else {
58
			$this->errors[$hash] = array(
59
				"errno" => $errno,
60
				"message" => $errstr,
61
				"file" => $errfile,
62
				"name" => $errname,
63
				"line" => $errline,
64
				"count" => 0,
65
			);
66
		}
67
	}
68
69
	/**
70
	 * @param string $classes
71
	 * @return string
72
	 */
73
	public function filterBodyClasses( $classes )
74
	{
75
		return trim( $classes.' '.static::ID );
76
	}
77
78
	/**
79
	 * @return array
80
	 */
81
	public function filterNoconflictScripts( $scripts )
82
	{
83
		$scripts[] = static::ID;
84
		return $scripts;
85
	}
86
87
	/**
88
	 * @return array
89
	 */
90
	public function filterNoconflictStyles( $styles )
91
	{
92
		$styles[] = static::ID;
93
		$styles[] = static::ID.'-syntax';
94
		return $styles;
95
	}
96
97
	/**
98
	 * @return void
99
	 */
100
	public function init()
101
	{
102
		add_action( 'admin_enqueue_scripts',    array( $this, 'enqueueAssets' ));
103
		add_action( 'admin_footer',             array( $this, 'renderBar' ));
104
		add_action( 'plugins_loaded',           array( $this, 'registerLanguages' ));
105
		add_action( 'wp_enqueue_scripts',       array( $this, 'enqueueAssets' ));
106
		add_action( 'wp_footer',                array( $this, 'renderBar' ));
107
		add_filter( 'admin_body_class',         array( $this, 'filterBodyClasses' ));
108
		add_filter( 'all',                      array( $this, 'initProfiler' ));
109
		add_filter( 'gform_noconflict_scripts', array( $this, 'filterNoconflictScripts' ) );
110
		add_filter( 'gform_noconflict_styles',  array( $this, 'filterNoconflictStyles' ) );
111
		apply_filters( 'debug', 'Profiler Started' );
112
		apply_filters( 'debug', 'blackbar/profiler/noise' );
113
		set_error_handler( array( $this, 'errorHandler' ), E_ALL|E_STRICT );
114
	}
115
116
	/**
117
	 * @return void
118
	 * @action all
119
	 */
120
	public function initProfiler()
121
	{
122
		if( func_get_arg(0) != static::DEBUG )return;
123
		$this->profiler->trace( func_get_arg(1) );
124
	}
125
126
	/**
127
	 * @return void
128
	 */
129
	public function registerLanguages()
130
	{
131
		load_plugin_textdomain( static::ID, false, plugin_basename( $this->path() ).static::LANG );
132
	}
133
134
	/**
135
	 * Render a view and pass any provided data to the view
136
	 *
137
	 * @param string $view
138
	 * @return void
139
	 */
140
	public function render( $view, array $data = array() )
141
	{
142
		$file = $this->path( sprintf( 'views/%s.php', str_replace( '.php', '', $view )));
143
		if( !file_exists( $file ))return;
144
		extract( $data );
145
		include $file;
146
	}
147
148
	/**
149
	 * @return void
150
	 * @action admin_footer
151
	 * @action wp_footer
152
	 */
153
	public function renderBar()
154
	{
155
		apply_filters( 'debug', 'Profiler Stopped' );
156
		$this->render( 'debug-bar', array(
157
			'blackbar' => $this,
158
			'errors' => $this->getErrors(),
159
			'errorsLabel' => $this->getErrorsLabel(),
160
			'profiler' => $this->profiler,
161
			'profilerLabel' => $this->getProfilerLabel(),
162
			'queries' => $this->getQueries(),
163
			'queriesLabel' => $this->getQueriesLabel(),
164
		));
165
	}
166
167
	/**
168
	 * @return string
169
	 */
170
	protected function convertToMiliseconds( $time, $decimals = 2 )
171
	{
172
		return number_format( $time * 1000, $decimals );
173
	}
174
175
	/**
176
	 * @return array
177
	 */
178
	protected function getErrors()
179
	{
180
		$errors = array();
181
		foreach( $this->errors as $error ) {
182
			if( $error['errno'] == E_WARNING ) {
183
				$error['name'] = '<span class="glbb-error">'.$error['name'].'</span>';
184
			}
185
			if( $error['count'] > 1 ) {
186
				$error['name'] .= ' ('.$error['count'].')';
187
			}
188
			$errors[] = array(
189
				'name' => $error['name'],
190
				'message' => sprintf( __( '%s on line %s in file %s', 'blackbar' ),
191
					$error['message'],
192
					$error['line'],
193
					$error['file']
194
				),
195
			);
196
		}
197
		return $errors;
198
	}
199
200
	/**
201
	 * @return string
202
	 */
203
	protected function getErrorsLabel()
204
	{
205
		$warningCount = 0;
206
		foreach( $this->errors as $error ) {
207
			if( $error['errno'] == E_WARNING ) {
208
				$warningCount++;
209
			}
210
		}
211
		$errorCount = count( $this->errors );
212
		$warnings = $warningCount > 0 ? sprintf( ', %d!', $warningCount ) : '';
213
		return sprintf( __( 'Errors (%d%s)', 'blackbar' ), $errorCount, $warnings );
214
	}
215
216
	/**
217
	 * @return string
218
	 */
219
	protected function getProfilerLabel()
220
	{
221
		$profilerTime = $this->convertToMiliseconds( $this->profiler->getTotalTime(), 0 );
222
		return sprintf( __( 'Profiler (%s ms)', 'blackbar' ), $profilerTime );
223
	}
224
225
	/**
226
	 * @return array
227
	 */
228
	protected function getQueries()
229
	{
230
		global $wpdb;
231
		$queries = array();
232
		$search = array(
233
			'AND',
234
			'FROM',
235
			'GROUP BY',
236
			'INNER JOIN',
237
			'LIMIT',
238
			'ON DUPLICATE KEY UPDATE',
239
			'ORDER BY',
240
			'SET',
241
			'WHERE',
242
		);
243
		$replace = array_map( function( $value ) {
244
			return PHP_EOL.$value;
245
		}, $search );
246
		foreach( $wpdb->queries as $query ) {
247
			$miliseconds = number_format( round( $query[1] * 1000, 4 ), 4 );
248
			$sql = preg_replace( '/\s\s+/', ' ', trim( $query[0] ));
249
			$sql = str_replace( PHP_EOL, ' ', $sql );
250
			$sql = str_replace( $search, $replace, $sql );
251
			$queries[] = array(
252
				'ms' => $miliseconds,
253
				'sql' => $sql,
254
			);
255
		}
256
		return $queries;
257
	}
258
259
	/**
260
	 * @return string
261
	 */
262
	protected function getQueriesLabel()
263
	{
264
		global $wpdb;
265
		$queryTime = 0;
266
		foreach( $wpdb->queries as $query ) {
267
			$queryTime += $query[1];
268
		}
269
		$queriesCount = '<span class="glbb-queries-count">'.count( $wpdb->queries ).'</span>';
270
		$queriesTime = '<span class="glbb-queries-time">'.$this->convertToMiliseconds( $queryTime ).'</span>';
271
		return sprintf( __( 'SQL (%s queries in %s ms)', 'blackbar' ), $queriesCount, $queriesTime );
272
	}
273
274
	/**
275
	 * @param string $file
276
	 * @return string
277
	 */
278
	protected function path( $file = '' )
279
	{
280
		return plugin_dir_path( $this->file ).ltrim( trim( $file ), '/' );
281
	}
282
283
	/**
284
	 * @param string $path
285
	 * @return string
286
	 */
287
	protected function url( $path = '' )
288
	{
289
		return esc_url( plugin_dir_url( $this->file ) . ltrim( trim( $path ), '/' ));
290
	}
291
}
292