Passed
Push — master ( 54186f...17f01a )
by Alexander
03:09
created
src/components/Debug/Exceptions/Handlers/PleasingPageHandler.php 1 patch
Indentation   +511 added lines, -511 removed lines patch added patch discarded remove patch
@@ -39,535 +39,535 @@
 block discarded – undo
39 39
  */
40 40
 class PleasingPageHandler extends Handler
41 41
 {
42
-	/**
43
-	 * The brand main of handler.
44
-	 * 
45
-	 * @var string $brand
46
-	 */
47
-	protected $brand = 'Lenevor Debug';
48
-
49
-	/**
50
-	 * A string identifier for a known IDE/text editor, or a closure
51
-	 * that resolves a string that can be used to open a given file
52
-	 * in an editor.
53
-	 * 
54
-	 * @var mixed $editor
55
-	 */
56
-	protected $editor;
57
-
58
-	/**
59
-	 * A list of known editor strings.
60
-	 * 
61
-	 * @var array $editors
62
-	 */
63
-	protected $editors = [
64
-		"vscode"   => "vscode://file/%file:%line",
65
-		"netbeans" => "netbeans://open/?f=%file:%line",
66
-		"idea"     => "idea://open?file=%file&line=%line",
67
-		"sublime"  => "subl://open?url=file://%file&line=%line",
68
-		"phpstorm" => "phpstorm://open?file://%file&line=%line",
69
-		"textmate" => "txmt://open?url=file://%file&line=%line",
70
-		"emacs"    => "emacs://open?url=file://%file&line=%line",
42
+    /**
43
+     * The brand main of handler.
44
+     * 
45
+     * @var string $brand
46
+     */
47
+    protected $brand = 'Lenevor Debug';
48
+
49
+    /**
50
+     * A string identifier for a known IDE/text editor, or a closure
51
+     * that resolves a string that can be used to open a given file
52
+     * in an editor.
53
+     * 
54
+     * @var mixed $editor
55
+     */
56
+    protected $editor;
57
+
58
+    /**
59
+     * A list of known editor strings.
60
+     * 
61
+     * @var array $editors
62
+     */
63
+    protected $editors = [
64
+        "vscode"   => "vscode://file/%file:%line",
65
+        "netbeans" => "netbeans://open/?f=%file:%line",
66
+        "idea"     => "idea://open?file=%file&line=%line",
67
+        "sublime"  => "subl://open?url=file://%file&line=%line",
68
+        "phpstorm" => "phpstorm://open?file://%file&line=%line",
69
+        "textmate" => "txmt://open?url=file://%file&line=%line",
70
+        "emacs"    => "emacs://open?url=file://%file&line=%line",
71 71
         "macvim"   => "mvim://open/?url=file://%file&line=%line",
72
-		"atom"     => "atom://core/open/file?filename=%file&line=%line",
73
-	];
72
+        "atom"     => "atom://core/open/file?filename=%file&line=%line",
73
+    ];
74 74
 	
75
-	/**
76
-	 * The page title main of handler.
77
-	 * 
78
-	 * @var string $pageTitle
79
-	 */
80
-	protected $pageTitle = 'Lenevor Debug! There was an error';
75
+    /**
76
+     * The page title main of handler.
77
+     * 
78
+     * @var string $pageTitle
79
+     */
80
+    protected $pageTitle = 'Lenevor Debug! There was an error';
81 81
 	
82
-	/**
83
-	 * Fast lookup cache for known resource locations.
84
-	 * 
85
-	 * @var array $resourceCache
86
-	 */
87
-	protected $resourceCache = [];
82
+    /**
83
+     * Fast lookup cache for known resource locations.
84
+     * 
85
+     * @var array $resourceCache
86
+     */
87
+    protected $resourceCache = [];
88 88
 	
89
-	/**
90
-	 * The path to the directory containing the html error template directories.
91
-	 * 
92
-	 * @var array $searchPaths
93
-	 */
94
-	protected $searchPaths = [];
95
-
96
-	/**
97
-	 * Gets the table of data.
98
-	 * 
99
-	 * @var array $tables
100
-	 */
101
-	protected $tables = [];
102
-
103
-	/**
104
-	 * Gets the theme default.
105
-	 * 
106
-	 * @var string $theme
107
-	 */
108
-	protected $theme;
89
+    /**
90
+     * The path to the directory containing the html error template directories.
91
+     * 
92
+     * @var array $searchPaths
93
+     */
94
+    protected $searchPaths = [];
95
+
96
+    /**
97
+     * Gets the table of data.
98
+     * 
99
+     * @var array $tables
100
+     */
101
+    protected $tables = [];
102
+
103
+    /**
104
+     * Gets the theme default.
105
+     * 
106
+     * @var string $theme
107
+     */
108
+    protected $theme;
109 109
 	
110
-	/**
111
-	 * The template handler system.
112
-	 * 
113
-	 * @var string|object $template
114
-	 */
115
-	protected $template;	
110
+    /**
111
+     * The template handler system.
112
+     * 
113
+     * @var string|object $template
114
+     */
115
+    protected $template;	
116 116
 	
117
-	/**
118
-	 * Constructor. The PleasingPageHandler class.
119
-	 * 
120
-	 * @return void
121
-	 */
122
-	public function __construct()
123
-	{
124
-		$this->template      = new TemplateHandler;
125
-		$this->searchPaths[] = dirname(dirname(__DIR__)).DIRECTORY_SEPARATOR.'Resources';
126
-	}
127
-
128
-	/**
129
-	 * Adds an editor resolver, identified by a string name, and that may be a 
130
-	 * string path, or a callable resolver.
131
-	 * 
132
-	 * @param  string            $identifier
133
-	 * @param  string|\Callable  $resolver
134
-	 * 
135
-	 * @return void
136
-	 */
137
-	public function addEditor($identifier, $resolver): void
138
-	{
139
-		$this->editors[$identifier] = $resolver;
140
-	}
141
-
142
-	/**
143
-	 * Adds an entry to the list of tables displayed in the template.
144
-	 * The expected data is a simple associative array. Any nested arrays
145
-	 * will be flattened with print_r.
146
-	 * 
147
-	 * @param  \Syscodes\Components\Contracts\Debug\Table  $table
148
-	 * 
149
-	 * @return void
150
-	 */
151
-	public function addTables(Table $table): void
152
-	{
153
-		$this->tables[] = $table;
154
-	}
117
+    /**
118
+     * Constructor. The PleasingPageHandler class.
119
+     * 
120
+     * @return void
121
+     */
122
+    public function __construct()
123
+    {
124
+        $this->template      = new TemplateHandler;
125
+        $this->searchPaths[] = dirname(dirname(__DIR__)).DIRECTORY_SEPARATOR.'Resources';
126
+    }
127
+
128
+    /**
129
+     * Adds an editor resolver, identified by a string name, and that may be a 
130
+     * string path, or a callable resolver.
131
+     * 
132
+     * @param  string            $identifier
133
+     * @param  string|\Callable  $resolver
134
+     * 
135
+     * @return void
136
+     */
137
+    public function addEditor($identifier, $resolver): void
138
+    {
139
+        $this->editors[$identifier] = $resolver;
140
+    }
141
+
142
+    /**
143
+     * Adds an entry to the list of tables displayed in the template.
144
+     * The expected data is a simple associative array. Any nested arrays
145
+     * will be flattened with print_r.
146
+     * 
147
+     * @param  \Syscodes\Components\Contracts\Debug\Table  $table
148
+     * 
149
+     * @return void
150
+     */
151
+    public function addTables(Table $table): void
152
+    {
153
+        $this->tables[] = $table;
154
+    }
155 155
 	
156
-	/**
157
-	 * Gathers the variables that will be made available to the view.
158
-	 * 
159
-	 * @return  array
160
-	 */
161
-	protected function collectionVars(): array
162
-	{
163
-		$supervisor = $this->getSupervisor();
164
-		$style      = file_get_contents($this->getResource('compiled/css/debug.base.css'));
165
-		$jscript    = file_get_contents($this->getResource('compiled/js/debug.base.js'));
166
-		$servers    = array_merge($this->getDefaultServers(), $this->tables);
167
-		$routing    = array_merge($this->getDefaultRouting(), $this->tables);
168
-		$databases  = array_merge($this->getDefaultDatabase(), $this->tables);
169
-		$context    = array_merge($this->getDefaultContext(), $this->tables);
156
+    /**
157
+     * Gathers the variables that will be made available to the view.
158
+     * 
159
+     * @return  array
160
+     */
161
+    protected function collectionVars(): array
162
+    {
163
+        $supervisor = $this->getSupervisor();
164
+        $style      = file_get_contents($this->getResource('compiled/css/debug.base.css'));
165
+        $jscript    = file_get_contents($this->getResource('compiled/js/debug.base.js'));
166
+        $servers    = array_merge($this->getDefaultServers(), $this->tables);
167
+        $routing    = array_merge($this->getDefaultRouting(), $this->tables);
168
+        $databases  = array_merge($this->getDefaultDatabase(), $this->tables);
169
+        $context    = array_merge($this->getDefaultContext(), $this->tables);
170 170
 		
171
-		return [ 
172
-			'class' => explode('\\', $supervisor->getExceptionName()),
173
-			'stylesheet' => preg_replace('#[\r\n\t ]+#', ' ', $style),
174
-			'javascript' => preg_replace('#[\r\n\t ]+#', ' ', $jscript),
175
-			'header' => $this->getResource('views/partials/updown/header.php'),
176
-			'footer' => $this->getResource('views/partials/updown/footer.php'),
177
-			'info_exception' => $this->getResource('views/partials/info/info_exception.php'),
178
-			'section_stack_exception' => $this->getResource('views/partials/section_stack_exception.php'),
179
-			'section_frame' => $this->getResource('views/partials/section_frame.php'),
180
-			'frame_description' => $this->getResource('views/partials/frames/frame_description.php'),
181
-			'frame_list' => $this->getResource('views/partials/frames/frame_list.php'),
182
-			'section_code' => $this->getResource('views/partials/section_code.php'),
183
-			'code_source' => $this->getResource('views/partials/codes/code_source.php'),
184
-			'request_info' => $this->getResource('views/partials/request_info.php'),
185
-			'navigation' => $this->getResource('views/components/navBar.php'),
186
-			'settings' => $this->getResource('views/components/settingsDropdown.php'),
187
-			'section_detail_context' => $this->getResource('views/partials/details/section_detail_context.php'),
188
-			'plain_exception' => Formatter::formatExceptionAsPlainText($this->getSupervisor()),
189
-			'handler' => $this,
190
-			'handlers' => $this->getDebug()->getHandlers(),
191
-			'debug' => $this->getDebug(),
192
-			'code' => $this->getExceptionCode(),
193
-			'message' => $supervisor->getExceptionMessage(),
194
-			'frames' => $this->getExceptionFrames(),
195
-			'servers' => $this->getProcessTables($servers),
196
-			'routes' => $this->getProcessTables($routing),
197
-			'databases' => $this->getProcessTables($databases),
198
-			'contexts' => $this->getProcessTables($context),
199
-		];
200
-	}
171
+        return [ 
172
+            'class' => explode('\\', $supervisor->getExceptionName()),
173
+            'stylesheet' => preg_replace('#[\r\n\t ]+#', ' ', $style),
174
+            'javascript' => preg_replace('#[\r\n\t ]+#', ' ', $jscript),
175
+            'header' => $this->getResource('views/partials/updown/header.php'),
176
+            'footer' => $this->getResource('views/partials/updown/footer.php'),
177
+            'info_exception' => $this->getResource('views/partials/info/info_exception.php'),
178
+            'section_stack_exception' => $this->getResource('views/partials/section_stack_exception.php'),
179
+            'section_frame' => $this->getResource('views/partials/section_frame.php'),
180
+            'frame_description' => $this->getResource('views/partials/frames/frame_description.php'),
181
+            'frame_list' => $this->getResource('views/partials/frames/frame_list.php'),
182
+            'section_code' => $this->getResource('views/partials/section_code.php'),
183
+            'code_source' => $this->getResource('views/partials/codes/code_source.php'),
184
+            'request_info' => $this->getResource('views/partials/request_info.php'),
185
+            'navigation' => $this->getResource('views/components/navBar.php'),
186
+            'settings' => $this->getResource('views/components/settingsDropdown.php'),
187
+            'section_detail_context' => $this->getResource('views/partials/details/section_detail_context.php'),
188
+            'plain_exception' => Formatter::formatExceptionAsPlainText($this->getSupervisor()),
189
+            'handler' => $this,
190
+            'handlers' => $this->getDebug()->getHandlers(),
191
+            'debug' => $this->getDebug(),
192
+            'code' => $this->getExceptionCode(),
193
+            'message' => $supervisor->getExceptionMessage(),
194
+            'frames' => $this->getExceptionFrames(),
195
+            'servers' => $this->getProcessTables($servers),
196
+            'routes' => $this->getProcessTables($routing),
197
+            'databases' => $this->getProcessTables($databases),
198
+            'contexts' => $this->getProcessTables($context),
199
+        ];
200
+    }
201 201
 	
202
-	/**
203
-	 * The way in which the data sender (usually the server) can tell the recipient
204
-	 * (the browser, in general) what type of data is being sent in this case, html format tagged.
205
-	 * 
206
-	 * @return string
207
-	 */
208
-	public function contentType(): string
209
-	{
210
-		return 'text/html;charset=UTF-8';
211
-	}
212
-
213
-	/**
214
-	 * Gets the brand of project.
215
-	 * 
216
-	 * @return string
217
-	 */
218
-	public function getBrand(): string
219
-	{
220
-		return $this->brand;
221
-	}
222
-
223
-	/**
224
-	 * Returns the default servers.
225
-	 * 
226
-	 * @return \Syscodes\Components\Contracts\Debug\Table[]
227
-	 */
228
-	protected function getDefaultServers()
229
-	{
230
-		$server = [
231
-			'host' => $_SERVER['HTTP_HOST'], 
232
-			'user-agent' => $_SERVER['HTTP_USER_AGENT'], 
233
-			'accept' => $_SERVER['HTTP_ACCEPT'], 
234
-			'accept-language' => $_SERVER['HTTP_ACCEPT_LANGUAGE'], 
235
-			'accept-encoding' => $_SERVER['HTTP_ACCEPT_ENCODING'],
236
-			'connection' => $_SERVER['HTTP_CONNECTION'],
237
-			'upgrade-insecure-requests' => $_SERVER['HTTP_UPGRADE_INSECURE_REQUESTS'], 
238
-			'sec-fetch-dest' => $_SERVER['HTTP_SEC_FETCH_DEST'],
239
-			'sec-fetch-mode' => $_SERVER['HTTP_SEC_FETCH_MODE'],
240
-			'sec-fetch-site' => $_SERVER['HTTP_SEC_FETCH_SITE'],
241
-			'sec-fetch-user' => $_SERVER['HTTP_SEC_FETCH_USER'],
242
-		];
243
-
244
-		return [new ArrayTable($server)];
245
-	}
246
-
247
-	/**
248
-	 * Returns the default routing.
249
-	 * 
250
-	 * @return \Syscodes\Components\Contracts\Debug\Table[]
251
-	 */
252
-	protected function getDefaultRouting()
253
-	{
254
-		$action = 'Closure' ?? app('request')->route()->parseControllerCallback()[0];
255
-
256
-		$index = match (true) {
257
-			array_key_exists('web', app('router')->getMiddlewareGroups()) => 0,
258
-			array_key_exists('api', app('router')->getMiddlewareGroups()) => 1,
259
-		};
260
-
261
-		$routing = [
262
-			'Controller' => $action,
263
-			'Middleware' => array_keys(app('router')->getMiddlewareGroups())[$index],
264
-		];
265
-
266
-		return [new ArrayTable($routing)];
267
-	}
268
-
269
-	/**
270
-	 * Returns the default database.
271
-	 * 
272
-	 * @return \Syscodes\Components\Contracts\Debug\Table[]
273
-	 */
274
-	protected function getDefaultDatabase()
275
-	{
276
-		$query = [
277
-			'Sql' => null,
278
-			'Time' => null,
279
-			'Connection name' => null,
280
-		];
281
-
282
-		return [new ArrayTable($query)];
283
-	}
284
-
285
-	/**
286
-	 * Returns the default context data.
287
-	 * 
288
-	 * @return \Syscodes\Components\Contracts\Debug\Table[]
289
-	 */
290
-	protected function getDefaultContext()
291
-	{
292
-		$context = [
293
-			'Php Version' => PHP_VERSION,
294
-			'Lenevor Version' => app()->version(),
295
-			'Lenevor Locale' => config('app.locale'),
296
-			'App Debug' => (1 == env('APP_DEBUG') ? 'true' : 'false'),
297
-			'App Env' => env('APP_ENV'),
298
-		];
299
-
300
-		return [new ArrayTable($context)];
301
-	}
302
-
303
-	/**
304
-	 * Get the code of the exception that is currently being handled.
305
-	 * 
306
-	 * @return string
307
-	 */
308
-	protected function getExceptionCode()
309
-	{
310
-		$exception = $this->getException();
311
-		$code      = $exception->getCode();
312
-
313
-		if ($exception instanceof ErrorException) {
314
-			$code = Misc::translateErrorCode($exception->getSeverity());
315
-		}
316
-
317
-		return (string) $code;
318
-	}
319
-
320
-	/**
321
-	 * Get the stack trace frames of the exception that is currently being handled.
322
-	 * 
323
-	 * @return \Syscodes\Components\Debug\Engine\Supervisor;
324
-	 */
325
-	protected function getExceptionFrames()
326
-	{
327
-		$frames = $this->getSupervisor()->getFrames();
202
+    /**
203
+     * The way in which the data sender (usually the server) can tell the recipient
204
+     * (the browser, in general) what type of data is being sent in this case, html format tagged.
205
+     * 
206
+     * @return string
207
+     */
208
+    public function contentType(): string
209
+    {
210
+        return 'text/html;charset=UTF-8';
211
+    }
212
+
213
+    /**
214
+     * Gets the brand of project.
215
+     * 
216
+     * @return string
217
+     */
218
+    public function getBrand(): string
219
+    {
220
+        return $this->brand;
221
+    }
222
+
223
+    /**
224
+     * Returns the default servers.
225
+     * 
226
+     * @return \Syscodes\Components\Contracts\Debug\Table[]
227
+     */
228
+    protected function getDefaultServers()
229
+    {
230
+        $server = [
231
+            'host' => $_SERVER['HTTP_HOST'], 
232
+            'user-agent' => $_SERVER['HTTP_USER_AGENT'], 
233
+            'accept' => $_SERVER['HTTP_ACCEPT'], 
234
+            'accept-language' => $_SERVER['HTTP_ACCEPT_LANGUAGE'], 
235
+            'accept-encoding' => $_SERVER['HTTP_ACCEPT_ENCODING'],
236
+            'connection' => $_SERVER['HTTP_CONNECTION'],
237
+            'upgrade-insecure-requests' => $_SERVER['HTTP_UPGRADE_INSECURE_REQUESTS'], 
238
+            'sec-fetch-dest' => $_SERVER['HTTP_SEC_FETCH_DEST'],
239
+            'sec-fetch-mode' => $_SERVER['HTTP_SEC_FETCH_MODE'],
240
+            'sec-fetch-site' => $_SERVER['HTTP_SEC_FETCH_SITE'],
241
+            'sec-fetch-user' => $_SERVER['HTTP_SEC_FETCH_USER'],
242
+        ];
243
+
244
+        return [new ArrayTable($server)];
245
+    }
246
+
247
+    /**
248
+     * Returns the default routing.
249
+     * 
250
+     * @return \Syscodes\Components\Contracts\Debug\Table[]
251
+     */
252
+    protected function getDefaultRouting()
253
+    {
254
+        $action = 'Closure' ?? app('request')->route()->parseControllerCallback()[0];
255
+
256
+        $index = match (true) {
257
+            array_key_exists('web', app('router')->getMiddlewareGroups()) => 0,
258
+            array_key_exists('api', app('router')->getMiddlewareGroups()) => 1,
259
+        };
260
+
261
+        $routing = [
262
+            'Controller' => $action,
263
+            'Middleware' => array_keys(app('router')->getMiddlewareGroups())[$index],
264
+        ];
265
+
266
+        return [new ArrayTable($routing)];
267
+    }
268
+
269
+    /**
270
+     * Returns the default database.
271
+     * 
272
+     * @return \Syscodes\Components\Contracts\Debug\Table[]
273
+     */
274
+    protected function getDefaultDatabase()
275
+    {
276
+        $query = [
277
+            'Sql' => null,
278
+            'Time' => null,
279
+            'Connection name' => null,
280
+        ];
281
+
282
+        return [new ArrayTable($query)];
283
+    }
284
+
285
+    /**
286
+     * Returns the default context data.
287
+     * 
288
+     * @return \Syscodes\Components\Contracts\Debug\Table[]
289
+     */
290
+    protected function getDefaultContext()
291
+    {
292
+        $context = [
293
+            'Php Version' => PHP_VERSION,
294
+            'Lenevor Version' => app()->version(),
295
+            'Lenevor Locale' => config('app.locale'),
296
+            'App Debug' => (1 == env('APP_DEBUG') ? 'true' : 'false'),
297
+            'App Env' => env('APP_ENV'),
298
+        ];
299
+
300
+        return [new ArrayTable($context)];
301
+    }
302
+
303
+    /**
304
+     * Get the code of the exception that is currently being handled.
305
+     * 
306
+     * @return string
307
+     */
308
+    protected function getExceptionCode()
309
+    {
310
+        $exception = $this->getException();
311
+        $code      = $exception->getCode();
312
+
313
+        if ($exception instanceof ErrorException) {
314
+            $code = Misc::translateErrorCode($exception->getSeverity());
315
+        }
316
+
317
+        return (string) $code;
318
+    }
319
+
320
+    /**
321
+     * Get the stack trace frames of the exception that is currently being handled.
322
+     * 
323
+     * @return \Syscodes\Components\Debug\Engine\Supervisor;
324
+     */
325
+    protected function getExceptionFrames()
326
+    {
327
+        $frames = $this->getSupervisor()->getFrames();
328 328
 		
329
-		return $frames;
330
-	}
329
+        return $frames;
330
+    }
331 331
 	
332
-	/**
333
-	 * Gets the page title web.
334
-	 * 
335
-	 * @return string
336
-	 */
337
-	public function getPageTitle(): string
338
-	{
339
-		return $this->pageTitle;
340
-	}
341
-
342
-	/**
343
-	 * Processes an array of tables making sure everything is all right.
344
-	 * 
345
-	 * @param  \Syscodes\Components\Contracts\Debug\Table[]  $tables
346
-	 * 
347
-	 * @return array
348
-	 */
349
-	protected function getProcessTables(array $tables): array
350
-	{
351
-		$processTables = [];
352
-
353
-		foreach ($tables as $table) {
354
-			if ( ! $table instanceof Table) {
355
-				continue;
356
-			}
332
+    /**
333
+     * Gets the page title web.
334
+     * 
335
+     * @return string
336
+     */
337
+    public function getPageTitle(): string
338
+    {
339
+        return $this->pageTitle;
340
+    }
341
+
342
+    /**
343
+     * Processes an array of tables making sure everything is all right.
344
+     * 
345
+     * @param  \Syscodes\Components\Contracts\Debug\Table[]  $tables
346
+     * 
347
+     * @return array
348
+     */
349
+    protected function getProcessTables(array $tables): array
350
+    {
351
+        $processTables = [];
352
+
353
+        foreach ($tables as $table) {
354
+            if ( ! $table instanceof Table) {
355
+                continue;
356
+            }
357 357
 			
358
-			$label = $table->getLabel();
359
-
360
-			try {
361
-				$data = (array) $table->getData();
362
-
363
-				if ( ! (is_array($data) || $data instanceof Traversable)) {
364
-					$data = [];
365
-				}
366
-			} catch (Exception $e) {
367
-				$data = [];
368
-			}
369
-
370
-			$processTables[$label] = $data;
371
-		}
372
-
373
-		return $processTables;
374
-	}
375
-
376
-	/**
377
-	 * Finds a resource, by its relative path, in all available search paths.
378
-	 *
379
-	 * @param  string  $resource
380
-	 * 
381
-	 * @return string
382
-	 * 
383
-	 * @throws \RuntimeException
384
-	 */
385
-	protected function getResource($resource)
386
-	{
387
-		if (isset($this->resourceCache[$resource])) {
388
-			return $this->resourceCache[$resource];
389
-		}
390
-
391
-		foreach ($this->searchPaths as $path) {
392
-			$fullPath = $path.DIRECTORY_SEPARATOR.$resource;
393
-
394
-			if (is_file($fullPath)) {
395
-				// Cache:
396
-				$this->resourceCache[$resource] = $fullPath;
397
-
398
-				return $fullPath;
399
-			}
400
-		}
401
-
402
-		throw new RuntimeException( 
403
-				"Could not find resource '{$resource}' in any resource paths.". 
404
-				"(searched: ".join(", ", $this->searchPaths).")");
405
-	}
358
+            $label = $table->getLabel();
359
+
360
+            try {
361
+                $data = (array) $table->getData();
362
+
363
+                if ( ! (is_array($data) || $data instanceof Traversable)) {
364
+                    $data = [];
365
+                }
366
+            } catch (Exception $e) {
367
+                $data = [];
368
+            }
369
+
370
+            $processTables[$label] = $data;
371
+        }
372
+
373
+        return $processTables;
374
+    }
375
+
376
+    /**
377
+     * Finds a resource, by its relative path, in all available search paths.
378
+     *
379
+     * @param  string  $resource
380
+     * 
381
+     * @return string
382
+     * 
383
+     * @throws \RuntimeException
384
+     */
385
+    protected function getResource($resource)
386
+    {
387
+        if (isset($this->resourceCache[$resource])) {
388
+            return $this->resourceCache[$resource];
389
+        }
390
+
391
+        foreach ($this->searchPaths as $path) {
392
+            $fullPath = $path.DIRECTORY_SEPARATOR.$resource;
393
+
394
+            if (is_file($fullPath)) {
395
+                // Cache:
396
+                $this->resourceCache[$resource] = $fullPath;
397
+
398
+                return $fullPath;
399
+            }
400
+        }
401
+
402
+        throw new RuntimeException( 
403
+                "Could not find resource '{$resource}' in any resource paths.". 
404
+                "(searched: ".join(", ", $this->searchPaths).")");
405
+    }
406 406
 	
407
-	/**
408
-	 * Given an exception and status code will display the error to the client.
409
-	 * 
410
-	 * @return int|null
411
-	 */
412
-	public function handle()
413
-	{	
414
-		$templatePath = $this->getResource('views/debug.layout.php');
415
-
416
-		$vars = $this->collectionVars();
407
+    /**
408
+     * Given an exception and status code will display the error to the client.
409
+     * 
410
+     * @return int|null
411
+     */
412
+    public function handle()
413
+    {	
414
+        $templatePath = $this->getResource('views/debug.layout.php');
415
+
416
+        $vars = $this->collectionVars();
417 417
 		
418
-		if (empty($vars['message'])) $vars['message'] = __('exception.noMessage');
418
+        if (empty($vars['message'])) $vars['message'] = __('exception.noMessage');
419 419
 		
420
-		$this->template->setVariables($vars);
421
-		$this->template->render($templatePath);
420
+        $this->template->setVariables($vars);
421
+        $this->template->render($templatePath);
422 422
 		
423
-		return Handler::QUIT;
424
-	}
425
-
426
-	/**
427
-	 * Set the editor to use to open referenced files, by a string identifier or callable
428
-	 * that will be executed for every file reference. Should return a string.
429
-	 * 
430
-	 * @example  $debug->setEditor(function($file, $line) { return "file:///{$file}"; });
431
-	 * @example  $debug->setEditor('vscode');
432
-	 * 
433
-	 * @param  string  $editor
434
-	 * 
435
-	 * @return void
436
-	 * 
437
-	 * @throws \InvalidArgumentException
438
-	 */
439
-	public function setEditor($editor)
440
-	{
441
-		if ( ! is_callable($editor) && ! isset($this->editors[$editor])) {
442
-			throw new InvalidArgumentException("Unknown editor identifier: [{$editor}]. Known editors: " .
443
-				implode(', ', array_keys($this->editors))
444
-			);
445
-		}
446
-
447
-		$this->editor = $editor;
448
-	}
449
-
450
-	/**
451
-	 * Given a string file path, and an integer file line,
452
-	 * executes the editor resolver and returns.
453
-	 * 
454
-	 * @param  string  $file
455
-	 * @param  int	   $line
456
-	 * 
457
-	 * @return string|bool
458
-	 * 
459
-	 * @throws \UnexpectedValueException
460
-	 */
461
-	public function getEditorAtHref($file, $line)
462
-	{
463
-		$editor = $this->getEditor($file, $line);
464
-
465
-		if (empty($editor))	{
466
-			return false;
467
-		}
468
-
469
-		if ( ! isset($editor['url']) || ! is_string($editor['url'])) {
470
-			throw new UnexpectedValueException(__METHOD__.'should always resolve to a string or a valid editor array');
471
-		}
472
-
473
-		$editor['url'] = str_replace("%file", rawurldecode($file), $editor['url']);
474
-		$editor['url'] = str_replace("%line", rawurldecode($line), $editor['url']);
475
-
476
-		return $editor['url'];
477
-	}
478
-
479
-	/**
480
-	 * The editor must be a valid callable function/closure.
481
-	 * 
482
-	 * @param  string  $file
483
-	 * @param  int	   $line
484
-	 * 
485
-	 * @return array
486
-	 */
487
-	protected function getEditor($file, $line): array
488
-	{
489
-		if ( ! $this->editor || ( ! is_string($this->editor) && ! is_callable($this->editor))) {
490
-			return [];
491
-		}
492
-
493
-		if (is_string($this->editor) && isset($this->editors[$this->editor]) && ! is_callable($this->editors[$this->editor])) {
494
-			return ['url' => $this->editors[$this->editor]];
495
-		}
496
-
497
-		if (is_callable($this->editor) || (isset($this->editors[$this->editor]) && is_callable($this->editors[$this->editor]))) {
498
-			if (is_callable($this->editor)) {
499
-				$callback = call_user_func($this->editor, $file, $line);
500
-			} else {
501
-				$callback = call_user_func($this->editors[$this->editor], $file, $line);
502
-			}
503
-
504
-			if (empty($callback)) {
505
-				return [];
506
-			}
507
-
508
-			if (is_string($callback)) {
509
-				return ['url' => $callback];
510
-			}
423
+        return Handler::QUIT;
424
+    }
425
+
426
+    /**
427
+     * Set the editor to use to open referenced files, by a string identifier or callable
428
+     * that will be executed for every file reference. Should return a string.
429
+     * 
430
+     * @example  $debug->setEditor(function($file, $line) { return "file:///{$file}"; });
431
+     * @example  $debug->setEditor('vscode');
432
+     * 
433
+     * @param  string  $editor
434
+     * 
435
+     * @return void
436
+     * 
437
+     * @throws \InvalidArgumentException
438
+     */
439
+    public function setEditor($editor)
440
+    {
441
+        if ( ! is_callable($editor) && ! isset($this->editors[$editor])) {
442
+            throw new InvalidArgumentException("Unknown editor identifier: [{$editor}]. Known editors: " .
443
+                implode(', ', array_keys($this->editors))
444
+            );
445
+        }
446
+
447
+        $this->editor = $editor;
448
+    }
449
+
450
+    /**
451
+     * Given a string file path, and an integer file line,
452
+     * executes the editor resolver and returns.
453
+     * 
454
+     * @param  string  $file
455
+     * @param  int	   $line
456
+     * 
457
+     * @return string|bool
458
+     * 
459
+     * @throws \UnexpectedValueException
460
+     */
461
+    public function getEditorAtHref($file, $line)
462
+    {
463
+        $editor = $this->getEditor($file, $line);
464
+
465
+        if (empty($editor))	{
466
+            return false;
467
+        }
468
+
469
+        if ( ! isset($editor['url']) || ! is_string($editor['url'])) {
470
+            throw new UnexpectedValueException(__METHOD__.'should always resolve to a string or a valid editor array');
471
+        }
472
+
473
+        $editor['url'] = str_replace("%file", rawurldecode($file), $editor['url']);
474
+        $editor['url'] = str_replace("%line", rawurldecode($line), $editor['url']);
475
+
476
+        return $editor['url'];
477
+    }
478
+
479
+    /**
480
+     * The editor must be a valid callable function/closure.
481
+     * 
482
+     * @param  string  $file
483
+     * @param  int	   $line
484
+     * 
485
+     * @return array
486
+     */
487
+    protected function getEditor($file, $line): array
488
+    {
489
+        if ( ! $this->editor || ( ! is_string($this->editor) && ! is_callable($this->editor))) {
490
+            return [];
491
+        }
492
+
493
+        if (is_string($this->editor) && isset($this->editors[$this->editor]) && ! is_callable($this->editors[$this->editor])) {
494
+            return ['url' => $this->editors[$this->editor]];
495
+        }
496
+
497
+        if (is_callable($this->editor) || (isset($this->editors[$this->editor]) && is_callable($this->editors[$this->editor]))) {
498
+            if (is_callable($this->editor)) {
499
+                $callback = call_user_func($this->editor, $file, $line);
500
+            } else {
501
+                $callback = call_user_func($this->editors[$this->editor], $file, $line);
502
+            }
503
+
504
+            if (empty($callback)) {
505
+                return [];
506
+            }
507
+
508
+            if (is_string($callback)) {
509
+                return ['url' => $callback];
510
+            }
511 511
 			
512
-			return ['url' => isset($callback['url']) ? $callback['url'] : $callback];
513
-		}
512
+            return ['url' => isset($callback['url']) ? $callback['url'] : $callback];
513
+        }
514 514
 		
515
-		return [];
516
-	}
517
-
518
-	/**
519
-	 * Registered the editor.
520
-	 * 
521
-	 * @return string
522
-	 */
523
-	public function getEditorcode(): string
524
-	{
525
-		return $this->editor;
526
-	}
527
-
528
-	/**
529
-	 * Get the theme default.
530
-	 * 
531
-	 * @return string
532
-	 */
533
-	public function getTheme(): string
534
-	{
535
-		return $this->theme = config('gdebug.theme');
536
-	}
515
+        return [];
516
+    }
517
+
518
+    /**
519
+     * Registered the editor.
520
+     * 
521
+     * @return string
522
+     */
523
+    public function getEditorcode(): string
524
+    {
525
+        return $this->editor;
526
+    }
527
+
528
+    /**
529
+     * Get the theme default.
530
+     * 
531
+     * @return string
532
+     */
533
+    public function getTheme(): string
534
+    {
535
+        return $this->theme = config('gdebug.theme');
536
+    }
537 537
 	
538
-	/**
539
-	 * Sets the brand of project.
540
-	 * 
541
-	 * @param  string  $brand
542
-	 * 
543
-	 * @return void
544
-	 */
545
-	public function setBrand(string $brand): void
546
-	{
547
-		$this->brand = (string) $brand;
548
-	}
538
+    /**
539
+     * Sets the brand of project.
540
+     * 
541
+     * @param  string  $brand
542
+     * 
543
+     * @return void
544
+     */
545
+    public function setBrand(string $brand): void
546
+    {
547
+        $this->brand = (string) $brand;
548
+    }
549 549
 	
550
-	/**
551
-	 * Sets the page title web.
552
-	 * 
553
-	 * @param  string  $title
554
-	 * 
555
-	 * @return void
556
-	 */
557
-	public function setPageTitle(string $title): void
558
-	{
559
-		$this->pageTitle = (string) $title;
560
-	}
561
-
562
-	/**
563
-	 * Set the theme manually.
564
-	 * 
565
-	 * @param  string  $theme
566
-	 * 
567
-	 * @return void
568
-	 */
569
-	public function setTheme(string $theme): void
570
-	{
571
-		$this->theme = (string) $theme;
572
-	}
550
+    /**
551
+     * Sets the page title web.
552
+     * 
553
+     * @param  string  $title
554
+     * 
555
+     * @return void
556
+     */
557
+    public function setPageTitle(string $title): void
558
+    {
559
+        $this->pageTitle = (string) $title;
560
+    }
561
+
562
+    /**
563
+     * Set the theme manually.
564
+     * 
565
+     * @param  string  $theme
566
+     * 
567
+     * @return void
568
+     */
569
+    public function setTheme(string $theme): void
570
+    {
571
+        $this->theme = (string) $theme;
572
+    }
573 573
 }
574 574
\ No newline at end of file
Please login to merge, or discard this patch.