├── tests
├── tmp
│ └── .gitignore
├── php.ini-unix
├── IPubTests
│ ├── .gitignore
│ ├── MobileDetect
│ │ ├── files
│ │ │ ├── presenters.neon
│ │ │ └── config.neon
│ │ ├── templates
│ │ │ └── default.latte
│ │ ├── libs
│ │ │ └── RouterFactory.php
│ │ ├── ExtensionTest.phpt
│ │ ├── DeviceViewTest.phpt
│ │ ├── MobileDetectTest.phpt
│ │ └── TemplateTest.phpt
│ └── bootstrap.php
└── php.ini-win
├── .gitignore
├── .travis.yml
├── src
└── IPub
│ └── MobileDetect
│ ├── Exceptions
│ ├── IException.php
│ ├── CompileException.php
│ └── InvalidArgumentException.php
│ ├── TMobileDetect.php
│ ├── Events
│ ├── OnResponseHandler.php
│ └── OnRequestHandler.php
│ ├── MobileDetect.php
│ ├── Templating
│ └── Helpers.php
│ ├── Helpers
│ ├── CookieSettings.php
│ └── DeviceView.php
│ ├── Diagnostics
│ └── Panel.php
│ ├── DI
│ └── MobileDetectExtension.php
│ └── Latte
│ └── Macros.php
├── .travis.composer.php
├── .scrutinizer.yml
├── composer.json
├── readme.md
├── license.md
└── docs
└── en
└── index.md
/tests/tmp/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.*
--------------------------------------------------------------------------------
/tests/php.ini-unix:
--------------------------------------------------------------------------------
1 | extension = xdebug.so
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | composer.lock
2 | vendor
3 | tests/temp
4 |
--------------------------------------------------------------------------------
/tests/IPubTests/.gitignore:
--------------------------------------------------------------------------------
1 | coverage.dat
2 | *.actual
3 | *.expected
4 |
--------------------------------------------------------------------------------
/tests/php.ini-win:
--------------------------------------------------------------------------------
1 | date.timezone = Europe/Prague
2 |
3 | [PHP]
4 | extension_dir = "./ext"
5 | extension=php_xdebug.dll
6 |
--------------------------------------------------------------------------------
/tests/IPubTests/MobileDetect/files/presenters.neon:
--------------------------------------------------------------------------------
1 | application:
2 | mapping:
3 | *: IPubTests\MobileDetect\*Presenter
4 |
5 | services:
6 | # Test presenter
7 | presenters.test:
8 | class: IPubTests\MobileDetect\TestPresenter
9 |
10 | router: IPubTests\MobileDetect\Libs\RouterFactory::createRouter
11 |
--------------------------------------------------------------------------------
/tests/IPubTests/MobileDetect/files/config.neon:
--------------------------------------------------------------------------------
1 | mobileDetect:
2 | redirect:
3 | mobile:
4 | isEnabled : true
5 | host : http://m.site.com
6 | statusCode : 301
7 | action : redirect
8 | tablet:
9 | isEnabled : true
10 | host : http://t.site.com
11 | statusCode : 301
12 | action : redirect
13 | detectTabletAsMobile: true
14 | switchDeviceView:
15 | saveRefererPath: true
--------------------------------------------------------------------------------
/tests/IPubTests/MobileDetect/templates/default.latte:
--------------------------------------------------------------------------------
1 | {isMobile}
2 |
Mobile device
3 | {/isMobile}
4 | {isTablet}
5 | Table device
6 | {/isTablet}
7 |
8 | {isPhone}
9 | Phone device
10 | {/isPhone}
11 |
12 | {isMobileDevice iPhone}
13 | iPhone
14 | {/isMobileDevice}
15 |
16 | {isMobileOs iOS}
17 | iOS
18 | {/isMobileOs}
19 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | env:
4 | - NETTE=default
5 | - NETTE=~3.0.0
6 |
7 | php:
8 | - 7.2
9 | - 7.3
10 |
11 | before_install:
12 | - composer self-update
13 |
14 | before_script:
15 | - php .travis.composer.php
16 | - composer install --no-interaction --prefer-source --dev
17 |
18 | script:
19 | - vendor/bin/tester -s -p php -c ./tests/php.ini-unix tests
20 |
21 | after_failure:
22 | - 'for i in $(find ./tests -name \*.actual); do echo "--- $i"; cat $i; echo; echo; done'
23 |
--------------------------------------------------------------------------------
/src/IPub/MobileDetect/Exceptions/IException.php:
--------------------------------------------------------------------------------
1 |
8 | * @package iPublikuj:MobileDetect!
9 | * @subpackage Exceptions
10 | * @since 2.0.0
11 | *
12 | * @date 13.01.17
13 | */
14 |
15 | declare(strict_types = 1);
16 |
17 | namespace IPub\MobileDetect\Exceptions;
18 |
19 | interface IException
20 | {
21 | }
22 |
--------------------------------------------------------------------------------
/.travis.composer.php:
--------------------------------------------------------------------------------
1 |
8 | * @package iPublikuj:MobileDetect!
9 | * @subpackage Exceptions
10 | * @since 2.0.0
11 | *
12 | * @date 13.01.17
13 | */
14 |
15 | declare(strict_types = 1);
16 |
17 | namespace IPub\MobileDetect\Exceptions;
18 |
19 | use Latte;
20 |
21 | class CompileException extends Latte\CompileException implements IException
22 | {
23 | }
24 |
--------------------------------------------------------------------------------
/src/IPub/MobileDetect/Exceptions/InvalidArgumentException.php:
--------------------------------------------------------------------------------
1 |
8 | * @package iPublikuj:MobileDetect!
9 | * @subpackage Exceptions
10 | * @since 2.0.0
11 | *
12 | * @date 20.07.16
13 | */
14 |
15 | declare(strict_types = 1);
16 |
17 | namespace IPub\MobileDetect\Exceptions;
18 |
19 | class InvalidArgumentException extends \InvalidArgumentException implements IException
20 | {
21 | }
22 |
--------------------------------------------------------------------------------
/.scrutinizer.yml:
--------------------------------------------------------------------------------
1 | checks:
2 | php: true
3 |
4 | build:
5 | environment:
6 | php:
7 | version: 7.2
8 | variables:
9 | NETTE: default
10 |
11 | dependencies:
12 | before:
13 | -
14 | command: 'mkdir -p build/logs'
15 |
16 | tests:
17 | override:
18 | -
19 | command: 'vendor/bin/tester tests -p php -c ./tests/php.ini-unix --coverage build/logs/clover.xml --coverage-src src'
20 | coverage:
21 | file: build/logs/clover.xml
22 | format: php-clover
23 |
24 | filter:
25 | excluded_paths:
26 | - tests/*
27 |
28 | coding_style:
29 | php:
30 | indentation:
31 | general:
32 | use_tabs: true
33 | spaces:
34 | before_parentheses:
35 | closure_definition: true
36 |
--------------------------------------------------------------------------------
/tests/IPubTests/bootstrap.php:
--------------------------------------------------------------------------------
1 | run();
35 | }
36 |
--------------------------------------------------------------------------------
/tests/IPubTests/MobileDetect/libs/RouterFactory.php:
--------------------------------------------------------------------------------
1 |
9 | * @package iPublikuj:MobileDetect!
10 | * @subpackage Tests
11 | * @since 2.1.1
12 | *
13 | * @date 15.01.17
14 | */
15 |
16 | declare(strict_types = 1);
17 |
18 | namespace IPubTests\MobileDetect\Libs;
19 |
20 | use Nette\Application;
21 | use Nette\Application\Routers;
22 |
23 | /**
24 | * Simple routes factory
25 | *
26 | * @package iPublikuj:MobileDetect!
27 | * @subpackage Tests
28 | *
29 | * @author Adam Kadlec
30 | */
31 | class RouterFactory
32 | {
33 | /**
34 | * @return Application\IRouter
35 | */
36 | public static function createRouter() : Application\IRouter
37 | {
38 | $router = new Routers\RouteList();
39 | $router[] = new Routers\Route('/[/]', 'Test:default');
40 |
41 | return $router;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/IPub/MobileDetect/TMobileDetect.php:
--------------------------------------------------------------------------------
1 |
8 | * @package iPublikuj:MobileDetect!
9 | * @subpackage common
10 | * @since 1.0.0
11 | *
12 | * @date 24.04.14
13 | */
14 |
15 | declare(strict_types = 1);
16 |
17 | namespace IPub\MobileDetect;
18 |
19 | use IPub\MobileDetect\Helpers;
20 |
21 | /**
22 | * Mobile detect trait for presenters & components
23 | *
24 | * @package iPublikuj:MobileDetect!
25 | * @subpackage common
26 | *
27 | * @author Adam Kadlec
28 | */
29 | trait TMobileDetect
30 | {
31 | /**
32 | * @var MobileDetect
33 | */
34 | protected $mobileDetect;
35 |
36 | /**
37 | * @var Helpers\DeviceView
38 | */
39 | protected $deviceView;
40 |
41 | /**
42 | * @param MobileDetect $mobileDetect
43 | * @param Helpers\DeviceView $deviceView
44 | *
45 | * @return void
46 | */
47 | public function injectMobileDetector(MobileDetect $mobileDetect, Helpers\DeviceView $deviceView) : void
48 | {
49 | $this->mobileDetect = $mobileDetect;
50 | $this->deviceView = $deviceView;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/tests/IPubTests/MobileDetect/ExtensionTest.phpt:
--------------------------------------------------------------------------------
1 |
9 | * @package iPublikuj:MobileDetect!
10 | * @subpackage Tests
11 | * @since 1.0.0
12 | *
13 | * @date 10.01.15
14 | */
15 |
16 | declare(strict_types = 1);
17 |
18 | namespace IPubTests\MobileDetect;
19 |
20 | use Nette;
21 |
22 | use Tester;
23 | use Tester\Assert;
24 |
25 | use IPub\MobileDetect;
26 |
27 | require __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'bootstrap.php';
28 |
29 | class ExtensionTest extends Tester\TestCase
30 | {
31 | public function testFunctional() : void
32 | {
33 | $dic = $this->createContainer();
34 |
35 | Assert::true($dic->getService('mobileDetect.mobileDetect') instanceof MobileDetect\MobileDetect);
36 | Assert::true($dic->getService('mobileDetect.deviceView') instanceof MobileDetect\Helpers\DeviceView);
37 | Assert::true($dic->getService('mobileDetect.onRequestHandler') instanceof MobileDetect\Events\OnRequestHandler);
38 | Assert::true($dic->getService('mobileDetect.onResponseHandler') instanceof MobileDetect\Events\OnResponseHandler);
39 | }
40 |
41 | /**
42 | * @return Nette\DI\Container
43 | */
44 | protected function createContainer() : Nette\DI\Container
45 | {
46 | $config = new Nette\Configurator();
47 | $config->setTempDirectory(TEMP_DIR);
48 |
49 | MobileDetect\DI\MobileDetectExtension::register($config);
50 |
51 | $config->addConfig(__DIR__ . DS . 'files' . DS . 'config.neon');
52 |
53 | return $config->createContainer();
54 | }
55 | }
56 |
57 | \run(new ExtensionTest());
58 |
--------------------------------------------------------------------------------
/src/IPub/MobileDetect/Events/OnResponseHandler.php:
--------------------------------------------------------------------------------
1 |
8 | * @package iPublikuj:MobileDetect!
9 | * @subpackage Events
10 | * @since 1.0.0
11 | *
12 | * @date 23.04.14
13 | */
14 |
15 | declare(strict_types = 1);
16 |
17 | namespace IPub\MobileDetect\Events;
18 |
19 | use Nette\Application;
20 |
21 | use IPub\MobileDetect\Helpers\DeviceView;
22 |
23 | /**
24 | * On response event handler
25 | *
26 | * @package iPublikuj:MobileDetect!
27 | * @subpackage Events
28 | *
29 | * @author Adam Kadlec
30 | */
31 | final class OnResponseHandler
32 | {
33 | /**
34 | * @var bool
35 | */
36 | private $needModifyResponse = false;
37 |
38 | /**
39 | * @var DeviceView
40 | */
41 | private $deviceView;
42 |
43 | /**
44 | * @var \Closure
45 | */
46 | public $modifyResponseClosure;
47 |
48 | /**
49 | * @param DeviceView $deviceView
50 | */
51 | public function __construct(DeviceView $deviceView)
52 | {
53 | $this->deviceView = $deviceView;
54 | }
55 |
56 | /**
57 | * Stores information about modifying response
58 | *
59 | * @return void
60 | */
61 | public function needModifyResponse() : void
62 | {
63 | $this->needModifyResponse = true;
64 | }
65 |
66 | /**
67 | * @param Application\Application $application
68 | *
69 | * @return void
70 | */
71 | public function __invoke(Application\Application $application) : void
72 | {
73 | if ($this->needModifyResponse && $this->modifyResponseClosure instanceof \Closure) {
74 | $modifyClosure = $this->modifyResponseClosure;
75 | $modifyClosure($this->deviceView);
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/IPub/MobileDetect/MobileDetect.php:
--------------------------------------------------------------------------------
1 |
8 | * @package iPublikuj:MobileDetect!
9 | * @subpackage common
10 | * @since 1.0.0
11 | *
12 | * @date 21.04.14
13 | */
14 |
15 | declare(strict_types = 1);
16 |
17 | namespace IPub\MobileDetect;
18 |
19 | use Nette\Http;
20 |
21 | use IPub\MobileDetect\Helpers;
22 |
23 | use Jenssegers\Agent;
24 |
25 | /**
26 | * Mobile detect detector service
27 | *
28 | * @package iPublikuj:MobileDetect!
29 | * @subpackage common
30 | *
31 | * @author Adam Kadlec
32 | */
33 | final class MobileDetect extends Agent\Agent
34 | {
35 | /**
36 | * @var Helpers\DeviceView
37 | */
38 | private $deviceView;
39 |
40 | /**
41 | * @param Helpers\DeviceView $deviceView
42 | * @param Http\Request $httpRequest
43 | */
44 | public function __construct(
45 | Helpers\DeviceView $deviceView,
46 | Http\Request $httpRequest
47 | ) {
48 | // Get http headers
49 | $httpHeaders = $httpRequest->getHeaders();
50 |
51 | $userAgent = NULL;
52 |
53 | // If user agent info is set in headers...
54 | if (isset($httpHeaders['user-agent'])) {
55 | // ...set user agent details
56 | $userAgent = $httpHeaders['user-agent'];
57 | }
58 |
59 | parent::__construct($httpHeaders, $userAgent);
60 |
61 | $this->deviceView = $deviceView;
62 | }
63 |
64 | /**
65 | * Check if the device is not mobile phone
66 | *
67 | * @return bool
68 | */
69 | public function isNotPhone() : bool
70 | {
71 | return (($this->isMobile() && $this->isTablet()) || !$this->isMobile());
72 | }
73 |
74 | /**
75 | * @return string
76 | */
77 | public function view() : string
78 | {
79 | return $this->deviceView->getViewType();
80 | }
81 |
82 | /**
83 | * @return string
84 | */
85 | public function browserVersion() : string
86 | {
87 | return (string) $this->version($this->browser());
88 | }
89 |
90 | /**
91 | * @return string
92 | */
93 | public function platformVersion() : string
94 | {
95 | return (string) $this->version($this->platform());
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "ipub/mobile-detect",
3 | "type" : "library",
4 | "description" : "Extension for detecting mobile devices, managing mobile view types, redirect to mobile version for Nette Framework",
5 | "keywords" : ["nette", "mobile", "mobile detect", "mobile view managing", "mobile redirect", "ipub", "ipublikuj", "framework", "tools"],
6 | "homepage" : "https://github.com/iPublikuj/mobile-detect",
7 | "license" : ["GPL-2.0", "GPL-3.0"],
8 |
9 | "authors": [
10 | {
11 | "name" : "iPublikuj:cms",
12 | "email" : "info@ipublikuj.eu",
13 | "homepage" : "https://www.ipublikuj.eu/"
14 | }
15 | ],
16 |
17 | "support":{
18 | "email" :"support@ipublikuj.eu",
19 | "issues" :"https://github.com/iPublikuj/mobile-detect/issues"
20 | },
21 |
22 | "extra": {
23 | "ipub" : {
24 | "configuration" : {
25 | "extensions" : {
26 | "mobileDetect" : "IPub\\MobileDetect\\DI\\MobileDetectExtension"
27 | }
28 | },
29 | "mobileDetect" : {
30 | "redirect" : {
31 | "mobile" : {
32 | "isEnabled" : false,
33 | "host" : null,
34 | "statusCode" : 301,
35 | "action" : "noRedirect"
36 | },
37 | "phone" : {
38 | "isEnabled" : false,
39 | "host" : null,
40 | "statusCode" : 301,
41 | "action" : "noRedirect"
42 | },
43 | "tablet" : {
44 | "isEnabled" : false,
45 | "host" : null,
46 | "statusCode" : 301,
47 | "action" : "noRedirect"
48 | },
49 | "detectPhoneAsMobile" : false,
50 | "detectTabletAsMobile" : false
51 | },
52 | "switchDeviceView" : {
53 | "saveRefererPath" : true
54 | }
55 | }
56 | }
57 | },
58 |
59 | "require": {
60 | "php" : ">=7.2.0",
61 |
62 | "nette/application" : "~3.0",
63 | "nette/di" : "~3.0",
64 | "nette/http" : "~3.0",
65 | "nette/utils" : "~3.0",
66 |
67 | "latte/latte" : "~2.5",
68 |
69 | "jenssegers/agent" : "~2.5"
70 | },
71 |
72 | "require-dev": {
73 | "nette/bootstrap" : "~3.0",
74 | "nette/mail" : "~3.0",
75 | "nette/robot-loader" : "~3.0",
76 | "nette/safe-stream" : "~2.4",
77 | "nette/tester" : "~2.3",
78 |
79 | "tracy/tracy" : "~2.6",
80 |
81 | "pds/skeleton" : "~1.0"
82 | },
83 |
84 | "autoload": {
85 | "psr-0": {
86 | "IPub\\MobileDetect\\": "src/"
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # MobileDetect
2 |
3 | [](https://travis-ci.org/iPublikuj/mobile-detect)
4 | [](https://scrutinizer-ci.com/g/iPublikuj/mobile-detect/?branch=master)
5 | [](https://scrutinizer-ci.com/g/iPublikuj/mobile-detect/?branch=master)
6 | [](https://packagist.org/packages/ipub/mobile-detect)
7 | [](https://packagist.org/packages/ipub/mobile-detect)
8 | [](https://packagist.org/packages/ipub/mobile-detect)
9 |
10 | Extension for detecting mobile devices, managing mobile view types, redirect to mobile version for [Nette Framework](http://nette.org/)
11 |
12 | ## Introduction
13 |
14 | This extension use [Mobile_Detect](https://github.com/serbanghita/Mobile-Detect) class and provides the following features:
15 |
16 | * Detect the various mobile devices by name, OS, browser User-Agent
17 | * Manages site views for the variuos mobile devices (`mobile`, `phone`, `tablet`, `full`)
18 | * Redirects to mobile and tablet sites
19 |
20 | ## Installation
21 |
22 | The best way to install ipub/mobile-detect is using [Composer](http://getcomposer.org/):
23 |
24 | ```sh
25 | $ composer require ipub/mobile-detect
26 | ```
27 |
28 | After that you have to register extension in config.neon.
29 |
30 | ```neon
31 | extensions:
32 | mobileDetect: IPub\MobileDetect\DI\MobileDetectExtension
33 | ```
34 |
35 | Package contains trait, which you will have to use in class, where you want to use mobile detector.
36 |
37 | ```php
38 |
9 | * @package iPublikuj:MobileDetect!
10 | * @subpackage Tests
11 | * @since 1.0.0
12 | *
13 | * @date 10.01.15
14 | */
15 |
16 | declare(strict_types = 1);
17 |
18 | namespace IPubTests\MobileDetect;
19 |
20 | use Nette;
21 |
22 | use Tester;
23 | use Tester\Assert;
24 |
25 | use IPub\MobileDetect;
26 | use IPub\MobileDetect\Helpers;
27 |
28 | require __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'bootstrap.php';
29 |
30 | class DeviceViewTest extends Tester\TestCase
31 | {
32 | public function testRequestHasSwitchParam() : void
33 | {
34 | $query = [
35 | 'myparam' => 'myvalue',
36 | 'device_view' => Helpers\DeviceView::VIEW_MOBILE
37 | ];
38 |
39 | // Get helper
40 | $deviceView = $this->getHelper($query);
41 |
42 | Assert::true($deviceView->hasSwitchParameter());
43 | Assert::equal(Helpers\DeviceView::VIEW_MOBILE, $deviceView->getSwitchParameterValue());
44 | }
45 |
46 | public function testDeviceIsMobile() : void
47 | {
48 | $query = [
49 | 'myparam' => 'myvalue',
50 | 'device_view' => Helpers\DeviceView::VIEW_MOBILE
51 | ];
52 |
53 | // Get helper
54 | $deviceView = $this->getHelper($query);
55 |
56 | Assert::equal(Helpers\DeviceView::VIEW_MOBILE, $deviceView->getViewType());
57 | Assert::true($deviceView->isMobileView());
58 | Assert::false($deviceView->isFullView());
59 | }
60 |
61 | public function testMobileViewType() : void
62 | {
63 | $query = [
64 | 'myparam' => 'myvalue',
65 | 'device_view' => Helpers\DeviceView::VIEW_MOBILE
66 | ];
67 |
68 | // Get helper
69 | $deviceView = $this->getHelper($query);
70 |
71 | Assert::equal(Helpers\DeviceView::VIEW_MOBILE, $deviceView->getViewType());
72 | }
73 |
74 | public function testSetMobileViewType() : void
75 | {
76 | $query = [
77 | 'myparam' => 'myvalue',
78 | 'device_view' => Helpers\DeviceView::VIEW_MOBILE
79 | ];
80 |
81 | // Get helper
82 | $deviceView = $this->getHelper($query);
83 | $deviceView->setTabletView();
84 |
85 | Assert::notEqual(Helpers\DeviceView::VIEW_MOBILE, $deviceView->getViewType());
86 | }
87 |
88 | /**
89 | * Create DeviceView helper
90 | *
91 | * @param array $query
92 | *
93 | * @return Helpers\DeviceView
94 | */
95 | private function getHelper($query = []) : Helpers\DeviceView
96 | {
97 | $url = new Nette\Http\Url('https://www.ipublikuj.eu');
98 | $url->setQuery($query);
99 |
100 | $urlScript = new Nette\Http\UrlScript($url);
101 |
102 | $httpRequest = new Nette\Http\Request($urlScript);
103 | $httpResponse = new Nette\Http\Response();
104 |
105 | $cookieSettings = new Helpers\CookieSettings('device_view', NULL, '+1 month', '/', false, true);
106 |
107 | // Get helper
108 | return new Helpers\DeviceView('device_view', $cookieSettings, $httpRequest, $httpResponse);
109 | }
110 | }
111 |
112 | \run(new DeviceViewTest());
113 |
--------------------------------------------------------------------------------
/tests/IPubTests/MobileDetect/MobileDetectTest.phpt:
--------------------------------------------------------------------------------
1 |
9 | * @package iPublikuj:MobileDetect!
10 | * @subpackage Tests
11 | * @since 1.0.0
12 | *
13 | * @date 10.01.15
14 | */
15 |
16 | declare(strict_types = 1);
17 |
18 | namespace IPubTests\MobileDetect;
19 |
20 | use Nette;
21 |
22 | use Tester;
23 | use Tester\Assert;
24 |
25 | use IPub\MobileDetect;
26 |
27 | require __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'bootstrap.php';
28 |
29 | class MobileDetectTest extends Tester\TestCase
30 | {
31 | /**
32 | * @var MobileDetect\MobileDetect
33 | */
34 | private $mobileDetector;
35 |
36 | /**
37 | * {@inheritdoc}
38 | */
39 | public function setUp() : void
40 | {
41 | parent::setUp();
42 |
43 | $dic = $this->createContainer();
44 |
45 | // Get extension services
46 | $this->mobileDetector = $dic->getService('mobileDetect.mobileDetect');
47 | }
48 |
49 | public function testBasicMethods() : void
50 | {
51 | $this->mobileDetector->setHttpHeaders([
52 | 'SERVER_SOFTWARE' => 'Apache/2.2.15 (Linux) Whatever/4.0 PHP/5.2.13',
53 | 'REQUEST_METHOD' => 'POST',
54 | 'HTTP_HOST' => 'home.ghita.org',
55 | 'HTTP_X_REAL_IP' => '1.2.3.4',
56 | 'HTTP_X_FORWARDED_FOR' => '1.2.3.5',
57 | 'HTTP_CONNECTION' => 'close',
58 | 'HTTP_USER_AGENT' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 6_0_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A523 Safari/8536.25',
59 | 'HTTP_ACCEPT' => 'text/vnd.wap.wml, application/json, text/javascript, */*; q=0.01',
60 | 'HTTP_ACCEPT_LANGUAGE' => 'en-us,en;q=0.5',
61 | 'HTTP_ACCEPT_ENCODING' => 'gzip, deflate',
62 | 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest',
63 | 'HTTP_REFERER' => 'http://ipublikuj.eu',
64 | 'HTTP_PRAGMA' => 'no-cache',
65 | 'HTTP_CACHE_CONTROL' => 'no-cache',
66 | 'REMOTE_ADDR' => '11.22.33.44',
67 | 'REQUEST_TIME' => '01-10-2012 07:57'
68 | ]);
69 |
70 | Assert::true($this->mobileDetector->isMobile());
71 | Assert::false($this->mobileDetector->isTablet());
72 |
73 | Assert::false($this->mobileDetector->isiphone());
74 | Assert::false($this->mobileDetector->isiOS());
75 |
76 | $this->mobileDetector->setUserAgent('Mozilla/5.0 (iPhone; CPU iPhone OS 6_0_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A523 Safari/8536.25');
77 |
78 | Assert::true($this->mobileDetector->isiphone());
79 | Assert::true($this->mobileDetector->isiOS());
80 | Assert::true($this->mobileDetector->isios());
81 | Assert::true($this->mobileDetector->is('iphone'));
82 | Assert::true($this->mobileDetector->is('ios'));
83 | }
84 |
85 | /**
86 | * @return Nette\DI\Container
87 | */
88 | protected function createContainer() : Nette\DI\Container
89 | {
90 | $config = new Nette\Configurator();
91 | $config->setTempDirectory(TEMP_DIR);
92 |
93 | MobileDetect\DI\MobileDetectExtension::register($config);
94 |
95 | $config->addConfig(__DIR__ . DS . 'files' . DS . 'config.neon');
96 |
97 | return $config->createContainer();
98 | }
99 | }
100 |
101 | \run(new MobileDetectTest());
102 |
--------------------------------------------------------------------------------
/src/IPub/MobileDetect/Templating/Helpers.php:
--------------------------------------------------------------------------------
1 |
8 | * @package iPublikuj:MobileDetect!
9 | * @subpackage Templating
10 | * @since 1.0.0
11 | *
12 | * @date 16.06.14
13 | */
14 |
15 | declare(strict_types = 1);
16 |
17 | namespace IPub\MobileDetect\Templating;
18 |
19 | use Nette;
20 |
21 | use IPub\MobileDetect;
22 |
23 | /**
24 | * Mobile detect template helpers
25 | *
26 | * @package iPublikuj:MobileDetect!
27 | * @subpackage Templating
28 | *
29 | * @author Adam Kadlec
30 | */
31 | final class Helpers
32 | {
33 | /**
34 | * Implement nette smart magic
35 | */
36 | use Nette\SmartObject;
37 |
38 | /**
39 | * @var MobileDetect\MobileDetect
40 | */
41 | private $mobileDetect;
42 |
43 | /**
44 | * @var MobileDetect\Helpers\DeviceView
45 | */
46 | private $deviceView;
47 |
48 | /**
49 | * @param MobileDetect\MobileDetect $mobileDetect
50 | * @param MobileDetect\Helpers\DeviceView $deviceView
51 | */
52 | public function __construct(
53 | MobileDetect\MobileDetect $mobileDetect,
54 | MobileDetect\Helpers\DeviceView $deviceView
55 | ) {
56 | $this->mobileDetect = $mobileDetect;
57 | $this->deviceView = $deviceView;
58 | }
59 |
60 | /**
61 | * @return MobileDetect\MobileDetect
62 | */
63 | public function getMobileDetectService() : MobileDetect\MobileDetect
64 | {
65 | return $this->mobileDetect;
66 | }
67 |
68 | /**
69 | * @return MobileDetect\Helpers\DeviceView
70 | */
71 | public function getDeviceViewService() : MobileDetect\Helpers\DeviceView
72 | {
73 | return $this->deviceView;
74 | }
75 |
76 | /**
77 | * @return bool
78 | */
79 | public function isMobile() : bool
80 | {
81 | return $this->mobileDetect->isMobile();
82 | }
83 |
84 | /**
85 | * @return bool
86 | */
87 | public function isPhone() : bool
88 | {
89 | return $this->mobileDetect->isPhone();
90 | }
91 |
92 | /**
93 | * @return bool
94 | */
95 | public function isTablet() : bool
96 | {
97 | return $this->mobileDetect->isTablet();
98 | }
99 |
100 | /**
101 | * @param string $device
102 | *
103 | * @return bool
104 | */
105 | public function isDevice(string $device) : bool
106 | {
107 | return $this->mobileDetect->is($device);
108 | }
109 |
110 | /**
111 | * @param string $os
112 | *
113 | * @return bool
114 | */
115 | public function isOs(string $os) : bool
116 | {
117 | return $this->mobileDetect->is($os);
118 | }
119 |
120 | /**
121 | * @return bool
122 | */
123 | public function isFullView() : bool
124 | {
125 | return $this->deviceView->isFullView();
126 | }
127 |
128 | /**
129 | * @return bool
130 | */
131 | public function isMobileView() : bool
132 | {
133 | return $this->deviceView->isMobileView();
134 | }
135 |
136 | /**
137 | * @return bool
138 | */
139 | public function isPhoneView() : bool
140 | {
141 | return $this->deviceView->isPhoneView();
142 | }
143 |
144 | /**
145 | * @return bool
146 | */
147 | public function isTabletView() : bool
148 | {
149 | return $this->deviceView->isTabletView();
150 | }
151 |
152 | /**
153 | * @return bool
154 | */
155 | public function isNotMobileView() : bool
156 | {
157 | return $this->deviceView->isNotMobileView();
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/src/IPub/MobileDetect/Helpers/CookieSettings.php:
--------------------------------------------------------------------------------
1 |
8 | * @package iPublikuj:MobileDetect!
9 | * @subpackage Helpers
10 | * @since 1.0.0
11 | *
12 | * @date 23.04.14
13 | */
14 |
15 | declare(strict_types = 1);
16 |
17 | namespace IPub\MobileDetect\Helpers;
18 |
19 | use Nette;
20 |
21 | use IPub\MobileDetect\Exceptions;
22 |
23 | /**
24 | * Cookies creator helper
25 | *
26 | * @package iPublikuj:MobileDetect!
27 | * @subpackage Helpers
28 | *
29 | * @author Adam Kadlec
30 | */
31 | final class CookieSettings
32 | {
33 | /**
34 | * Implement nette smart magic
35 | */
36 | use Nette\SmartObject;
37 |
38 | /**
39 | * @var string
40 | */
41 | private $name;
42 |
43 | /**
44 | * @var string|NULL
45 | */
46 | private $domain;
47 |
48 | /**
49 | * @var string
50 | */
51 | private $expire;
52 |
53 | /**
54 | * @var string
55 | */
56 | private $path;
57 |
58 | /**
59 | * @var bool
60 | */
61 | private $secure;
62 |
63 | /**
64 | * @var bool
65 | */
66 | private $httpOnly;
67 |
68 | /**
69 | * @param string $name The name of the cookie
70 | * @param string $expireAfter The time the cookie expires
71 | * @param string $path The path on the server in which the cookie will be available on
72 | * @param string $domain The domain that the cookie is available to
73 | * @param bool $secure Whether the cookie should only be transmitted over a secure HTTPS connection from the client
74 | * @param bool $httpOnly Whether the cookie will be made accessible only through the HTTP protocol
75 | *
76 | * @throws Exceptions\InvalidArgumentException
77 | */
78 | public function __construct(string $name, ?string $domain = null, ?string $expireAfter = null, string $path = '/', bool $secure = false, bool $httpOnly = true)
79 | {
80 | // from PHP source code
81 | if (preg_match("/[=,; \t\r\n\013\014]/", $name)) {
82 | throw new Exceptions\InvalidArgumentException(sprintf('The cookie name "%s" contains invalid characters.', $name));
83 | }
84 |
85 | if (empty($name)) {
86 | throw new Exceptions\InvalidArgumentException('The cookie name cannot be empty.');
87 | }
88 |
89 | $expire = new \DateTime;
90 |
91 | if ($expireAfter !== null) {
92 | $expire->modify($expireAfter);
93 | }
94 |
95 | $this->name = $name;
96 | $this->domain = $domain;
97 | $this->expire = (int) $expire->format('U');
98 | $this->path = empty($path) ? '/' : $path;
99 | $this->secure = $secure;
100 | $this->httpOnly = $httpOnly;
101 | }
102 |
103 | /**
104 | * Gets the name of the cookie
105 | *
106 | * @return string
107 | */
108 | public function getName() : string
109 | {
110 | return $this->name;
111 | }
112 |
113 | /**
114 | * Gets the domain that the cookie is available to
115 | *
116 | * @return string|NULL
117 | */
118 | public function getDomain() : ?string
119 | {
120 | return $this->domain;
121 | }
122 |
123 | /**
124 | * Gets the time the cookie expires
125 | *
126 | * @return int
127 | */
128 | public function getExpiresTime() : int
129 | {
130 | return $this->expire;
131 | }
132 |
133 | /**
134 | * Gets the path on the server in which the cookie will be available on
135 | *
136 | * @return string
137 | */
138 | public function getPath() : string
139 | {
140 | return $this->path;
141 | }
142 |
143 | /**
144 | * Checks whether the cookie should only be transmitted over a secure HTTPS connection from the client
145 | *
146 | * @return bool
147 | */
148 | public function isSecure() : bool
149 | {
150 | return $this->secure;
151 | }
152 |
153 | /**
154 | * Checks whether the cookie will be made accessible only through the HTTP protocol
155 | *
156 | * @return bool
157 | */
158 | public function isHttpOnly() : bool
159 | {
160 | return $this->httpOnly;
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/src/IPub/MobileDetect/Diagnostics/Panel.php:
--------------------------------------------------------------------------------
1 |
8 | * @package iPublikuj:MobileDetect!
9 | * @subpackage Diagnostics
10 | * @since 1.0.0
11 | *
12 | * @date 21.04.14
13 | */
14 |
15 | declare(strict_types = 1);
16 |
17 | namespace IPub\MobileDetect\Diagnostics;
18 |
19 | use Nette;
20 |
21 | use Tracy;
22 |
23 | use IPub\MobileDetect;
24 |
25 | /**
26 | * Mobile device detect tracy panel
27 | *
28 | * @package iPublikuj:MobileDetect!
29 | * @subpackage Diagnostics
30 | *
31 | * @author Václav Pelíšek
32 | */
33 | final class Panel implements Tracy\IBarPanel
34 | {
35 | /**
36 | * Implement nette smart magic
37 | */
38 | use Nette\SmartObject;
39 |
40 | /** @var MobileDetect\MobileDetect
41 | */
42 | private $mobileDetect;
43 |
44 | /**
45 | * @param MobileDetect\MobileDetect $mobileDetect
46 | *
47 | * @return self
48 | */
49 | public function register(MobileDetect\MobileDetect $mobileDetect) : self
50 | {
51 | $this->mobileDetect = $mobileDetect;
52 |
53 | Tracy\Debugger::getBar()->addPanel($this, 'ipub.mobileDetect');
54 |
55 | return $this;
56 | }
57 |
58 | /**
59 | * Renders HTML code for custom tab
60 | *
61 | * @return string
62 | */
63 | public function getTab()
64 | {
65 | return '
'
66 | . $this->mobileDetect->view() . ' / ' . $this->mobileDetect->platform() . '';
67 | }
68 |
69 | /**
70 | * Renders HTML code for custom panel
71 | *
72 | * @return string
73 | */
74 | public function getPanel()
75 | {
76 | $h = 'htmlSpecialChars';
77 |
78 | $panel = [];
79 |
80 | $panel[] = 'Original User agent header
';
81 | $panel[] = '' . $h($this->mobileDetect->getUserAgent()) . '
';
82 |
83 | $properties = ['view', 'platform', 'platformVersion', 'device', 'browser', 'browserVersion'];
84 |
85 | $panel[] = '';
86 | foreach ($properties as $property) {
87 | $panel[] = '| ' . ucfirst($property) . ' | ' . $h($this->mobileDetect->{$property}() ?: '') . ' |
';
88 | }
89 | $panel[] = '
';
90 |
91 | return empty($panel) ? '' :
92 | 'View: ' . $this->mobileDetect->view() . ', OS: ' . $this->mobileDetect->platform() . '
' .
93 | '' . implode($panel) . '
' .
94 | '';
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/tests/IPubTests/MobileDetect/TemplateTest.phpt:
--------------------------------------------------------------------------------
1 |
9 | * @package iPublikuj:MobileDetect!
10 | * @subpackage Tests
11 | * @since 1.0.0
12 | *
13 | * @date 15.01.17
14 | */
15 |
16 | declare(strict_types = 1);
17 |
18 | namespace IPubTests\MobileDetect;
19 |
20 | use Nette;
21 | use Nette\Application;
22 | use Nette\Application\Routers;
23 | use Nette\Application\UI;
24 | use Nette\Utils;
25 |
26 | use Tester;
27 | use Tester\Assert;
28 |
29 | use IPub\MobileDetect;
30 | use IPub\MobileDetect\Helpers;
31 |
32 | require __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'bootstrap.php';
33 | require __DIR__ . DS . 'libs' . DS . 'RouterFactory.php';
34 |
35 | class TemplateTest extends Tester\TestCase
36 | {
37 | /**
38 | * @var Application\IPresenterFactory
39 | */
40 | private $presenterFactory;
41 |
42 | /**
43 | * @var Nette\DI\Container
44 | */
45 | private $container;
46 |
47 | /**
48 | * @var MobileDetect\MobileDetect
49 | */
50 | private $mobileDetector;
51 |
52 | /**
53 | * {@inheritdoc}
54 | */
55 | public function setUp() : void
56 | {
57 | parent::setUp();
58 |
59 | $this->container = $this->createContainer();
60 |
61 | // Get presenter factory from container
62 | $this->presenterFactory = $this->container->getByType(Application\IPresenterFactory::class);
63 |
64 | // Get device view service
65 | $this->mobileDetector = $this->container->getByType(MobileDetect\MobileDetect::class);
66 |
67 | $this->mobileDetector->setHttpHeaders([
68 | 'SERVER_SOFTWARE' => 'Apache/2.2.15 (Linux) Whatever/4.0 PHP/5.2.13',
69 | 'REQUEST_METHOD' => 'POST',
70 | 'HTTP_HOST' => 'home.ghita.org',
71 | 'HTTP_X_REAL_IP' => '1.2.3.4',
72 | 'HTTP_X_FORWARDED_FOR' => '1.2.3.5',
73 | 'HTTP_CONNECTION' => 'close',
74 | 'HTTP_USER_AGENT' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 6_0_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A523 Safari/8536.25',
75 | 'HTTP_ACCEPT' => 'text/vnd.wap.wml, application/json, text/javascript, */*; q=0.01',
76 | 'HTTP_ACCEPT_LANGUAGE' => 'en-us,en;q=0.5',
77 | 'HTTP_ACCEPT_ENCODING' => 'gzip, deflate',
78 | 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest',
79 | 'HTTP_REFERER' => 'http://ipublikuj.eu',
80 | 'HTTP_PRAGMA' => 'no-cache',
81 | 'HTTP_CACHE_CONTROL' => 'no-cache',
82 | 'REMOTE_ADDR' => '11.22.33.44',
83 | 'REQUEST_TIME' => '01-10-2012 07:57'
84 | ]);
85 | }
86 |
87 | public function testMobileVersion() : void
88 | {
89 | // Create test presenter
90 | $presenter = $this->createPresenter();
91 |
92 | // Create GET request
93 | $request = new Application\Request('Test', 'GET', ['action' => 'default']);
94 | // & fire presenter & catch response
95 | $response = $presenter->run($request);
96 |
97 | $dq = Tester\DomQuery::fromHtml((string) $response->getSource());
98 |
99 | Assert::true($dq->has('div[id*="mobileDevice"]'));
100 | Assert::true($dq->has('div[id*="phoneDevice"]'));
101 | Assert::false($dq->has('div[id*="tableDevice"]'));
102 | }
103 |
104 | public function testPhoneVersion() : void
105 | {
106 | $this->mobileDetector->setUserAgent('Mozilla/5.0 (iPhone; CPU iPhone OS 6_0_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A523 Safari/8536.25');
107 |
108 | // Create test presenter
109 | $presenter = $this->createPresenter();
110 |
111 | // Create GET request
112 | $request = new Application\Request('Test', 'GET', ['action' => 'default']);
113 | // & fire presenter & catch response
114 | $response = $presenter->run($request);
115 |
116 | $dq = Tester\DomQuery::fromHtml((string) $response->getSource());
117 |
118 | Assert::true($dq->has('div[id*="mobileDevice"]'));
119 | Assert::true($dq->has('div[id*="phoneDevice"]'));
120 | Assert::true($dq->has('div[id*="mobileDeviceType"]'));
121 | Assert::true($dq->has('div[id*="mobileDeviceOs"]'));
122 | Assert::false($dq->has('div[id*="tableDevice"]'));
123 | }
124 |
125 | /**
126 | * @return Application\IPresenter
127 | */
128 | private function createPresenter() : Application\IPresenter
129 | {
130 | // Create test presenter
131 | $presenter = $this->presenterFactory->createPresenter('Test');
132 | // Disable auto canonicalize to prevent redirection
133 | $presenter->autoCanonicalize = FALSE;
134 |
135 | return $presenter;
136 | }
137 |
138 | /**
139 | * @return Nette\DI\Container
140 | */
141 | private function createContainer() : Nette\DI\Container
142 | {
143 | $config = new Nette\Configurator();
144 | $config->setTempDirectory(TEMP_DIR);
145 |
146 | MobileDetect\DI\MobileDetectExtension::register($config);
147 |
148 | $config->addConfig(__DIR__ . DS . 'files' . DS . 'config.neon');
149 |
150 | $version = getenv('NETTE');
151 |
152 | $config->addConfig(__DIR__ . DS . 'files' . DS . 'presenters.neon');
153 |
154 | return $config->createContainer();
155 | }
156 | }
157 |
158 | class TestPresenter extends UI\Presenter
159 | {
160 | use MobileDetect\TMobileDetect;
161 |
162 | public function renderDefault() : void
163 | {
164 | // Set template for component testing
165 | $this->template->setFile(__DIR__ . DIRECTORY_SEPARATOR . 'templates' . DIRECTORY_SEPARATOR . 'default.latte');
166 | }
167 | }
168 |
169 | \run(new TemplateTest());
170 |
--------------------------------------------------------------------------------
/src/IPub/MobileDetect/DI/MobileDetectExtension.php:
--------------------------------------------------------------------------------
1 |
8 | * @package iPublikuj:MobileDetect!
9 | * @subpackage DI
10 | * @since 1.0.0
11 | *
12 | * @date 21.04.14
13 | */
14 |
15 | declare(strict_types = 1);
16 |
17 | namespace IPub\MobileDetect\DI;
18 |
19 | use Nette;
20 | use Nette\Bridges;
21 | use Nette\DI;
22 |
23 | use Tracy;
24 |
25 | use IPub\MobileDetect;
26 | use IPub\MobileDetect\Diagnostics;
27 | use IPub\MobileDetect\Events;
28 | use IPub\MobileDetect\Helpers;
29 | use IPub\MobileDetect\Templating;
30 |
31 | /**
32 | * Mobile device detect extension container
33 | *
34 | * @package iPublikuj:MobileDetect!
35 | * @subpackage DI
36 | *
37 | * @author Adam Kadlec
38 | */
39 | final class MobileDetectExtension extends DI\CompilerExtension
40 | {
41 | /**
42 | * @var array
43 | */
44 | private $defaults = [
45 | 'redirect' => [
46 | 'mobile' => [
47 | 'isEnabled' => false,
48 | 'host' => null,
49 | 'statusCode' => 301,
50 | 'action' => 'noRedirect', // redirect/noRedirect/redirectWithoutPath
51 | ],
52 | 'phone' => [
53 | 'isEnabled' => false,
54 | 'host' => null,
55 | 'statusCode' => 301,
56 | 'action' => 'noRedirect', // redirect/noRedirect/redirectWithoutPath
57 | ],
58 | 'tablet' => [
59 | 'isEnabled' => false,
60 | 'host' => null,
61 | 'statusCode' => 301,
62 | 'action' => 'noRedirect', // redirect/noRedirect/redirectWithoutPath
63 | ],
64 | 'detectPhoneAsMobile' => false,
65 | 'detectTabletAsMobile' => false,
66 | ],
67 | 'switchDeviceView' => [
68 | 'saveRefererPath' => true
69 | ],
70 | 'switchParameterName' => 'device_view',
71 | 'deviceViewCookie' => [
72 | 'name' => 'device_view',
73 | 'domain' => null,
74 | 'expireAfter' => '+1 month',
75 | 'path' => '/',
76 | 'secure' => false,
77 | 'httpOnly' => true,
78 | ],
79 | 'debugger' => '%debugMode%'
80 | ];
81 |
82 | /**
83 | * @return void
84 | */
85 | public function loadConfiguration() : void
86 | {
87 | // Get container builder
88 | $builder = $this->getContainerBuilder();
89 |
90 | // Set the default configuration
91 | $this->validateConfig($this->defaults);
92 |
93 | // Get extension configuration
94 | $configuration = $this->getConfig();
95 |
96 | // Install mobile detect service
97 | $mobileDetect = $builder->addDefinition($this->prefix('mobileDetect'))
98 | ->setType(MobileDetect\MobileDetect::class);
99 |
100 | $builder->addDefinition($this->prefix('deviceView'))
101 | ->setType(Helpers\DeviceView::class)
102 | ->setArguments(['setSwitchParameterName' => $configuration['switchParameterName']]);
103 |
104 | $builder->addDefinition($this->prefix('cookieSettings'))
105 | ->setType(Helpers\CookieSettings::class)
106 | ->setArguments([
107 | 'name' => $configuration['deviceViewCookie']['name'],
108 | 'domain' => $configuration['deviceViewCookie']['domain'],
109 | 'expireAfter' => $configuration['deviceViewCookie']['expireAfter'],
110 | 'path' => $configuration['deviceViewCookie']['path'],
111 | 'secure' => $configuration['deviceViewCookie']['secure'],
112 | 'httpOnly' => $configuration['deviceViewCookie']['httpOnly'],
113 | ]);
114 |
115 | if ($configuration['debugger'] && interface_exists(Tracy\IBarPanel::class)) {
116 | $builder->addDefinition($this->prefix('panel'))
117 | ->setType(Diagnostics\Panel::class);
118 |
119 | $mobileDetect->addSetup('?->register(?)', [$this->prefix('@panel'), '@self']);
120 | }
121 |
122 | $builder->addDefinition($this->prefix('onRequestHandler'))
123 | ->setType(Events\OnRequestHandler::class)
124 | ->addSetup('$redirectConf', [$configuration['redirect']])
125 | ->addSetup('$isFullPath', [$configuration['switchDeviceView']['saveRefererPath']]);
126 |
127 | $builder->addDefinition($this->prefix('onResponseHandler'))
128 | ->setType(Events\OnResponseHandler::class);
129 |
130 | // Register template helpers
131 | $builder->addDefinition($this->prefix('helpers'))
132 | ->setType(Templating\Helpers::class)
133 | ->setAutowired(FALSE);
134 |
135 | $application = $builder->getDefinition('application');
136 | $application->addSetup('$service->onRequest[] = ?', ['@' . $this->prefix('onRequestHandler')]);
137 | $application->addSetup('$service->onResponse[] = ?', ['@' . $this->prefix('onResponseHandler')]);
138 | }
139 |
140 | /**
141 | * {@inheritdoc}
142 | */
143 | public function beforeCompile() : void
144 | {
145 | parent::beforeCompile();
146 |
147 | $builder = $this->getContainerBuilder();
148 |
149 | // Install extension latte macros
150 | $latteFactory = $builder->getDefinition($builder->getByType(Bridges\ApplicationLatte\ILatteFactory::class) ?: 'nette.latteFactory');
151 |
152 | $latteFactory->getResultDefinition()
153 | ->addSetup('IPub\MobileDetect\Latte\Macros::install(?->getCompiler())', ['@self'])
154 | ->addSetup('addFilter', ['isMobile', [$this->prefix('@helpers'), 'isMobile']])
155 | ->addSetup('addFilter', ['isPhone', [$this->prefix('@helpers'), 'isPhone']])
156 | ->addSetup('addFilter', ['isTablet', [$this->prefix('@helpers'), 'isTablet']])
157 | ->addSetup('addFilter', ['isDevice', [$this->prefix('@helpers'), 'isDevice']])
158 | ->addSetup('addFilter', ['isOs', [$this->prefix('@helpers'), 'isOs']])
159 | ->addSetup('addFilter', ['isFullView', [$this->prefix('@helpers'), 'isFullView']])
160 | ->addSetup('addFilter', ['isMobileView', [$this->prefix('@helpers'), 'isMobileView']])
161 | ->addSetup('addFilter', ['isPhoneView', [$this->prefix('@helpers'), 'isPhoneView']])
162 | ->addSetup('addFilter', ['isTabletView', [$this->prefix('@helpers'), 'isTabletView']])
163 | ->addSetup('addFilter', ['isNotMobileView', [$this->prefix('@helpers'), 'isNotMobileView']])
164 | ->addSetup('addFilter', ['getMobileDetectService', [$this->prefix('@helpers'), 'getMobileDetectService']])
165 | ->addSetup('addFilter', ['getDeviceViewService', [$this->prefix('@helpers'), 'getDeviceViewService']]);
166 | }
167 |
168 | /**
169 | * @param Nette\Configurator $config
170 | * @param string $extensionName
171 | *
172 | * @return void
173 | */
174 | public static function register(Nette\Configurator $config, string $extensionName = 'mobileDetect') : void
175 | {
176 | $config->onCompile[] = function (Nette\Configurator $config, Nette\DI\Compiler $compiler) use ($extensionName) : void {
177 | $compiler->addExtension($extensionName, new MobileDetectExtension());
178 | };
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/docs/en/index.md:
--------------------------------------------------------------------------------
1 | # MobileDetect
2 |
3 | Extension for detecting mobile devices, managing mobile view types, redirect to mobile version for [Nette Framework](http://nette.org/)
4 |
5 | ## Introduction
6 |
7 | This extension use [Mobile_Detect](https://github.com/serbanghita/Mobile-Detect) class and provides the following features:
8 |
9 | * Detect the various mobile devices by name, OS, browser User-Agent
10 | * Manages site views for the variuos mobile devices (`mobile`, `phone`, `tablet`, `full`)
11 | * Redirects to mobile and tablet sites
12 |
13 | ## Installation
14 |
15 | The best way to install ipub/mobile-detect is using [Composer](http://getcomposer.org/):
16 |
17 | ```sh
18 | $ composer require ipub/mobile-detect
19 | ```
20 |
21 | After that you have to register extension in config.neon.
22 |
23 | ```neon
24 | extensions:
25 | mobileDetect: IPub\MobileDetect\DI\MobileDetectExtension
26 | ```
27 |
28 | Package contains trait, which you will have to use in class, where you want to use mobile detector.
29 |
30 | ```php
31 | redirectUrl = http://site.com/current/path
74 | # false => redirectUrl = http://site.com
75 | ```
76 |
77 | ## Usage in PHP files
78 |
79 | ### Switch device view
80 |
81 | For switch device view, use `device_view` GET parameter:
82 |
83 | ````
84 | http://site.com?device_view={full/mobile/phone/tablet}
85 | ````
86 |
87 | ### How to use in presenter etc.
88 |
89 | In presenters or other services where you import mobile detector you could create calls like this
90 |
91 | ```php
92 | class SomePresenter extends Nette\Application\UI\Presenter
93 | {
94 | /**
95 | * @var \IPub\MobileDetect\MobileDetect
96 | */
97 | protected $mobileDetect
98 |
99 | /**
100 | * Some action with mobile detection
101 | */
102 | public function someAction()
103 | {
104 | if ($this->mobileDetect->isMobile()) {
105 | //...do whatever
106 | }
107 | }
108 | }
109 | ```
110 |
111 | ### Check type device
112 |
113 | ```php
114 | $mobileDetect->isMobile();
115 | $mobileDetect->isTablet();
116 | $mobileDetect->isPhone();
117 | ```
118 |
119 | ### Check phone
120 |
121 | is[iPhone|HTC|Nexus|Dell|Motorola|Samsung|Sony|Asus|Palm|Vertu|GenericPhone]
122 |
123 | ```php
124 | $mobileDetect->isIphone();
125 | $mobileDetect->isHTC();
126 | // etc.
127 | ```
128 |
129 | ### Check tablet
130 |
131 | is[BlackBerryTablet|iPad|Kindle|SamsungTablet|HTCtablet|MotorolaTablet|AsusTablet|NookTablet|AcerTablet| YarvikTablet|GenericTablet]
132 |
133 | ```php
134 | $mobileDetect->isIpad();
135 | $mobileDetect->isMotorolaTablet();
136 | // etc.
137 | ```
138 |
139 | ### Check mobile OS
140 |
141 | is[AndroidOS|BlackBerryOS|PalmOS|SymbianOS|WindowsMobileOS|iOS|badaOS]
142 |
143 | ```php
144 | $mobileDetect->isAndroidOS();
145 | $mobileDetect->isIOS();
146 | // etc.
147 | ```
148 |
149 | ### Check mobile browser User-Agent
150 |
151 | is[Chrome|Dolfin|Opera|Skyfire|IE|Firefox|Bolt|TeaShark|Blazer|Safari|Midori|GenericBrowser]
152 |
153 | ```php
154 | $mobileDetect->isChrome();
155 | $mobileDetect->isSafari();
156 | // etc.
157 | ```
158 |
159 | ## Using in Latte
160 |
161 | ### Check device type
162 |
163 | ```html
164 | {isMobile}
165 | This content will be only on mobile devices....
166 | {/isMobile}
167 |
168 | {isTablet}
169 | This content will be only on tablet devices....
170 | {/isTablet}
171 |
172 | {isPhone}
173 | This content will be only on phone devices....
174 | {/isPhone}
175 | ```
176 |
177 | Available Latte macros:
178 |
179 | ```html
180 | {isMobile}....{/isMobile}
181 | {isNotMobile}....{/isNotMobile}
182 |
183 | {isTablet}....{/isTablet}
184 | {isNotTablet}....{/isNotTablet}
185 |
186 | {isPhone}....{/isPhone}
187 | {isNotPhone}....{/isNotPhone}
188 | ```
189 |
190 | ### Check device type by provided name
191 |
192 | ```html
193 | {isMobileDevice iPhone}
194 | This content will be only on Apple iPhone devices....
195 | {/isMobileDevice}
196 |
197 |
198 | This content will be only on Apple iPhone devices....
199 |
200 | ```
201 |
202 | ### Check device OS by provided name
203 |
204 | ```html
205 | {isMobileOs iOS}
206 | This content will be only on mobile devices with iOS operating system....
207 | {/isMobileOs}
208 |
209 |
210 | This content will be only on mobile devices with iOS operating system....
211 |
212 | ```
213 |
214 | ### Check view type set by helper
215 |
216 | With view type detector you could change your default layout in templates.
217 |
218 | ```html
219 | {isMobileView}
220 | {layout '../Path/To/Your/Mobile/Device/@layout.latte'}
221 | {/isMobileView}
222 |
223 | {isTabletView}
224 | {layout '../Path/To/Your/Tablet/Device/@layout.latte'}
225 | {/isTabletView}
226 |
227 | {isPhoneView}
228 | {layout '../Path/To/Your/Phone/Device/@layout.latte'}
229 | {/isPhoneView}
230 |
231 | {isFullView}
232 | {layout '../Path/To/Your/Full/View/@layout.latte'}
233 | {/isFullView}
234 |
235 | {isNotMobileView}
236 | {layout '../Path/To/Your/Not/Mobile/Device/@layout.latte'}
237 | {/isNotMobileView}
238 | ```
239 |
--------------------------------------------------------------------------------
/src/IPub/MobileDetect/Helpers/DeviceView.php:
--------------------------------------------------------------------------------
1 |
8 | * @package iPublikuj:MobileDetect!
9 | * @subpackage Helpers
10 | * @since 1.0.0
11 | *
12 | * @date 23.04.14
13 | */
14 |
15 | declare(strict_types = 1);
16 |
17 | namespace IPub\MobileDetect\Helpers;
18 |
19 | use Nette;
20 | use Nette\Application;
21 | use Nette\Http;
22 |
23 | /**
24 | * Device view detector helper
25 | *
26 | * @package iPublikuj:MobileDetect!
27 | * @subpackage Helpers
28 | *
29 | * @author Adam Kadlec
30 | */
31 | final class DeviceView
32 | {
33 | /**
34 | * Implement nette smart magic
35 | */
36 | use Nette\SmartObject;
37 |
38 | public const VIEW_MOBILE = 'mobile';
39 | public const VIEW_PHONE = 'phone';
40 | public const VIEW_TABLET = 'tablet';
41 | public const VIEW_FULL = 'full';
42 | public const VIEW_NOT_MOBILE = 'not_mobile';
43 |
44 | /**
45 | * @var Http\IRequest
46 | */
47 | private $httpRequest;
48 |
49 | /**
50 | * @var Http\IResponse
51 | */
52 | private $httpResponse;
53 |
54 | /**
55 | * @var string
56 | */
57 | private $viewType = self::VIEW_FULL;
58 |
59 | /**
60 | * @var CookieSettings
61 | */
62 | private $cookieSettings;
63 |
64 | /**
65 | * @var string
66 | */
67 | private $switchParameterName = 'device_view';
68 |
69 | /**
70 | * @param string $setSwitchParameterName
71 | * @param CookieSettings $cookieSettings
72 | * @param Http\IRequest $httpRequest
73 | * @param Http\IResponse $httpResponse
74 | */
75 | public function __construct(string $setSwitchParameterName, CookieSettings $cookieSettings, Http\IRequest $httpRequest, Http\IResponse $httpResponse)
76 | {
77 | $this->cookieSettings = $cookieSettings;
78 | $this->httpRequest = $httpRequest;
79 | $this->httpResponse = $httpResponse;
80 |
81 | $this->switchParameterName = $setSwitchParameterName;
82 |
83 | if ($this->httpRequest->getQuery($this->switchParameterName) ?? false) {
84 | $this->viewType = $this->httpRequest->getQuery($this->switchParameterName);
85 |
86 | } elseif ($this->httpRequest->getCookie($this->cookieSettings->getName())) {
87 | $this->viewType = $this->httpRequest->getCookie($this->cookieSettings->getName());
88 | }
89 | }
90 |
91 | /**
92 | * Gets the view type for a device
93 | *
94 | * @return string
95 | */
96 | public function getViewType() : string
97 | {
98 | return $this->viewType;
99 | }
100 |
101 | /**
102 | * Is the device in full view
103 | *
104 | * @return bool
105 | */
106 | public function isFullView() : bool
107 | {
108 | return $this->viewType === self::VIEW_FULL;
109 | }
110 |
111 | /**
112 | * Is the device a tablet view type
113 | *
114 | * @return bool
115 | */
116 | public function isTabletView() : bool
117 | {
118 | return $this->viewType === self::VIEW_TABLET;
119 | }
120 |
121 | /**
122 | * Is the device a phone view type
123 | *
124 | * @return bool
125 | */
126 | public function isPhoneView() : bool
127 | {
128 | return $this->viewType === self::VIEW_PHONE;
129 | }
130 |
131 | /**
132 | * Is the device a mobile view type
133 | *
134 | * @return bool
135 | */
136 | public function isMobileView() : bool
137 | {
138 | return $this->viewType === self::VIEW_MOBILE || $this->isPhoneView() || $this->isTabletView();
139 | }
140 |
141 | /**
142 | * Is not the device a mobile view type (PC, Mac, etc.)
143 | *
144 | * @return bool
145 | */
146 | public function isNotMobileView() : bool
147 | {
148 | return $this->viewType === self::VIEW_NOT_MOBILE;
149 | }
150 |
151 | /**
152 | * Sets the tablet view type
153 | *
154 | * @return void
155 | */
156 | public function setTabletView() : void
157 | {
158 | $this->viewType = self::VIEW_TABLET;
159 | }
160 |
161 | /**
162 | * Sets the phone view type
163 | *
164 | * @return void
165 | */
166 | public function setPhoneView() : void
167 | {
168 | $this->viewType = self::VIEW_PHONE;
169 | }
170 |
171 | /**
172 | * Sets the mobile view type
173 | *
174 | * @return void
175 | */
176 | public function setMobileView() : void
177 | {
178 | $this->viewType = self::VIEW_MOBILE;
179 | }
180 |
181 | /**
182 | * Sets the not mobile view type
183 | *
184 | * @return void
185 | */
186 | public function setNotMobileView() : void
187 | {
188 | $this->viewType = self::VIEW_NOT_MOBILE;
189 | }
190 |
191 | /**
192 | * @return string
193 | */
194 | public function getSwitchParameterName() : string
195 | {
196 | return $this->switchParameterName;
197 | }
198 |
199 | /**
200 | * Gets the switch param value from the query string (GET header)
201 | *
202 | * @return string
203 | */
204 | public function getSwitchParameterValue() : string
205 | {
206 | return $this->httpRequest->getQuery($this->switchParameterName) ?? self::VIEW_FULL;
207 | }
208 |
209 | /**
210 | * Has the Request the switch param in the query string (GET header)
211 | *
212 | * @return bool
213 | */
214 | public function hasSwitchParameter() : bool
215 | {
216 | return ($this->httpRequest->getQuery($this->switchParameterName) ?? false) ? true : false;
217 | }
218 |
219 | /**
220 | * Gets the RedirectResponse by switch param value
221 | *
222 | * @param string $redirectUrl
223 | *
224 | * @return Application\Responses\RedirectResponse
225 | */
226 | public function getRedirectResponseBySwitchParam(string $redirectUrl) : Application\Responses\RedirectResponse
227 | {
228 | $statusCode = 302;
229 |
230 | switch ($this->getSwitchParameterValue()) {
231 | case self::VIEW_MOBILE:
232 | $this->createCookie(self::VIEW_MOBILE);
233 | break;
234 |
235 | case self::VIEW_PHONE:
236 | $this->createCookie(self::VIEW_PHONE);
237 | break;
238 |
239 | case self::VIEW_TABLET:
240 | $this->createCookie(self::VIEW_TABLET);
241 | break;
242 |
243 | default:
244 | $this->createCookie(self::VIEW_FULL);
245 | break;
246 | }
247 |
248 | return new Application\Responses\RedirectResponse($redirectUrl, $statusCode);
249 | }
250 |
251 | /**
252 | * Modifies the Response for non-mobile devices
253 | *
254 | * @return Http\IResponse
255 | */
256 | public function modifyNotMobileResponse() : Http\IResponse
257 | {
258 | // Create cookie
259 | $this->createCookie(self::VIEW_NOT_MOBILE);
260 |
261 | return $this->httpResponse;
262 | }
263 |
264 | /**
265 | * Modifies the Response for tablet devices
266 | *
267 | * @return Http\IResponse
268 | */
269 | public function modifyTabletResponse() : Http\IResponse
270 | {
271 | // Create cookie
272 | $this->createCookie(self::VIEW_TABLET);
273 |
274 | return $this->httpResponse;
275 | }
276 |
277 | /**
278 | * Modifies the Response for phone devices
279 | *
280 | * @return Http\IResponse
281 | */
282 | public function modifyPhoneResponse() : Http\IResponse
283 | {
284 | // Create cookie
285 | $this->createCookie(self::VIEW_PHONE);
286 |
287 | return $this->httpResponse;
288 | }
289 |
290 | /**
291 | * Modifies the Response for mobile devices
292 | *
293 | * @return Http\IResponse
294 | */
295 | public function modifyMobileResponse() : Http\IResponse
296 | {
297 | // Create cookie
298 | $this->createCookie(self::VIEW_MOBILE);
299 |
300 | return $this->httpResponse;
301 | }
302 |
303 | /**
304 | * Gets the RedirectResponse for phone devices
305 | *
306 | * @param string $host Uri host
307 | * @param int $statusCode Status code
308 | *
309 | * @return Application\Responses\RedirectResponse
310 | */
311 | public function getPhoneRedirectResponse(string $host, int $statusCode) : Application\Responses\RedirectResponse
312 | {
313 | // Create cookie
314 | $this->createCookie(self::VIEW_PHONE);
315 |
316 | return new Application\Responses\RedirectResponse($host, $statusCode);
317 | }
318 |
319 | /**
320 | * Gets the RedirectResponse for tablet devices
321 | *
322 | * @param string $host Uri host
323 | * @param int $statusCode Status code
324 | *
325 | * @return Application\Responses\RedirectResponse
326 | */
327 | public function getTabletRedirectResponse(string $host, int $statusCode) : Application\Responses\RedirectResponse
328 | {
329 | // Create cookie
330 | $this->createCookie(self::VIEW_TABLET);
331 |
332 | return new Application\Responses\RedirectResponse($host, $statusCode);
333 | }
334 |
335 | /**
336 | * Gets the RedirectResponse for mobile devices
337 | *
338 | * @param string $host Uri host
339 | * @param int $statusCode Status code
340 | *
341 | * @return Application\Responses\RedirectResponse
342 | */
343 | public function getMobileRedirectResponse(string $host, int $statusCode) : Application\Responses\RedirectResponse
344 | {
345 | // Create cookie
346 | $this->createCookie(self::VIEW_MOBILE);
347 |
348 | return new Application\Responses\RedirectResponse($host, $statusCode);
349 | }
350 |
351 | /**
352 | * Gets the cookie
353 | *
354 | * @param string $cookieValue
355 | *
356 | * @return void
357 | */
358 | private function createCookie(string $cookieValue) : void
359 | {
360 | // Store cookie in response
361 | $this->httpResponse->setCookie(
362 | $this->cookieSettings->getName(),
363 | $cookieValue,
364 | $this->cookieSettings->getExpiresTime(),
365 | $this->cookieSettings->getPath(),
366 | $this->cookieSettings->getDomain(),
367 | $this->cookieSettings->isSecure(),
368 | $this->cookieSettings->isHttpOnly()
369 | );
370 | }
371 | }
372 |
--------------------------------------------------------------------------------
/src/IPub/MobileDetect/Latte/Macros.php:
--------------------------------------------------------------------------------
1 |
8 | * @package iPublikuj:MobileDetect!
9 | * @subpackage Latte
10 | * @since 1.0.0
11 | *
12 | * @date 22.04.14
13 | */
14 |
15 | declare(strict_types = 1);
16 |
17 | namespace IPub\MobileDetect\Latte;
18 |
19 | use Latte\Compiler;
20 | use Latte\MacroNode;
21 | use Latte\PhpWriter;
22 | use Latte\Macros\MacroSet;
23 |
24 | use IPub\MobileDetect\Exceptions;
25 |
26 | /**
27 | * Mobile detect latte macros definition
28 | *
29 | * @package iPublikuj:MobileDetect!
30 | * @subpackage Latte
31 | *
32 | * @author Adam Kadlec
33 | */
34 | final class Macros extends MacroSet
35 | {
36 | /**
37 | * Register latte macros
38 | *
39 | * @param Compiler $compiler
40 | *
41 | * @return static
42 | */
43 | public static function install(Compiler $compiler)
44 | {
45 | $me = new static($compiler);
46 |
47 | /**
48 | * {isMobile /}, {isNotMobile /}
49 | */
50 | $me->addMacro('isMobile', [$me, 'macroIsMobile'], '}');
51 | $me->addMacro('isNotMobile', [$me, 'macroIsNotMobile'], '}');
52 |
53 | /**
54 | * {isPhone /}, {isNotPhone /}
55 | */
56 | $me->addMacro('isPhone', [$me, 'macroIsPhone'], '}');
57 | $me->addMacro('isNotPhone', [$me, 'macroIsNotPhone'], '}');
58 |
59 | /**
60 | * {isTablet /}, {isNotTablet /}
61 | */
62 | $me->addMacro('isTablet', [$me, 'macroIsTablet'], '}');
63 | $me->addMacro('isNotTablet', [$me, 'macroIsNotTablet'], '}');
64 |
65 | /**
66 | * {isMobileDevice 'device_name'}
67 | */
68 | $me->addMacro('isMobileDevice', [$me, 'macroIsDevice'], '}');
69 |
70 | /**
71 | * {isMobileOs 'device_name'}
72 | */
73 | $me->addMacro('isMobileOs', [$me, 'macroIsOS'], '}');
74 |
75 | /**
76 | * {isFullView /}, {isMobileView /}, {isTabletView /}, {isNotMobileView /}
77 | */
78 | $me->addMacro('isFullView', [$me, 'macroIsFullView'], '}');
79 | $me->addMacro('isMobileView', [$me, 'macroIsMobileView'], '}');
80 | $me->addMacro('isPhoneView', [$me, 'macroIsPhoneView'], '}');
81 | $me->addMacro('isTabletView', [$me, 'macroIsTabletView'], '}');
82 | $me->addMacro('isNotMobileView', [$me, 'macroIsNotMobileView'], '}');
83 |
84 | return $me;
85 | }
86 |
87 | /**
88 | * {isMobile /}
89 | *
90 | * @param MacroNode $node
91 | * @param PhpWriter $writer
92 | *
93 | * @return string
94 | */
95 | public function macroIsMobile(MacroNode $node, PhpWriter $writer) : string
96 | {
97 | return $writer->write('
98 | $_resultMD = property_exists($this, "filters") ? %escape(call_user_func($this->filters->isMobile)) : $template->getMobileDetectService()->isMobile() && !$template->getMobileDetectService()->isTablet();
99 | if ($_resultMD) {
100 | ');
101 | }
102 |
103 | /**
104 | * {isNotMobile /}
105 | *
106 | * @param MacroNode $node
107 | * @param PhpWriter $writer
108 | *
109 | * @return string
110 | */
111 | public function macroIsNotMobile(MacroNode $node, PhpWriter $writer) : string
112 | {
113 | return $writer->write('
114 | $_resultMD = property_exists($this, "filters") ? %escape(!call_user_func($this->filters->isMobile)) : !$template->getMobileDetectService()->isMobile();
115 | if ($_resultMD) {
116 | ');
117 | }
118 |
119 | /**
120 | * {isPhone /}
121 | *
122 | * @param MacroNode $node
123 | * @param PhpWriter $writer
124 | *
125 | * @return string
126 | */
127 | public function macroIsPhone(MacroNode $node, PhpWriter $writer) : string
128 | {
129 | return $writer->write('
130 | $_resultMD = property_exists($this, "filters") ? %escape(call_user_func($this->filters->isMobile) && !call_user_func($this->filters->isTablet)) : $template->getMobileDetectService()->isMobile() && !$template->getMobileDetectService()->isTablet();
131 | if ($_resultMD) {
132 | ');
133 | }
134 |
135 | /**
136 | * {isNotPhone /}
137 | *
138 | * @param MacroNode $node
139 | * @param PhpWriter $writer
140 | *
141 | * @return string
142 | */
143 | public function macroIsNotPhone(MacroNode $node, PhpWriter $writer) : string
144 | {
145 | return $writer->write('
146 | $_resultMD = property_exists($this, "filters") ? %escape((call_user_func($this->filters->isMobile) && call_user_func($this->filters->isTablet)) || !call_user_func($this->filters->isMobile)) : ($template->getMobileDetectService()->isMobile() && $template->getMobileDetectService()->isTablet()) || !$template->getMobileDetectService()->isMobile();
147 | if ($_resultMD) {
148 | ');
149 | }
150 |
151 | /**
152 | * {isTablet /}
153 | *
154 | * @param MacroNode $node
155 | * @param PhpWriter $writer
156 | *
157 | * @return string
158 | */
159 | public function macroIsTablet(MacroNode $node, PhpWriter $writer) : string
160 | {
161 | return $writer->write('
162 | $_resultMD = property_exists($this, "filters") ? %escape(call_user_func($this->filters->isTablet)) : $template->getMobileDetectService()->isTablet();
163 | if ($_resultMD) {
164 | ');
165 | }
166 |
167 | /**
168 | * {isNotTablet /}
169 | *
170 | * @param MacroNode $node
171 | * @param PhpWriter $writer
172 | *
173 | * @return string
174 | */
175 | public function macroIsNotTablet(MacroNode $node, PhpWriter $writer) : string
176 | {
177 | return $writer->write('
178 | $_resultMD = property_exists($this, "filters") ? %escape(!call_user_func($this->filters->isTablet)) : !$template->getMobileDetectService()->isTablet();
179 | if ($_resultMD) {
180 | ');
181 | }
182 |
183 | /**
184 | * @param MacroNode $node
185 | * @param PhpWriter $writer
186 | *
187 | * @return string
188 | *
189 | * @throws Exceptions\CompileException
190 | */
191 | public function macroIsDevice(MacroNode $node, PhpWriter $writer) : string
192 | {
193 | $arguments = self::prepareMacroArguments($node->args);
194 |
195 | if ($arguments['device'] === NULL) {
196 | throw new Exceptions\CompileException('Please provide device name.');
197 | }
198 |
199 | // Create magic method name
200 | $magicMethodName = 'is' . ucfirst(strtolower((string) $arguments["device"]));
201 |
202 | return $writer->write('
203 | $_resultMD = property_exists($this, "filters") ? %escape(call_user_func($this->filters->isDevice, "' . $arguments['device'] . '")) : $template->getMobileDetectService()->'. $magicMethodName.'();
204 | if ($_resultMD) {
205 | ');
206 | }
207 |
208 | /**
209 | * @param MacroNode $node
210 | * @param PhpWriter $writer
211 | *
212 | * @return string
213 | *
214 | * @throws Exceptions\CompileException
215 | */
216 | public function macroIsOS(MacroNode $node, PhpWriter $writer) : string
217 | {
218 | $arguments = self::prepareMacroArguments($node->args);
219 |
220 | if ($arguments['os'] === NULL) {
221 | throw new Exceptions\CompileException('Please provide OS name.');
222 | }
223 |
224 | // Create magic method name
225 | $magicMethodName = 'is' . ucfirst(strtolower((string) $arguments["os"]));
226 |
227 | return $writer->write('
228 | $_resultMD = property_exists($this, "filters") ? %escape(call_user_func($this->filters->isOs, "' . $arguments['os'] . '")) : $template->getMobileDetectService()->'. $magicMethodName.'();
229 | if ($_resultMD) {
230 | ');
231 | }
232 |
233 | /**
234 | * {isFullView /}
235 | *
236 | * @param MacroNode $node
237 | * @param PhpWriter $writer
238 | *
239 | * @return string
240 | */
241 | public function macroIsFullView(MacroNode $node, PhpWriter $writer) : string
242 | {
243 | return $writer->write('
244 | $_resultMD = property_exists($this, "filters") ? %escape(!call_user_func($this->filters->isFullView)) : $template->getDeviceViewService()->isFullView();
245 | if ($_resultMD) {
246 | ');
247 | }
248 |
249 | /**
250 | * {isMobileView /}
251 | *
252 | * @param MacroNode $node
253 | * @param PhpWriter $writer
254 | *
255 | * @return string
256 | */
257 | public function macroIsMobileView(MacroNode $node, PhpWriter $writer) : string
258 | {
259 | return $writer->write('
260 | $_resultMD = property_exists($this, "filters") ? %escape(!call_user_func($this->filters->isMobileView)) : $template->getDeviceViewService()->isMobileView();
261 | if ($_resultMD) {
262 | ');
263 | }
264 |
265 | /**
266 | * {isPhoneView /}
267 | *
268 | * @param MacroNode $node
269 | * @param PhpWriter $writer
270 | *
271 | * @return string
272 | */
273 | public function macroIsPhoneView(MacroNode $node, PhpWriter $writer) : string
274 | {
275 | return $writer->write('
276 | $_resultMD = property_exists($this, "filters") ? %escape(!call_user_func($this->filters->isPhoneView)) : $template->getDeviceViewService()->isPhoneView();
277 | if ($_resultMD) {
278 | ');
279 | }
280 |
281 | /**
282 | * {isTabletView /}
283 | *
284 | * @param MacroNode $node
285 | * @param PhpWriter $writer
286 | *
287 | * @return string
288 | */
289 | public function macroIsTabletView(MacroNode $node, PhpWriter $writer) : string
290 | {
291 | return $writer->write('
292 | $_resultMD = property_exists($this, "filters") ? %escape(!call_user_func($this->filters->isTabletView)) : $template->getDeviceViewService()->isTabletView();
293 | if ($_resultMD) {
294 | ');
295 | }
296 |
297 | /**
298 | * {isNotMobileView /}
299 | *
300 | * @param MacroNode $node
301 | * @param PhpWriter $writer
302 | *
303 | * @return string
304 | */
305 | public function macroIsNotMobileView(MacroNode $node, PhpWriter $writer) : string
306 | {
307 | return $writer->write('
308 | $_resultMD = property_exists($this, "filters") ? %escape(!call_user_func($this->filters->isNotMobileView)) : $template->getDeviceViewService()->isNotMobileView();
309 | if ($_resultMD) {
310 | ');
311 | }
312 |
313 | /**
314 | * @param string $macro
315 | *
316 | * @return array
317 | */
318 | public static function prepareMacroArguments($macro) : array
319 | {
320 | $arguments = array_map(function ($value) : string {
321 | return trim($value);
322 | }, explode(',', $macro));
323 |
324 | $device = $os = $arguments[0];
325 |
326 | return [
327 | 'device' => $device,
328 | 'os' => $os,
329 | ];
330 | }
331 | }
332 |
--------------------------------------------------------------------------------
/src/IPub/MobileDetect/Events/OnRequestHandler.php:
--------------------------------------------------------------------------------
1 |
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
33 | */
34 | final class OnRequestHandler
35 | {
36 | private const REDIRECT = 'redirect';
37 | private const NO_REDIRECT = 'noRedirect';
38 | private const REDIRECT_WITHOUT_PATH = 'redirectWithoutPath';
39 |
40 | private const MOBILE = 'mobile';
41 | private const TABLET = 'tablet';
42 | private 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 | $this->httpRequest = $httpRequest;
101 | $this->httpResponse = $httpResponse;
102 |
103 | $this->router = $router;
104 |
105 | $this->onResponseHandler = $onResponseHandler;
106 |
107 | $this->mobileDetect = $mobileDetect;
108 | $this->deviceView = $deviceView;
109 | }
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 (Helpers\DeviceView $deviceView) : Http\IResponse {
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) : Http\IResponse {
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) : Http\IResponse {
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) : Http\IResponse {
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|NULL
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 | return null;
409 | }
410 |
411 | /**
412 | * Gets the redirect url
413 | *
414 | * @param string $platform
415 | *
416 | * @return string|NULL
417 | */
418 | private function getRedirectUrl(string $platform) : ?string
419 | {
420 | if ($routingOption = $this->getRoutingOption($platform)) {
421 | switch ($routingOption) {
422 | case self::REDIRECT:
423 | return rtrim($this->redirectConf[$platform]['host'], '/') . '/' . ltrim($this->httpRequest->getUrl()->getRelativeUrl(), '/');
424 |
425 | case self::REDIRECT_WITHOUT_PATH:
426 | return $this->redirectConf[$platform]['host'];
427 | }
428 | }
429 |
430 | return null;
431 | }
432 |
433 | /**
434 | * Gets named option from current route
435 | *
436 | * @param string $name
437 | *
438 | * @return string|NULL
439 | */
440 | private function getRoutingOption(string $name) : ?string
441 | {
442 | $option = null;
443 |
444 | // Get actual route
445 | $request = $this->router->match($this->httpRequest);
446 |
447 | if ($request instanceof Application\Request) {
448 | $params = $request->getParameters();
449 | $option = isset($params[$name]) ? $params[$name] : null;
450 | }
451 |
452 | if (!$option) {
453 | $option = $this->redirectConf[$name]['action'];
454 | }
455 |
456 | if (in_array($option, [self::REDIRECT, self::REDIRECT_WITHOUT_PATH, self::NO_REDIRECT])) {
457 | return $option;
458 | }
459 |
460 | return null;
461 | }
462 |
463 | /**
464 | * Gets the current host
465 | *
466 | * @return string
467 | */
468 | private function getCurrentHost() : string
469 | {
470 | return $this->httpRequest->getUrl()->getHostUrl() . $this->httpRequest->getUrl()->getScriptPath();
471 | }
472 | }
473 |
--------------------------------------------------------------------------------