Controller   A
last analyzed

Complexity

Total Complexity 34

Size/Duplication

Total Lines 420
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 0
Metric Value
dl 0
loc 420
rs 9.2
c 0
b 0
f 0
wmc 34
lcom 1
cbo 6

19 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 28 2
A redirectToDefaultRoute() 0 5 1
A redirect_to_previous() 0 5 1
B set_session_redirect() 0 29 5
A session_redirect() 0 13 2
A __get() 0 11 2
B load_partial() 0 22 4
A render_full_page() 0 12 3
A login() 0 19 2
A loginAction() 0 12 2
A logout() 0 7 1
A notFound() 0 6 1
A errorPage() 0 8 1
A set_flash_message() 0 7 1
A clearCache() 0 7 1
A showMessage() 0 7 1
A outputHTML() 0 10 2
A outputJSON() 0 7 1
A redirect() 0 5 1
1
<?php declare(strict_types=1);
2
/**
3
 * Hummingbird Anime Client
4
 *
5
 * An API client for Hummingbird to manage anime and manga watch lists
6
 *
7
 * PHP version 7
8
 *
9
 * @package     HummingbirdAnimeClient
10
 * @author      Timothy J. Warren <[email protected]>
11
 * @copyright   2015 - 2016  Timothy J. Warren
12
 * @license     http://www.opensource.org/licenses/mit-license.html  MIT License
13
 * @version     3.1
14
 * @link        https://github.com/timw4mail/HummingBirdAnimeClient
15
 */
16
17
namespace Aviat\AnimeClient;
18
19
use const Aviat\AnimeClient\SESSION_SEGMENT;
20
21
use Aviat\Ion\Di\{ContainerAware, ContainerInterface};
22
use Aviat\Ion\View\{HtmlView, HttpView, JsonView};
23
use InvalidArgumentException;
24
25
/**
26
 * Controller base, defines output methods
27
 *
28
 * @property Response object $response
29
 */
