Completed
Push — master ( 57eaac...84ae94 )
by Kenji
03:19 queued 12s
created

CIPHPUnitTestRequest::createAndCallController()   C

Complexity

Conditions 9
Paths 32

Size

Total Lines 58
Code Lines 24

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 58
rs 6.9928
cc 9
eloc 24
nc 32
nop 4

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Part of CI PHPUnit Test
4
 *
5
 * @author     Kenji Suzuki <https://github.com/kenjis>
6
 * @license    MIT License
7
 * @copyright  2015 Kenji Suzuki
8
 * @link       https://github.com/kenjis/ci-phpunit-test
9
 */
10
11
class CIPHPUnitTestRequest
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
12
{
13
	protected $testCase;
14
15
	/**
16
	 * @var CIPHPUnitTestSuperGlobal
17
	 */
18
	protected $superGlobal;
19
20
	/**
21
	 * @var CIPHPUnitTestRouter
22
	 */
23
	protected $router;
24
25
	/**
26
	 * @var callable[] callable called post controller constructor
27
	 */
28
	protected $callables = [];
29
	
30
	/**
31
	 * @var callable[] callable called pre controller constructor
32
	 */
33
	protected $callablePreConstructors = [];
34
35
	protected $enableHooks = false;
36
	
37
	/**
38
	 * @var CI_Hooks
39
	 */
40
	protected $hooks;
41
42
	public function __construct(PHPUnit_Framework_TestCase $testCase)
43
	{
44
		$this->testCase = $testCase;
45
		$this->superGlobal = new CIPHPUnitTestSuperGlobal();
46
		$this->router = new CIPHPUnitTestRouter();
47
	}
48
49
	/**
50
	 * Set HTTP request header
51
	 * 
52
	 * @param string $name  header name
53
	 * @param string $value value
54
	 */
55
	public function setHeader($name, $value)
56
	{
57
		$this->superGlobal->set_SERVER_HttpHeader($name, $value);
58
	}
59
60
	/**
61
	 * Set (and Reset) callable
62
	 * 
63
	 * @param callable $callable function to run after controller instantiation
64
	 */
65
	public function setCallable(callable $callable)
66
	{
67
		$this->callables = [];
68
		$this->callables[] = $callable;
69
	}
70
71
	/**
72
	 * Add callable
73
	 * 
74
	 * @param callable $callable function to run after controller instantiation
75
	 */
76
	public function addCallable(callable $callable)
77
	{
78
		$this->callables[] = $callable;
79
	}
80
81
	/**
82
	 * Set (and Reset) callable pre constructor
83
	 * 
84
	 * @param callable $callable function to run before controller instantiation
85
	 */
86
	public function setCallablePreConstructor(callable $callable)
87
	{
88
		$this->callablePreConstructors = [];
89
		$this->callablePreConstructors[] = $callable;
90
	}
91
92
	/**
93
	 * Add callable pre constructor
94
	 * 
95
	 * @param callable $callable function to run before controller instantiation
96
	 */
97
	public function addCallablePreConstructor(callable $callable)
98
	{
99
		$this->callablePreConstructors[] = $callable;
100
	}
101
102
	/**
103
	 * Enable Hooks for Controllres
104
	 * This enables only pre_controller, post_controller_constructor, post_controller
105
	 */
106
	public function enableHooks()
107
	{
108
		$this->enableHooks = true;
109
		$this->hooks =& load_class('Hooks', 'core');
110
	}
111
112
	/**
113
	 * Request to Controller
114
	 *
115
	 * @param string       $http_method HTTP method
116
	 * @param array|string $argv        array of controller,method,arg|uri
117
	 * @param array|string $params      POST params/GET params|raw_input_stream
118
	 */
119
	public function request($http_method, $argv, $params = [])
0 ignored issues
show
Coding Style introduced by
request uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
120
	{
121
		if (is_string($argv))
122
		{
123
			$argv = ltrim($argv, '/');
124
		}
125
126
		// Set super globals
127
		$_SERVER['REQUEST_METHOD'] = $http_method;
128
		$this->superGlobal->set_GET($argv, $params);
129
		$this->superGlobal->set_POST($params);
130
		$this->superGlobal->set_SERVER_REQUEST_URI($argv);
131
132
		try {
133
			if (is_array($argv))
134
			{
135
				return $this->callControllerMethod(
136
					$http_method, $argv, $params
137
				);
138
			}
139
			else
140
			{
141
				return $this->requestUri($http_method, $argv, $params);
142
			}
143
		}
144
		// redirect()
145
		catch (CIPHPUnitTestRedirectException $e)
146
		{
147
			if ($e->getCode() === 0)
148
			{
149
				set_status_header(200);
150
			}
151
			else
152
			{
153
				set_status_header($e->getCode());
154
			}
155
			$CI =& get_instance();
156
			$CI->output->_status['redirect'] = $e->getMessage();
157
		}
158
		// show_404()
159
		catch (CIPHPUnitTestShow404Exception $e)
160
		{
161
			$this->processError($e);
162
			return $e->getMessage();
163
		}
164
		// show_error()
165
		catch (CIPHPUnitTestShowErrorException $e)
166
		{
167
			$this->processError($e);
168
			return $e->getMessage();
169
		}
170
	}
171
172
	protected function processError(Exception $e)
173
	{
174
		set_status_header($e->getCode());
175
	}
176
177
	/**
178
	 * Call Controller Method
179
	 *
180
	 * @param string       $http_method    HTTP method
181
	 * @param array        $argv           controller, method [, arg1, ...]
182
	 * @param array|string $request_params POST params/GET params|raw_input_stream
183
	 */
184
	protected function callControllerMethod($http_method, $argv, $request_params)
0 ignored issues
show
Unused Code introduced by
The parameter $http_method 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...
Coding Style introduced by
callControllerMethod uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
185
	{
186
		$_SERVER['argv'] = array_merge(['index.php'], $argv);
187
188
		$class  = ucfirst($argv[0]);
189
		$method = $argv[1];
190
191
		// Remove controller and method
192
		array_shift($argv);
193
		array_shift($argv);
194
195
//		$request = [
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
196
//			'REQUEST_METHOD' => $_SERVER['REQUEST_METHOD'],
197
//			'class' => $class,
198
//			'method' => $method,
199
//			'params' => $argv,
200
//			'$_GET' => $_GET,
201
//			'$_POST' => $_POST,
202
//		];
203
//		var_dump($request, $_SERVER['argv']);
204
205
		// Reset CodeIgniter instance state
206
		reset_instance();
207
208
		$this->setRawInputStream($request_params);
209
210
		// 404 checking
211
		if (! class_exists($class) || ! method_exists($class, $method))
212
		{
213
			// If 404, CodeIgniter instance is not created yet. So create it here
214
			// Because we need CI->output->_status to store info
215
			$CI =& get_instance();
216
			if ($CI instanceof CIPHPUnitTestNullCodeIgniter)
217
			{
218
				CIPHPUnitTest::createCodeIgniterInstance();
219
			}
220
221
			show_404($class.'::'.$method . '() is not found');
222
		}
223
224
		$params = $argv;
225
226
		return $this->createAndCallController($class, $method, $params, false);
227
	}
228
229
	/**
230
	 * Request to URI
231
	 *
232
	 * @param string       $http_method    HTTP method
233
	 * @param string       $uri            URI string
234
	 * @param array|string $request_params POST params/GET params|raw_input_stream
235
	 */
236
	protected function requestUri($http_method, $uri, $request_params)
0 ignored issues
show
Unused Code introduced by
The parameter $http_method 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...
Coding Style introduced by
requestUri uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
237
	{
238
		$_SERVER['argv'] = ['index.php', $uri];
239
240
		// Force cli mode because if not, it changes URI (and RTR) behavior
241
		$cli = is_cli();
242
		set_is_cli(TRUE);
0 ignored issues
show
Unused Code introduced by
The call to the function set_is_cli() seems unnecessary as the function has no side-effects.
Loading history...
243
244
		// Reset CodeIgniter instance state
245
		reset_instance();
246
247
		$this->setRawInputStream($request_params);
248
249
		// Get route
250
		list($class, $method, $params) = $this->router->getRoute();
251
252
		// Restore cli mode
253
		set_is_cli($cli);
0 ignored issues
show
Unused Code introduced by
The call to the function set_is_cli() seems unnecessary as the function has no side-effects.
Loading history...
254
255
//		$request = [
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
256
//			'REQUEST_METHOD' => $_SERVER['REQUEST_METHOD'],
257
//			'class' => $class,
258
//			'method' => $method,
259
//			'params' => $params,
260
//			'$_GET' => $_GET,
261
//			'$_POST' => $_POST,
262
//		];
263
//		var_dump($request, $_SERVER['argv']);
264
265
		return $this->createAndCallController($class, $method, $params);
266
	}
267
268
	protected function callHook($hook)
269
	{
270
		if ($this->enableHooks)
271
		{
272
			return $this->hooks->call_hook($hook);
273
		}
274
275
		return false;
276
	}
277
278
	protected function setRawInputStream($string)
279
	{
280
		if (is_string($string))
281
		{
282
			$INPUT =& load_class('Input', 'core');
283
			CIPHPUnitTestReflection::setPrivateProperty(
284
				$INPUT,
285
				'_raw_input_stream',
286
				$string
287
			);
288
		}
289
	}
290
291
	protected function createAndCallController($class, $method, $params, $call_display = true)
292
	{
293
		ob_start();
294
295
		$this->callHook('pre_controller');
296
297
		// Run callablePreConstructor
298
		if ($this->callablePreConstructors !== [])
299
		{
300
			foreach ($this->callablePreConstructors as $callable)
301
			{
302
				$callable();
303
			}
304
		}
305
306
		// Create controller
307
		if (CIPHPUnitTest::wiredesignzHmvcInstalled())
308
		{
309
			new CI();
310
		}
311
		$controller = new $class;
312
		$CI =& get_instance();
313
314
		// Set CodeIgniter instance to TestCase
315
		$this->testCase->setCI($CI);
316
317
		// Set default response code 200
318
		set_status_header(200);
319
		// Run callable
320
		if ($this->callables !== [])
321
		{
322
			foreach ($this->callables as $callable)
323
			{
324
				$callable($CI);
325
			}
326
		}
327
328
		$this->callHook('post_controller_constructor');
329
330
		// Call controller method
331
		call_user_func_array([$controller, $method], $params);
332
333
		$this->callHook('post_controller');
334
335
		if ($call_display && $this->callHook('display_override') === false)
336
		{
337
			$CI->output->_display();
338
		}
339
340
		$output = ob_get_clean();
341
342
		if ($output == '')
343
		{
344
			$output = $CI->output->get_output();
345
		}
346
347
		return $output;
348
	}
349
350
	/**
351
	 * Get HTTP Status Code Info
352
	 * 
353
	 * @return array ['code' => code, 'text' => text]
354
	 * @throws LogicException
355
	 */
356
	public function getStatus()
357
	{
358
		$CI =& get_instance();
359
		if (! isset($CI->output->_status))
360
		{
361
			throw new LogicException('Status code is not set. You must call $this->request() first');
362
		}
363
364
		return $CI->output->_status;
365
	}
366
}
367