Completed
Push — master ( 9bf2f8...66ae6f )
by Harro
10:12
created

Error   B

Complexity

Total Complexity 43

Size/Duplication

Total Lines 311
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 0%

Importance

Changes 15
Bugs 5 Features 3
Metric Value
wmc 43
c 15
b 5
f 3
lcom 1
cbo 4
dl 0
loc 311
ccs 0
cts 0
cp 0
rs 8.3157

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 20 3
A handler() 0 4 1
A commandlineHandler() 0 3 1
A ajaxCallHandler() 0 3 1
D interactiveHandler() 0 175 28
B getMessages() 0 26 5
A setMessage() 0 17 4

How to fix   Complexity   

Complex Class

Complex classes like Error often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Error, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @package    Fuel\Foundation
4
 * @version    2.0
5
 * @author     Fuel Development Team
6
 * @license    MIT License
7
 * @copyright  2010 - 2014 Fuel Development Team
8
 * @link       http://fuelphp.com
9
 */
10
11
namespace Fuel\Foundation;
12
13
use Whoops\Run;
14
use Whoops\Handler\PrettyPageHandler;
15
use Whoops\Handler\JsonResponseHandler;
16
use Fuel\Foundation\Whoops\ProductionHandler;
17
18
/**
19
 * Error class, implements the Whoops error handler
20
 *
21
 * @package  Fuel\Foundation
22
 *
23
 * @since  2.0.0
24
 */
