Completed
Push — master ( e02a77...1e7f08 )
by Adam
02:45
created

OnRequestHandler::hasPhoneRedirect()   D

Complexity

Conditions 9
Paths 5

Size

Total Lines 25
Code Lines 13

Duplication

Lines 25
Ratio 100 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 25
loc 25
rs 4.909
cc 9
eloc 13
nc 5
nop 0
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
final class OnRequestHandler
27
{
28
	const REDIRECT = 'redirect';
29
	const NO_REDIRECT = 'noRedirect';
30
	const REDIRECT_WITHOUT_PATH = 'redirectWithoutPath';
31
32
	const MOBILE = 'mobile';
33
	const TABLET = 'tablet';
34
	const PHONE = 'phone';
35
36
	/**
37
	 * @var array
38
	 */
39
	public $redirectConf = [];
40
41
	/**
42
	 * @var bool
43
	 */
44
	public $isFullPath = TRUE;
45
46
	/**
47
	 * @var Http\IRequest
48
	 */
49
	private $httpRequest;
50
51
	/**
52
	 * @var Http\IResponse
53
	 */
54
	private $httpResponse;
55
56
	/**
57
	 * @var Application\IRouter
58
	 */
59
	private $router;
60
61
	/**
62
	 * @var MobileDetect\MobileDetect
63
	 */
64
	private $mobileDetect;
65
66
	/**
67
	 * @var Helpers\DeviceView
68
	 */
69
	private $deviceView;
70
71
	/**
72
	 * @var OnResponseHandler
73
	 */
74
	private $onResponseHandler;
75
76
	/**
77
	 * @param Http\IRequest $httpRequest
78
	 * @param Http\IResponse $httpResponse
79
	 * @param Application\IRouter $router
80
	 * @param OnResponseHandler $onResponseHandler
81
	 * @param MobileDetect\MobileDetect $mobileDetect
82
	 * @param Helpers\DeviceView $deviceView
83
	 */
84
	public function __construct(
85
		Http\IRequest $httpRequest,
86
		Http\IResponse $httpResponse,
87
		Application\IRouter $router,
88
		OnResponseHandler $onResponseHandler,
89
		MobileDetect\MobileDetect $mobileDetect,
90
		Helpers\DeviceView $deviceView
91
	) {
92
		$this->httpRequest = $httpRequest;
93
		$this->httpResponse = $httpResponse;
94
95
		$this->router = $router;
96
97
		$this->onResponseHandler = $onResponseHandler;
98
99
		$this->mobileDetect = $mobileDetect;
100
		$this->deviceView = $deviceView;
101
	}
102
103
	/**
104
	 * @param Application\Application $application
105
	 *
106
	 * @return void
107
	 */
108
	public function __invoke(Application\Application $application)
109
	{
110
		// Redirect only normal request
111
		if ($this->httpRequest->isAjax()) {
112
			return;
113
		}
114
115
		// Sets the flag for the response handled by the GET switch param and the type of the view.
116
		if ($this->deviceView->hasSwitchParameter()) {
117
			if ($response = $this->getRedirectResponseBySwitchParam()) {
118
				$response->send($this->httpRequest, $this->httpResponse);
119
				exit();
120
			}
121
122
			return;
123
		}
124
125
		// If the device view is either the full view or not the mobile view
126
		if ($this->deviceView->isFullView() || $this->deviceView->isNotMobileView()) {
127
			return;
128
		}
129
130
		// Redirects to the phone version and set the 'phone' device view in a cookie.
131 View Code Duplication
		if ($this->hasPhoneRedirect()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
132
			if ($response = $this->getDeviceRedirectResponse(self::PHONE)) {
133
				$response->send($this->httpRequest, $this->httpResponse);
134
				exit();
135
			}
136
137
			return;
138
		}
139
140
		// Redirects to the tablet version and set the 'tablet' device view in a cookie.
141 View Code Duplication
		if ($this->hasTabletRedirect()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
142
			if ($response = $this->getDeviceRedirectResponse(self::TABLET)) {
143
				$response->send($this->httpRequest, $this->httpResponse);
144
				exit();
145
			}
146
147
			return;
148
		}
149
150
		// Redirects to the mobile version and set the 'mobile' device view in a cookie.
151 View Code Duplication
		if ($this->hasMobileRedirect()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
152
			if ($response = $this->getDeviceRedirectResponse(self::MOBILE)) {
153
				$response->send($this->httpRequest, $this->httpResponse);
154
				exit();
155
			}
156
157
			return;
158
		}
159
160
		// No need to redirect
161
162
		// Sets the flag for the response handler
163
		$this->onResponseHandler->needModifyResponse();
164
165
		// Checking the need to modify the Response and set closure
166
		if ($this->needPhoneResponseModify()) {
167
			$this->deviceView->setPhoneView();
168
169
			return;
170
		}
171
172
		// Checking the need to modify the Response and set closure
173
		if ($this->needTabletResponseModify()) {
174
			$this->deviceView->setTabletView();
175
176
			return;
177
		}
178
179
		// Sets the closure modifier mobile Response
180
		if ($this->needMobileResponseModify()) {
181
			$this->deviceView->setMobileView();
182
183
			return;
184
		}
185
186
		// Sets the closure modifier not_mobile Response
187
		if ($this->needNotMobileResponseModify()) {
188
			$this->deviceView->setNotMobileView();
189
190
			return;
191
		}
192
	}
193
194
	/**
195
	 * Detects phone redirections
196
	 *
197
	 * @return bool
198
	 */
199 View Code Duplication
	private function hasPhoneRedirect() : bool
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
200
	{
201
		if (!$this->redirectConf['phone']['isEnabled']) {
202
			return FALSE;
203
		}
204
205
		$isPhone = $this->mobileDetect->isPhone();
206
207
		if ($this->redirectConf['detectPhoneAsMobile'] === FALSE) {
208
			$isPhoneHost = ($this->getCurrentHost() === $this->redirectConf['phone']['host']);
209
210
			if ($isPhone && !$isPhoneHost && ($this->getRoutingOption(self::PHONE) != self::NO_REDIRECT)) {
211
				return TRUE;
212
			}
213
214
		} else {
215
			$isMobileHost = ($this->getCurrentHost() === $this->redirectConf['mobile']['host']);
216
217
			if ($isPhone && !$isMobileHost && ($this->getRoutingOption(self::PHONE) != self::NO_REDIRECT)) {
218
				return TRUE;
219
			}
220
		}
221
222
		return FALSE;
223
	}
224
225
	/**
226
	 * Detects tablet redirections
227
	 *
228
	 * @return bool
229
	 */
230 View Code Duplication
	private function hasTabletRedirect() : bool
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
231
	{
232
		if (!$this->redirectConf['tablet']['isEnabled']) {
233
			return FALSE;
234
		}
235
236
		$isTablet = $this->mobileDetect->isTablet();
237
238
		if ($this->redirectConf['detectTabletAsMobile'] === FALSE) {
239
			$isTabletHost = ($this->getCurrentHost() === $this->redirectConf['tablet']['host']);
240
241
			if ($isTablet && !$isTabletHost && ($this->getRoutingOption(self::TABLET) != self::NO_REDIRECT)) {
242
				return TRUE;
243
			}
244
245
		} else {
246
			$isMobileHost = ($this->getCurrentHost() === $this->redirectConf['mobile']['host']);
247
248
			if ($isTablet && !$isMobileHost && ($this->getRoutingOption(self::TABLET) != self::NO_REDIRECT)) {
249
				return TRUE;
250
			}
251
		}
252
253
		return FALSE;
254
	}
255
256
	/**
257
	 * Detects mobile redirections
258
	 *
259
	 * @return bool
260
	 */
261
	private function hasMobileRedirect() : bool
262
	{
263
		if (!$this->redirectConf['mobile']['isEnabled']) {
264
			return FALSE;
265
		}
266
267
		if ($this->redirectConf['detectPhoneAsMobile'] === FALSE) {
268
			$isMobile = ($this->mobileDetect->isTablet() || ($this->mobileDetect->isMobile()) && !$this->mobileDetect->isPhone());
269
270
		} elseif ($this->redirectConf['detectTabletAsMobile'] === FALSE) {
271
			$isMobile = ($this->mobileDetect->isPhone() || ($this->mobileDetect->isMobile()) && !$this->mobileDetect->isTablet());
272
273
		} else {
274
			$isMobile = $this->mobileDetect->isMobile();
275
		}
276
277
		$isMobileHost = ($this->getCurrentHost() === $this->redirectConf['mobile']['host']);
278
279
		if ($isMobile && !$isMobileHost && ($this->getRoutingOption(self::MOBILE) != self::NO_REDIRECT)) {
280
			return TRUE;
281
		}
282
283
		return FALSE;
284
	}
285
286
	/**
287
	 * If a modified Response for phone devices is needed
288
	 *
289
	 * @return bool
290
	 */
291 View Code Duplication
	private function needPhoneResponseModify() : bool
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
292
	{
293
		if (($this->deviceView->getViewType() === NULL || $this->deviceView->isPhoneView()) && $this->mobileDetect->isMobile() && !$this->mobileDetect->isTablet()) {
294
			$this->onResponseHandler->modifyResponseClosure = function ($deviceView) {
295
				return $deviceView->modifyPhoneResponse();
296
			};
297
298
			return TRUE;
299
		}
300
301
		return FALSE;
302
	}
303
304
	/**
305
	 * If a modified Response for tablet devices is needed
306
	 *
307
	 * @return bool
308
	 */
309 View Code Duplication
	private function needTabletResponseModify() : bool
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
310
	{
311
		if (($this->deviceView->getViewType() === NULL || $this->deviceView->isTabletView()) && $this->mobileDetect->isTablet()) {
312
			$this->onResponseHandler->modifyResponseClosure = function (Helpers\DeviceView $deviceView) {
313
				return $deviceView->modifyTabletResponse();
314
			};
315
316
			return TRUE;
317
		}
318
319
		return FALSE;
320
	}
321
322
	/**
323
	 * If a modified Response for mobile devices is needed
324
	 *
325
	 * @return bool
326
	 */
327 View Code Duplication
	private function needMobileResponseModify() : bool
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
328
	{
329
		if (($this->deviceView->getViewType() === NULL || $this->deviceView->isMobileView()) && $this->mobileDetect->isMobile()) {
330
			$this->onResponseHandler->modifyResponseClosure = function (Helpers\DeviceView $deviceView) {
331
				return $deviceView->modifyMobileResponse();
332
			};
333
334
			return TRUE;
335
		}
336
337
		return FALSE;
338
	}
339
340
	/**
341
	 * If a modified Response for non-mobile devices is needed
342
	 *
343
	 * @return bool
344
	 */
345
	private function needNotMobileResponseModify() : bool
346
	{
347
		if ($this->deviceView->getViewType() === NULL || $this->deviceView->isNotMobileView()) {
348
			$this->onResponseHandler->modifyResponseClosure = function (Helpers\DeviceView $deviceView) {
349
				return $deviceView->modifyNotMobileResponse();
350
			};
351
352
			return TRUE;
353
		}
354
355
		return FALSE;
356
	}
357
358
	/**
359
	 * Gets the RedirectResponse by switch param
360
	 *
361
	 * @return Responses\RedirectResponse
362
	 */
363
	private function getRedirectResponseBySwitchParam() : Responses\RedirectResponse
364
	{
365
		// Generate full url path
366
		if ($this->isFullPath === TRUE) {
367
			// Get actual url
368
			$url = $this->httpRequest->getUrl();
369
370
			// Remove switch param
371
			$url->setQueryParameter($this->deviceView->getSwitchParameterName(), NULL);
372
373
			// Create full path url
374
			$redirectUrl = $this->getCurrentHost() . $url->getRelativeUrl();
375
376
			// Generate only domain path
377
		} else {
378
			$redirectUrl = $this->getCurrentHost();
379
		}
380
381
		return $this->deviceView->getRedirectResponseBySwitchParam($redirectUrl);
382
	}
383
384
	/**
385
	 * Gets the device RedirectResponse
386
	 * 
387
	 * @param string $device
388
	 *
389
	 * @return Responses\RedirectResponse
390
	 */
391
	private function getDeviceRedirectResponse(string $device) : Responses\RedirectResponse
392
	{
393
		if ($host = $this->getRedirectUrl($device)) {
394
			return $this->deviceView->getMobileRedirectResponse(
395
				$host,
396
				$this->redirectConf[$device]['statusCode']
397
			);
398
		}
399
	}
400
401
	/**
402
	 * Gets the redirect url
403
	 *
404
	 * @param string $platform
405
	 *
406
	 * @return string
407
	 */
408
	private function getRedirectUrl(string $platform) : string
409
	{
410
		if ($routingOption = $this->getRoutingOption($platform)) {
411
			switch ($routingOption) {
412
				case self::REDIRECT:
413
					return rtrim($this->redirectConf[$platform]['host'], '/') . '/' . ltrim($this->httpRequest->getUrl()->getRelativeUrl(), '/');
414
415
				case self::REDIRECT_WITHOUT_PATH:
416
					return $this->redirectConf[$platform]['host'];
417
			}
418
		}
419
	}
420
421
	/**
422
	 * Gets named option from current route
423
	 *
424
	 * @param string $name
425
	 *
426
	 * @return string|NULL
427
	 */
428
	private function getRoutingOption(string $name)
429
	{
430
		$option = NULL;
431
432
		// Get actual route
433
		$request = $this->router->match($this->httpRequest);
434
435
		if ($request instanceof Application\Request) {
436
			$params = $request->getParameters();
437
			$option = isset($params[$name]) ? $params[$name] : NULL;
438
		}
439
440
		if (!$option) {
441
			$option = $this->redirectConf[$name]['action'];
442
		}
443
444
		if (in_array($option, [self::REDIRECT, self::REDIRECT_WITHOUT_PATH, self::NO_REDIRECT])) {
445
			return $option;
446
		}
447
448
		return NULL;
449
	}
450
451
	/**
452
	 * Gets the current host
453
	 *
454
	 * @return string
455
	 */
456
	private function getCurrentHost() : string
457
	{
458
		return $this->httpRequest->getUrl()->getHostUrl() . $this->httpRequest->getUrl()->getScriptPath();
459
	}
460
}
461