Passed
Push — master ( 9edc41...f34eb1 )
by Adam
03:33
created

OnRequestHandler::getRoutingOption()   B

Complexity

Conditions 5
Paths 12

Size

Total Lines 22
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 22
ccs 0
cts 10
cp 0
rs 8.6737
cc 5
eloc 11
nc 12
nop 1
crap 30
1
<?php
2
/**
3
 * OnRequestHandler.php
4
 *
5
 * @copyright      More in license.md
6
 * @license        http://www.ipublikuj.eu
7
 * @author         Adam Kadlec http://www.ipublikuj.eu
8
 * @package        iPublikuj:MobileDetect!
9
 * @subpackage     Events
10
 * @since          1.0.0
11
 *
12
 * @date           22.04.14
13
 */
14
15
declare(strict_types = 1);
16
17
namespace IPub\MobileDetect\Events;
18
19
use Nette\Application;
20
use Nette\Application\Responses;
21
use Nette\Http;
22
23
use IPub\MobileDetect;
24
use IPub\MobileDetect\Helpers;
25
26
/**
27
 * On request event handler
28
 *
29
 * @package        iPublikuj:MobileDetect!
30
 * @subpackage     Events
31
 *
32
 * @author         Adam Kadlec <[email protected]>
33
 */
34 1
final class OnRequestHandler
35
{
36
	const REDIRECT = 'redirect';
37
	const NO_REDIRECT = 'noRedirect';
38
	const REDIRECT_WITHOUT_PATH = 'redirectWithoutPath';
39
40
	const MOBILE = 'mobile';
41
	const TABLET = 'tablet';
42
	const PHONE = 'phone';
43
44
	/**
45
	 * @var array
46
	 */
47
	public $redirectConf = [];
48
49
	/**
50
	 * @var bool
51
	 */
52
	public $isFullPath = TRUE;
53
54
	/**
55
	 * @var Http\IRequest
56
	 */
57
	private $httpRequest;
58
59
	/**
60
	 * @var Http\IResponse
61
	 */
62
	private $httpResponse;
63
64
	/**
65
	 * @var Application\IRouter
66
	 */
67
	private $router;
68
69
	/**
70
	 * @var MobileDetect\MobileDetect
71
	 */
72
	private $mobileDetect;
73
74
	/**
75
	 * @var Helpers\DeviceView
76
	 */
77
	private $deviceView;
78
79
	/**
80
	 * @var OnResponseHandler
81
	 */
82
	private $onResponseHandler;
83
84
	/**
85
	 * @param Http\IRequest $httpRequest
86
	 * @param Http\IResponse $httpResponse
87
	 * @param Application\IRouter $router
88
	 * @param OnResponseHandler $onResponseHandler
89
	 * @param MobileDetect\MobileDetect $mobileDetect
90
	 * @param Helpers\DeviceView $deviceView
91
	 */
92
	public function __construct(
93
		Http\IRequest $httpRequest,
94
		Http\IResponse $httpResponse,
95
		Application\IRouter $router,
96
		OnResponseHandler $onResponseHandler,
97
		MobileDetect\MobileDetect $mobileDetect,
98
		Helpers\DeviceView $deviceView
99
	) {
100 1
		$this->httpRequest = $httpRequest;
101 1
		$this->httpResponse = $httpResponse;
102
103 1
		$this->router = $router;
104
105 1
		$this->onResponseHandler = $onResponseHandler;
106
107 1
		$this->mobileDetect = $mobileDetect;
108 1
		$this->deviceView = $deviceView;
109 1
	}
110
111
	/**
112
	 * @param Application\Application $application
113
	 *
114
	 * @return void
115
	 */
116
	public function __invoke(Application\Application $application) : void
117
	{
118
		// Redirect only normal request
119
		if ($this->httpRequest->isAjax()) {
120
			return;
121
		}
122
123
		// Sets the flag for the response handled by the GET switch param and the type of the view.
124
		if ($this->deviceView->hasSwitchParameter()) {
125
			if ($response = $this->getRedirectResponseBySwitchParam()) {
126
				$response->send($this->httpRequest, $this->httpResponse);
127
				exit();
128
			}
129
130
			return;
131
		}
132
133
		// If the device view is either the full view or not the mobile view
134
		if ($this->deviceView->isFullView() || $this->deviceView->isNotMobileView()) {
135
			return;
136
		}
137
138
		// Redirects to the phone version and set the 'phone' device view in a cookie.
139
		if ($this->hasPhoneRedirect()) {
140
			if ($response = $this->getDeviceRedirectResponse(self::PHONE)) {
141
				$response->send($this->httpRequest, $this->httpResponse);
142
				exit();
143
			}
144
145
			return;
146
		}
147
148
		// Redirects to the tablet version and set the 'tablet' device view in a cookie.
149
		if ($this->hasTabletRedirect()) {
150
			if ($response = $this->getDeviceRedirectResponse(self::TABLET)) {
151
				$response->send($this->httpRequest, $this->httpResponse);
152
				exit();
153
			}
154
155
			return;
156
		}
157
158
		// Redirects to the mobile version and set the 'mobile' device view in a cookie.
159
		if ($this->hasMobileRedirect()) {
160
			if ($response = $this->getDeviceRedirectResponse(self::MOBILE)) {
161
				$response->send($this->httpRequest, $this->httpResponse);
162
				exit();
163
			}
164
165
			return;
166
		}
167
168
		// No need to redirect
169
170
		// Sets the flag for the response handler
171
		$this->onResponseHandler->needModifyResponse();
172
173
		// Checking the need to modify the Response and set closure
174
		if ($this->needPhoneResponseModify()) {
175
			$this->deviceView->setPhoneView();
176
177
			return;
178
		}
179
180
		// Checking the need to modify the Response and set closure
181
		if ($this->needTabletResponseModify()) {
182
			$this->deviceView->setTabletView();
183
184
			return;
185
		}
186
187
		// Sets the closure modifier mobile Response
188
		if ($this->needMobileResponseModify()) {
189
			$this->deviceView->setMobileView();
190
191
			return;
192
		}
193
194
		// Sets the closure modifier not_mobile Response
195
		if ($this->needNotMobileResponseModify()) {
196
			$this->deviceView->setNotMobileView();
197
198
			return;
199
		}
200
	}
201
202
	/**
203
	 * Detects phone redirections
204
	 *
205
	 * @return bool
206
	 */
207
	private function hasPhoneRedirect() : bool
208
	{
209
		if (!$this->redirectConf['phone']['isEnabled']) {
210
			return FALSE;
211
		}
212
213
		$isPhone = $this->mobileDetect->isPhone();
214
215
		if ($this->redirectConf['detectPhoneAsMobile'] === FALSE) {
216
			$isPhoneHost = ($this->getCurrentHost() === $this->redirectConf['phone']['host']);
217
218
			if ($isPhone && !$isPhoneHost && ($this->getRoutingOption(self::PHONE) != self::NO_REDIRECT)) {
219
				return TRUE;
220
			}
221
222
		} else {
223
			$isMobileHost = ($this->getCurrentHost() === $this->redirectConf['mobile']['host']);
224
225
			if ($isPhone && !$isMobileHost && ($this->getRoutingOption(self::PHONE) != self::NO_REDIRECT)) {
226
				return TRUE;
227
			}
228
		}
229
230
		return FALSE;
231
	}
232
233
	/**
234
	 * Detects tablet redirections
235
	 *
236
	 * @return bool
237
	 */
238
	private function hasTabletRedirect() : bool
239
	{
240
		if (!$this->redirectConf['tablet']['isEnabled']) {
241
			return FALSE;
242
		}
243
244
		$isTablet = $this->mobileDetect->isTablet();
245
246
		if ($this->redirectConf['detectTabletAsMobile'] === FALSE) {
247
			$isTabletHost = ($this->getCurrentHost() === $this->redirectConf['tablet']['host']);
248
249
			if ($isTablet && !$isTabletHost && ($this->getRoutingOption(self::TABLET) != self::NO_REDIRECT)) {
250
				return TRUE;
251
			}
252
253
		} else {
254
			$isMobileHost = ($this->getCurrentHost() === $this->redirectConf['mobile']['host']);
255
256
			if ($isTablet && !$isMobileHost && ($this->getRoutingOption(self::TABLET) != self::NO_REDIRECT)) {
257
				return TRUE;
258
			}
259
		}
260
261
		return FALSE;
262
	}
263
264
	/**
265
	 * Detects mobile redirections
266
	 *
267
	 * @return bool
268
	 */
269
	private function hasMobileRedirect() : bool
270
	{
271
		if (!$this->redirectConf['mobile']['isEnabled']) {
272
			return FALSE;
273
		}
274
275
		if ($this->redirectConf['detectPhoneAsMobile'] === FALSE) {
276
			$isMobile = ($this->mobileDetect->isTablet() || ($this->mobileDetect->isMobile()) && !$this->mobileDetect->isPhone());
277
278
		} elseif ($this->redirectConf['detectTabletAsMobile'] === FALSE) {
279
			$isMobile = ($this->mobileDetect->isPhone() || ($this->mobileDetect->isMobile()) && !$this->mobileDetect->isTablet());
280
281
		} else {
282
			$isMobile = $this->mobileDetect->isMobile();
283
		}
284
285
		$isMobileHost = ($this->getCurrentHost() === $this->redirectConf['mobile']['host']);
286
287
		if ($isMobile && !$isMobileHost && ($this->getRoutingOption(self::MOBILE) != self::NO_REDIRECT)) {
288
			return TRUE;
289
		}
290
291
		return FALSE;
292
	}
293
294
	/**
295
	 * If a modified Response for phone devices is needed
296
	 *
297
	 * @return bool
298
	 */
299
	private function needPhoneResponseModify() : bool
300
	{
301
		if (($this->deviceView->getViewType() === NULL || $this->deviceView->isPhoneView()) && $this->mobileDetect->isMobile() && !$this->mobileDetect->isTablet()) {
302
			$this->onResponseHandler->modifyResponseClosure = function ($deviceView) {
303
				return $deviceView->modifyPhoneResponse();
304
			};
305
306
			return TRUE;
307
		}
308
309
		return FALSE;
310
	}
311
312
	/**
313
	 * If a modified Response for tablet devices is needed
314
	 *
315
	 * @return bool
316
	 */
317
	private function needTabletResponseModify() : bool
318
	{
319
		if (($this->deviceView->getViewType() === NULL || $this->deviceView->isTabletView()) && $this->mobileDetect->isTablet()) {
320
			$this->onResponseHandler->modifyResponseClosure = function (Helpers\DeviceView $deviceView) {
321
				return $deviceView->modifyTabletResponse();
322
			};
323
324
			return TRUE;
325
		}
326
327
		return FALSE;
328
	}
329
330
	/**
331
	 * If a modified Response for mobile devices is needed
332
	 *
333
	 * @return bool
334
	 */
335
	private function needMobileResponseModify() : bool
336
	{
337
		if (($this->deviceView->getViewType() === NULL || $this->deviceView->isMobileView()) && $this->mobileDetect->isMobile()) {
338
			$this->onResponseHandler->modifyResponseClosure = function (Helpers\DeviceView $deviceView) {
339
				return $deviceView->modifyMobileResponse();
340
			};
341
342
			return TRUE;
343
		}
344
345
		return FALSE;
346
	}
347
348
	/**
349
	 * If a modified Response for non-mobile devices is needed
350
	 *
351
	 * @return bool
352
	 */
353
	private function needNotMobileResponseModify() : bool
354
	{
355
		if ($this->deviceView->getViewType() === NULL || $this->deviceView->isNotMobileView()) {
356
			$this->onResponseHandler->modifyResponseClosure = function (Helpers\DeviceView $deviceView) {
357
				return $deviceView->modifyNotMobileResponse();
358
			};
359
360
			return TRUE;
361
		}
362
363
		return FALSE;
364
	}
365
366
	/**
367
	 * Gets the RedirectResponse by switch param
368
	 *
369
	 * @return Responses\RedirectResponse
370
	 */
371
	private function getRedirectResponseBySwitchParam() : Responses\RedirectResponse
372
	{
373
		// Generate full url path
374
		if ($this->isFullPath === TRUE) {
375
			// Get actual url
376
			$url = $this->httpRequest->getUrl();
377
378
			// Remove switch param
379
			$url->setQueryParameter($this->deviceView->getSwitchParameterName(), NULL);
380
381
			// Create full path url
382
			$redirectUrl = $this->getCurrentHost() . $url->getRelativeUrl();
383
384
			// Generate only domain path
385
		} else {
386
			$redirectUrl = $this->getCurrentHost();
387
		}
388
389
		return $this->deviceView->getRedirectResponseBySwitchParam($redirectUrl);
390
	}
391
392
	/**
393
	 * Gets the device RedirectResponse
394
	 * 
395
	 * @param string $device
396
	 *
397
	 * @return Responses\RedirectResponse
398
	 */
399
	private function getDeviceRedirectResponse(string $device) : Responses\RedirectResponse
400
	{
401
		if ($host = $this->getRedirectUrl($device)) {
402
			return $this->deviceView->getMobileRedirectResponse(
403
				$host,
404
				$this->redirectConf[$device]['statusCode']
405
			);
406
		}
407
	}
408
409
	/**
410
	 * Gets the redirect url
411
	 *
412
	 * @param string $platform
413
	 *
414
	 * @return string
415
	 */
416
	private function getRedirectUrl(string $platform) : string
417
	{
418
		if ($routingOption = $this->getRoutingOption($platform)) {
419
			switch ($routingOption) {
420
				case self::REDIRECT:
421
					return rtrim($this->redirectConf[$platform]['host'], '/') . '/' . ltrim($this->httpRequest->getUrl()->getRelativeUrl(), '/');
422
423
				case self::REDIRECT_WITHOUT_PATH:
424
					return $this->redirectConf[$platform]['host'];
425
			}
426
		}
427
	}
428
429
	/**
430
	 * Gets named option from current route
431
	 *
432
	 * @param string $name
433
	 *
434
	 * @return string|NULL
435
	 */
436
	private function getRoutingOption(string $name) : ?string
437
	{
438
		$option = NULL;
439
440
		// Get actual route
441
		$request = $this->router->match($this->httpRequest);
442
443
		if ($request instanceof Application\Request) {
444
			$params = $request->getParameters();
445
			$option = isset($params[$name]) ? $params[$name] : NULL;
446
		}
447
448
		if (!$option) {
449
			$option = $this->redirectConf[$name]['action'];
450
		}
451
452
		if (in_array($option, [self::REDIRECT, self::REDIRECT_WITHOUT_PATH, self::NO_REDIRECT])) {
453
			return $option;
454
		}
455
456
		return NULL;
457
	}
458
459
	/**
460
	 * Gets the current host
461
	 *
462
	 * @return string
463
	 */
464
	private function getCurrentHost() : string
465
	{
466
		return $this->httpRequest->getUrl()->getHostUrl() . $this->httpRequest->getUrl()->getScriptPath();
467
	}
468
}
469