25
class Error
26
{
27
	/**
28
	 * @var  Whoops\Run  the Whoops error handler instance
29
	 */
30
	protected $whoops;
31
32
	/**
33
	 * @var  Whoops\Handler\PrettyPageHandler  the current page handler
34
	 */
35
	protected $pagehandler;
36
37
	/**
38
	 * Initialization, set the Error handler
39
	 *
40
	 * @since  2.0.0
41
	 */
42
	public function __construct()
43
	{
44
		// are we in a CLi environment?
45
		if ((bool) defined('STDIN'))
46
		{
47
			$this->commandlineHandler();
48
		}
49
50
		// is this an ajax call?
51
		elseif(false)
52
		{
53
			$this->ajaxCallHandler();
54
		}
55
56
		// load the default interactive error handler
57
		else
58
		{
59
			$this->interactiveHandler();
60
		}
61
	}
62
63
	/**
64
	 * Load the correct file with translations, based on the locale passed
65
	 *
66
	 * @return  Whoops\Handler\PrettyPageHandler
67
	 *
68
	 * @since  2.0.0
69
	 */
70
	public function handler()
71
	{
72
		return $this->pagehandler;
73
	}
74
75
	/**
76
	 * Error handler for when the framework is used in CLi environments
77
	 *
78
	 * @since  2.0.0
79
	 */
80
	protected function commandlineHandler()
81
	{
82
	}
83
84
	/**
85
	 * Error handler for when the framework is used in Ajax environments
86
	 *
87
	 * @since  2.0.0
88
	 */
89
	protected function ajaxCallHandler()
90
	{
91
	}
92
93
	/**
94
	 * Error handler for when the framework is used in Web environments
95
	 *
96
	 * @since  2.0.0
97
	 */
98
	protected function interactiveHandler()
99
	{
100
		// use the framework default Whoops error handler
101
		$this->whoops = new Run;
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Whoops\Run() of type object<Whoops\Run> is incompatible with the declared type object<Fuel\Foundation\Whoops\Run> of property $whoops.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
102
103
		$this->whoops->writeToOutput(false);
104
		$this->whoops->allowQuit(false);
105
106
		// define the default page handler
107
		$this->pagehandler = new PrettyPageHandler;
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Whoops\Handler\PrettyPageHandler() of type object<Whoops\Handler\PrettyPageHandler> is incompatible with the declared type object<Fuel\Foundation\W...dler\PrettyPageHandler> of property $pagehandler.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
108
		$this->pagehandler->addResourcePath(__DIR__.DS.'Whoops'.DS.'resources');
109
110
		$this->pagehandler->addDataTableCallback('Application', function()
111
		{
112
			$application = \Application::getInstance();
113
			$environment = $application->getEnvironment();
114
			$request     = \Request::getInstance();
115
			$route = $request ? $request->getRoute() : null;
116
117
			return array(
118
				'Active application'    => $application ? $application->getName() : '',
119
				'Application namespace' => $route ? rtrim($route->namespace, '\\') : '',
120
 				'Environment'           => $environment ? $environment->getName() : '',
121
			);
122
		});
123
124
		$this->pagehandler->addDataTableCallback('Current Request', function()
125
		{
126
			$request = \Request::getInstance();
127
			$route = $request ? $request->getRoute() : null;
128
			$controller = $route ? $route->controller : '';
129
			$parameters = $route ? $route->parameters : array();
130
			array_shift($parameters);
131
132
			return array(
133
				'Original URI'          => $route ? $route->uri : '',
134
				'Mapped URI'            => $route ? $route->translation : '',
135
				'Controller'            => $controller,
136
				'Action'                => $controller ? ('action'.$route->action) : '',
137
				'HTTP Method'           => $request ? $request->getInput()->getMethod() : '',
138
				'Parameters'            => $parameters,
139
			);
140
		});
141
142
		$this->pagehandler->addDataTableCallback('Request Parameters', function()
143
		{
144
			$request = \Request::getInstance();
145
			return $request ? $request->getInput()->getParam()->getContents() : '';
146
		});
147
148
		$this->pagehandler->addDataTableCallback('Permanent Session Data', function()
149
		{
150
			if ($application = \Application::getInstance())
151
			{
152
				if ($session = $application->getSession())
153
				{
154
					return $session->getContents();
155
				}
156
			}
157
			return 'no session active';
158
		});
159
160
		$this->pagehandler->addDataTableCallback('Flash Session Data', function()
161
		{
162
			if ($application = \Application::getInstance())
163
			{
164
				if ($session = $application->getSession())
165
				{
166
					return $session->get('flash');
167
				}
168
			}
169
			return 'no session active';
170
		});
171
172
		$this->pagehandler->addDataTableCallback('Defined Cookies', function()
173
		{
174
			$result = array();
175
			if ($input = \Input::getInstance())
176
			{
177
				foreach ($input->getCookie() as $cookie)
178
				{
179
					$result[$cookie->getName()] = $cookie->getValue();
180
					if ($cookie->isDeleted())
181
					{
182
						$result[$cookie->getName()] .= '; State=Deleted';
183
					}
184
					else
185
					{
186
						$result[$cookie->getName()] .= '; State='.($cookie->isNew() ? 'New' : 'Request');
187
					}
188
				}
189
			}
190
			return $result;
191
		});
192
193
		$this->pagehandler->addDataTableCallback('Uploaded Files', function()
194
		{
195
			$result = array();
196
			if ($input = \Input::getInstance())
197
			{
198
				foreach ($input->getFile() as $file)
199
				{
200
					$result[] = $file;
201
				}
202
			}
203
			return $result;
204
		});
205
206
		$this->pagehandler->addDataTableCallback('Server Data', function()
207
		{
208
			return $_SERVER;
209
		});
210
211
		$this->whoops->pushHandler($this->pagehandler);
0 ignored issues
show
Documentation introduced by
$this->pagehandler is of type object<Whoops\Handler\PrettyPageHandler>, but the function expects a callable.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
212
213
		// next on the stack goes the JSON handler, to deal with AJAX reqqests
214
		$jsonHandler = new JsonResponseHandler;
215
		$jsonHandler->onlyForAjaxRequests(true);
216
		// $jsonHandler->addTraceToOutput(true);
217
218
		$this->whoops->pushHandler($jsonHandler);
0 ignored issues
show
Documentation introduced by
$jsonHandler is of type object<Whoops\Handler\JsonResponseHandler>, but the function expects a callable.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
219
220
		// add the Fuel production handler
221
		$productionHandler = new ProductionHandler;
222
		$this->whoops->pushHandler($productionHandler);
0 ignored issues
show
Documentation introduced by
$productionHandler is of type object<Fuel\Foundation\Whoops\ProductionHandler>, but the function expects a callable.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
223
224
		// activate the error handler
225
		$this->whoops->register();
226
227
		// set a custom handler, so we can deal with translations
228
		$current_handler = set_exception_handler(function($e) use(&$current_handler)
0 ignored issues
show
Unused Code introduced by
$current_handler is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
229
		{
230
			// get the locale
231
			if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')
232
			{
233
				// if the locale is set to C, default to English
234
				if (($locale = getenv('LC_ALL')) === 'C')
235
				{
236
					$locale = 'English';
237
				}
238
			}
239
			else
240
			{
241
				// if the locale is set to C, default to en_US
242
				if (($locale = setlocale(LC_MESSAGES, null)) === 'C')
243
				{
244
					$locale = 'en_US';
245
				}
246
			}
247
248
			// get access to the exception's error message
249
			$reflection = new \ReflectionClass($e);
250
			$property = $reflection->getProperty("message");
251
			$property->setAccessible(true);
252
253
			// get the translations for the current locale
254
			if ($translations = $this->getMessages($locale, true))
255
			{
256
				// does the error message exist?
257
				$messageId = substr($e->getMessage(), 0,7);
258
				if (isset($translations[$messageId]))
259
				{
260
					// swap the original message for the translated one
261
					$property->setValue($e, $this->setMessage($translations[$messageId], $e->getMessage()));
262
				}
263
			}
264
265
			// call the original error handler with the translated exception message
266
			$result = call_user_func($current_handler, $e);
267
268
			// re-enable output buffering, then send the response for the handlers out
269
			ob_start();
270
			echo $result;
271
		});
272
	}
273
274
	/**
275
	 * Load the correct file with translations, based on the locale passed
276
	 *
277
	 * @return  mixed  array of message translations, or false if none are found
278
	 *
279
	 * @since  2.0.0
280
	 */
281
	protected function getMessages($locale, $shorten = false)
282
	{
283
		$baseDir = realpath(__DIR__.DS.'..'.DS.'translations');
284
285
		$lookup = array($locale);
286
		if ($shorten)
287
		{
288
			$lookup[] = substr($locale, 0, 2);
289
		}
290
291
		foreach($lookup as $lang)
292
		{
293
			if (is_file($lang = $baseDir.DS.$lang.'.php'))
294
			{
295
				$translations = include $lang;
296
				if (is_string($translations))
297
				{
298
					return $this->getMessages($translations);
299
				}
300
				return $translations;
301
			}
302
		}
303
304
		// nothing found
305
		return false;
306
	}
307
308
	/**
309
	 * Convert the original message to the translated message
310
	 *
311
	 * @param  string  $translation  message in the current locale
312
	 * @param  string  $original     original error message
313
	 *
314
	 * @return  string  translated error message
315
	 *
316
	 * @since  2.0.0
317
	 */
318
	protected function setMessage($translation, $original)
319
	{
320
		// strip any parameters from the original message and unify the message for translation
321
		if (preg_match_all('~\[(.*?)\]~', $original, $matches) and ! empty($matches[1]))
322
		{
323
			$params = $matches[1];
324
			$message = preg_replace_callback('~\[(.*?)\]~', function($matches) { static $c = 0; return '"%'.(++$c).'$s"'; }, $original);
0 ignored issues
show
Unused Code introduced by
$message is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
Unused Code introduced by
The parameter $matches is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
325
		}
326
327
		// put the parameters back in if needed
328
		if ( ! empty($params))
329
		{
330
			$translation = vsprintf($translation, $params);
331
		}
332
333
		return $translation;
334
	}
335
}
336