30
class Controller {
31
32
	use ContainerAware;
33
34
	/**
35
	 * Cache manager
36
	 * @var \Aviat\Ion\Cache\CacheInterface
37
	 */
38
	protected $cache;
39
40
	/**
41
	 * The global configuration object
42
	 * @var Aviat\Ion\ConfigInterface $config
43
	 */
44
	protected $config;
45
46
	/**
47
	 * Request object
48
	 * @var object $request
49
	 */
50
	protected $request;
51
52
	/**
53
	 * Response object
54
	 * @var object $response
55
	 */
56
	protected $response;
57
58
	/**
59
	 * The api model for the current controller
60
	 * @var object
61
	 */
62
	protected $model;
63
64
	/**
65
	 * Url generation class
66
	 * @var UrlGenerator
67
	 */
68
	protected $urlGenerator;
69
70
	/**
71
	 * Session segment
72
	 * @var [type]
73
	 */
74
	protected $session;
75
76
	/**
77
	 * Common data to be sent to views
78
	 * @var array
79
	 */
80
	protected $base_data = [
81
		'url_type' => 'anime',
82
		'other_type' => 'manga',
83
		'menu_name' => ''
84
	];
85
86
	/**
87
	 * Constructor
88
	 *
89
	 * @param ContainerInterface $container
0 ignored issues
show
Documentation introduced by
Should the type for parameter $container not be \Aviat\Ion\Di\ContainerInterface?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
90
	 */
91
	public function __construct(ContainerInterface $container)
92
	{
93
		$this->setContainer($container);
94
		$auraUrlGenerator = $container->get('aura-router')->getGenerator();
95
		$urlGenerator = $container->get('url-generator');
96
		$this->cache =  $container->get('cache');
97
		$this->config = $container->get('config');
98
		$this->request = $container->get('request');
99
		$this->response = $container->get('response');
100
		$this->base_data['url'] = $auraUrlGenerator;
101
		$this->base_data['urlGenerator'] = $urlGenerator;
102
		$this->base_data['auth'] = $container->get('auth');
103
		$this->base_data['config'] = $this->config;
104
		$this->urlGenerator = $urlGenerator;
105
106
		$session = $container->get('session');
107
		$this->session = $session->getSegment(SESSION_SEGMENT);
108
109
		// Set a 'previous' flash value for better redirects
110
		$server_params = $this->request->getServerParams();
111
		if (array_key_exists('HTTP_REFERER', $server_params))
112
		{
113
			$this->session->setFlash('previous', $server_params['HTTP_REFERER']);
114
		}
115
116
		// Set a message box if available
117
		$this->base_data['message'] = $this->session->getFlash('message');
118
	}
119
120
	/**
121
	 * Redirect to the default controller/url from an empty path
122
	 *
123
	 * @return void
124
	 */
125
	public function redirectToDefaultRoute()
126
	{
127
		$default_type = $this->config->get(['routes', 'route_config', 'default_list']);
128
		$this->redirect($this->urlGenerator->default_url($default_type), 303);
129
	}
130
131
	/**
132
	 * Redirect to the previous page
133
	 *
134
	 * @return void
135
	 */
136
	public function redirect_to_previous()
137
	{
138
		$previous = $this->session->getFlash('previous');
139
		$this->redirect($previous, 303);
140
	}
141
142
	/**
143
	 * Set the current url in the session as the target of a future redirect
144
	 *
145
	 * @param string|null $url
146
	 * @return void
147
	 */
148
	public function set_session_redirect($url = NULL)
149
	{
150
		$server_params = $this->request->getServerParams();
151
152
		if ( ! array_key_exists('HTTP_REFERER', $server_params))
153
		{
154
			return;
155
		}
156
157
		$util = $this->container->get('util');
158
		$double_form_page = $server_params['HTTP_REFERER'] === $this->request->getUri();
159
160
		// Don't attempt to set the redirect url if
161
		// the page is one of the form type pages,
162
		// and the previous page is also a form type page_segments
163
		if ($double_form_page)
164
		{
165
			return;
166
		}
167
168
		if (is_null($url))
169
		{
170
			$url = $util->is_view_page()
171
				? $this->request->url->get()
172
				: $server_params['HTTP_REFERER'];
173
		}
174
175
		$this->session->set('redirect_url', $url);
176
	}
177
178
	/**
179
	 * Redirect to the url previously set in the  session
180
	 *
181
	 * @return void
182
	 */
183
	public function session_redirect()
184
	{
185
		$target = $this->session->get('redirect_url');
186
		if (empty($target))
187
		{
188
			$this->notFound();
189
		}
190
		else
191
		{
192
			$this->redirect($target, 303);
193
			$this->session->set('redirect_url', NULL);
194
		}
195
	}
196
197
	/**
198
	 * Get a class member
199
	 *
200
	 * @param string $key
201
	 * @return mixed
202
	 */
203
	public function __get(string $key)
204
	{
205
		$allowed = ['response', 'config'];
206
207
		if (in_array($key, $allowed))
208
		{
209
			return $this->$key;
210
		}
211
212
		return NULL;
213
	}
214
215
	/**
216
	 * Get the string output of a partial template
217
	 *
218
	 * @param HtmlView $view
219
	 * @param string $template
220
	 * @param array $data
221
	 * @throws InvalidArgumentException
222
	 * @return string
223
	 */
224
	protected function load_partial($view, $template, array $data = [])
225
	{
226
		$router = $this->container->get('dispatcher');
227
228
		if (isset($this->base_data))
229
		{
230
			$data = array_merge($this->base_data, $data);
231
		}
232
233
		$route = $router->getRoute();
234
		$data['route_path'] = $route ? $router->getRoute()->path : '';
235
236
237
		$template_path = _dir($this->config->get('view_path'), "{$template}.php");
238
239
		if ( ! is_file($template_path))
240
		{
241
			throw new InvalidArgumentException("Invalid template : {$template}");
242
		}
243
244
		return $view->renderTemplate($template_path, (array)$data);
245
	}
246
247
	/**
248
	 * Render a template with header and footer
249
	 *
250
	 * @param HtmlView $view
251
	 * @param string $template
252
	 * @param array $data
253
	 * @return void
254
	 */
255
	protected function render_full_page($view, $template, array $data)
256
	{
257
		$view->appendOutput($this->load_partial($view, 'header', $data));
258
259
		if (array_key_exists('message', $data) && is_array($data['message']))
260
		{
261
			$view->appendOutput($this->load_partial($view, 'message', $data['message']));
262
		}
263
264
		$view->appendOutput($this->load_partial($view, $template, $data));
265
		$view->appendOutput($this->load_partial($view, 'footer', $data));
266
	}
267
268
	/**
269
	 * Show the login form
270
	 *
271
	 * @codeCoverageIgnore
272
	 * @param string $status
273
	 * @return void
274
	 */
275
	public function login(string $status = '')
276
	{
277
		$message = '';
278
279
		$view = new HtmlView($this->container);
280
281
		if ($status !== '')
282
		{
283
			$message = $this->show_message($view, 'error', $status);
0 ignored issues
show
Bug introduced by
The method show_message() does not seem to exist on object<Aviat\AnimeClient\Controller>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
284
		}
285
286
		// Set the redirect url
287
		$this->set_session_redirect();
288
289
		$this->outputHTML('login', [
290
			'title' => 'Api login',
291
			'message' => $message
292
		], $view);
0 ignored issues
show
Documentation introduced by
$view is of type object<Aviat\Ion\View\HtmlView>, but the function expects a object<HtmlView>|null.

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...
293
	}
294
295
	/**
296
	 * Attempt login authentication
297
	 *
298
	 * @return void
299
	 */
300
	public function loginAction()
301
	{
302
		$auth = $this->container->get('auth');
303
		$post = $this->request->getParsedBody();
304
		if ($auth->authenticate($post['password']))
305
		{
306
			return $this->session_redirect();
307
		}
308
309
		$this->set_flash_message('Invalid username or password.');
310
		$this->redirect($this->urlGenerator->url('login'), 303);
311
	}
312
313
	/**
314
	 * Deauthorize the current user
315
	 *
316
	 * @return void
317
	 */
318
	public function logout()
319
	{
320
		$auth = $this->container->get('auth');
321
		$auth->logout();
322
323
		$this->redirectToDefaultRoute();
324
	}
325
326
	/**
327
	 * 404 action
328
	 *
329
	 * @return void
330
	 */
331
	public function notFound()
332
	{
333
		$this->outputHTML('404', [
334
			'title' => 'Sorry, page not found'
335
		], NULL, 404);
336
	}
337
338
	/**
339
	 * Display a generic error page
340
	 *
341
	 * @param int $http_code
342
	 * @param string $title
343
	 * @param string $message
344
	 * @param string $long_message
345
	 * @return void
346
	 */
347
	public function errorPage($http_code, $title, $message, $long_message = "")
348
	{
349
		$this->outputHTML('error', [
350
			'title' => $title,
351
			'message' => $message,
352
			'long_message' => $long_message
353
		], NULL, $http_code);
354
	}
355
356
	/**
357
	 * Set a session flash variable to display a message on
358
	 * next page load
359
	 *
360
	 * @param string $message
361
	 * @param string $type
362
	 * @return void
363
	 */
364
	public function set_flash_message($message, $type = "info")
365
	{
366
		$this->session->setFlash('message', [
367
			'message_type' => $type,
368
			'message' => $message
369
		]);
370
	}
371
372
	/**
373
	 * Purges the API cache
374
	 *
375
	 * @return void
376
	 */
377
	public function clearCache()
378
	{
379
		$this->cache->clear();
380
		$this->outputHTML('blank', [
381
			'title' => 'Cache cleared'
382
		], NULL, 200);
383
	}
384
385
	/**
386
	 * Add a message box to the page
387
	 *
388
	 * @codeCoverageIgnore
389
	 * @param HtmlView $view
390
	 * @param string $type
391
	 * @param string $message
392
	 * @return string
393
	 */
394
	protected function showMessage($view, $type, $message)
395
	{
396
		return $this->load_partial($view, 'message', [
397
			'message_type' => $type,
398
			'message'  => $message
399
		]);
400
	}
401
402
	/**
403
	 * Output a template to HTML, using the provided data
404
	 *
405
	 * @param string $template
406
	 * @param array $data
407
	 * @param HtmlView|null $view
408
	 * @param int $code
409
	 * @return void
410
	 */
411
	protected function outputHTML($template, array $data = [], $view = NULL, $code = 200)
412
	{
413
		if (is_null($view))
414
		{
415
			$view = new HtmlView($this->container);
416
		}
417
418
		$view->setStatusCode($code);
419
		$this->render_full_page($view, $template, $data);
0 ignored issues
show
Bug introduced by
It seems like $view can also be of type object<Aviat\Ion\View\HtmlView>; however, Aviat\AnimeClient\Controller::render_full_page() does only seem to accept object<HtmlView>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
420
	}
421
422
	/**
423
	 * Output a JSON Response
424
	 *
425
	 * @param mixed $data
426
	 * @param int $code - the http status code
427
	 * @return void
428
	 */
429
	protected function outputJSON($data = 'Empty response', int $code = 200)
430
	{
431
		(new JsonView($this->container))
432
			->setStatusCode($code)
433
			->setOutput($data)
434
			->send();
435
	}
436
437
	/**
438
	 * Redirect to the selected page
439
	 *
440
	 * @param string $url
441
	 * @param int $code
442
	 * @return void
443
	 */
444
	protected function redirect($url, $code)
445
	{
446
		$http = new HttpView($this->container);
447
		$http->redirect($url, $code);
448
	}
449
}
450
// End of BaseController.php