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()) { |
|
|
|
|
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()) { |
|
|
|
|
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()) { |
|
|
|
|
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 |
|
|
|
|
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 |
|
|
|
|
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 |
|
|
|
|
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 |
|
|
|
|
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 |
|
|
|
|
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
|
|
|
|
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.