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