MobileComponent.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. <?php
  2. App::uses('Component', 'Controller');
  3. App::uses('Router', 'Routing');
  4. /**
  5. * Uses Session: User.mobile and User.nomobile
  6. * - mobile is the auto-detection (true/false)
  7. * - nomobile can be set by the user and overrides the default behavior/detection
  8. * (1=true/0=false or -1=null which will remove the override)
  9. *
  10. * TODO: differentaite between "isMobile" and "has/wants mobile"
  11. * @author Mark Scherer
  12. * @license MIT
  13. * 2011-12-28 ms
  14. */
  15. class MobileComponent extends Component {
  16. public $components = array('Session');
  17. public $isMobile = null;
  18. public $setMobile = null;
  19. public $Controller = null;
  20. protected $_defaults = array(
  21. 'engine' => 'cake',
  22. 'auto' => false, // auto set mobile views
  23. );
  24. /**
  25. * if false uses subfolders: /View/.../mobile/
  26. */
  27. public $themed = true;
  28. public function __construct(ComponentCollection $collection, $settings = array()) {
  29. $settings = array_merge($this->_defaults, $settings);
  30. parent::__construct($collection, $settings);
  31. }
  32. public function initialize(Controller $Controller) {
  33. parent::initialize($Controller);
  34. $this->Controller = $Controller;
  35. if (isset($this->Controller->request->params['named']['mobile'])) {
  36. if ($this->Controller->request->params['named']['mobile'] == '-1') {
  37. $noMobile = null;
  38. } else {
  39. $wantsMobile = (bool)$this->Controller->request->params['named']['mobile'];
  40. $noMobile = (int)(!$wantsMobile);
  41. }
  42. $this->Session->write('User.nomobile', $noMobile);
  43. }
  44. $this->isMobile();
  45. }
  46. /**
  47. * Serve mobile views if available
  48. *
  49. * can be called from beforeFilter() to automatically serve an alternative mobile view
  50. * if the file exists. If it doesn't exist in `/View/[ViewPath]/mobile/` the normal one
  51. * will be used.
  52. *
  53. * @deprecated in favor of themed solution?
  54. * @return void
  55. * 2012-10-02 ms
  56. */
  57. public function serveMobileIfAvailable() {
  58. $viewDir = App::path('View');
  59. // returns an array
  60. /*
  61. * array(
  62. * (int) 0 => '/var/www/maps-cakephp2/app/View/'
  63. * )
  64. */
  65. $mobileViewFile = $viewDir[0] . $this->viewPath . DS . 'Mobile' . DS . $this->params['action'] . '.ctp';
  66. //Debugger::log($this->viewPath);
  67. // use this to log the output to
  68. // app/tmp/logs/debug.log
  69. if (file_exists($mobileViewFile)) {
  70. // if device is mobile, change layout to mobile
  71. // but only if a view exists for it.
  72. $this->layout = 'mobile';
  73. // and if a mobile view file has been
  74. // created for the action, serve it instead
  75. // of the default view file
  76. $this->viewPath = $this->viewPath . '/Mobile/';
  77. }
  78. }
  79. /**
  80. * Set mobile views as `Mobile` theme
  81. *
  82. * @return void
  83. */
  84. public function setMobile() {
  85. if ($this->isMobile === null) {
  86. $this->isMobile();
  87. }
  88. $noMobile = $this->Session->read('User.nomobile');
  89. if (!$this->isMobile && $noMobile === null || $noMobile) {
  90. $this->setMobile = false;
  91. } else {
  92. $this->setMobile = true;
  93. }
  94. $urlParams = Router::getParams(true);
  95. if (!isset($urlParams['named'])) {
  96. $urlParams['named'] = array();
  97. }
  98. if (!isset($urlParams['pass'])) {
  99. $urlParams['pass'] = array();
  100. }
  101. $urlParams = array_merge($urlParams, $urlParams['named'], $urlParams['pass']);
  102. unset($urlParams['named']);
  103. unset($urlParams['pass']);
  104. if (isset($urlParams['prefix'])) {
  105. unset($urlParams['prefix']);
  106. }
  107. if ($this->setMobile) {
  108. $url = Router::url(array_merge($urlParams, array('mobile' => 0)));
  109. $this->Controller->set('desktopUrl', $url);
  110. } else {
  111. $url = Router::url(array_merge($urlParams, array('mobile' => 1)));
  112. $this->Controller->set('mobileUrl', $url);
  113. }
  114. Configure::write('User.mobile', $this->isMobile);
  115. Configure::write('User.setMobile', $this->setMobile);
  116. if (!$this->isMobile) {
  117. return;
  118. }
  119. if (!$this->themed) {
  120. $this->serveMobileIfAvailable();
  121. return;
  122. }
  123. $this->Controller->viewClass = 'Theme';
  124. $this->Controller->theme = 'Mobile';
  125. }
  126. /**
  127. * Determine if we need to so serve mobile views based on session preference and browser headers.
  128. *
  129. * @return bool $success
  130. */
  131. public function isMobile() {
  132. if ($this->isMobile !== null) {
  133. return $this->isMobile;
  134. }
  135. $wantsMobile = null;
  136. if (isset($this->Controller->request->params['named']['mobile'])) {
  137. if ($this->Controller->request->params['named']['mobile'] == '-1') {
  138. $this->Session->delete('User.mobile');
  139. } else {
  140. $wantsMobile = (bool)$this->Controller->request->params['named']['mobile'];
  141. }
  142. }
  143. if ($wantsMobile) {
  144. $this->isMobile = $wantsMobile;
  145. return $this->isMobile;
  146. }
  147. $this->isMobile = $this->Session->read('User.mobile');
  148. if ($this->isMobile !== null) {
  149. return $this->isMobile;
  150. }
  151. $this->isMobile = (int)$this->detect();
  152. $this->Session->write('User.mobile', $this->isMobile);
  153. return $this->isMobile;
  154. }
  155. /**
  156. * Detect if the current request is from a mobile device
  157. *
  158. * @return bool $success
  159. */
  160. public function detect() {
  161. if ($this->settings['engine'] !== 'cake') {
  162. throw new CakeException(__('Engine %s not available', $this->settings['engine']));
  163. //TODO
  164. // $this->detectByTools()
  165. // $this->detectByWurfl()
  166. }
  167. $this->Controller->request->addDetector('mobile', array('options' => array('OMNIA7')));
  168. return $this->Controller->request->is('mobile');
  169. }
  170. /**
  171. * @return bool $success
  172. */
  173. public function detectByTools() {
  174. $isMobile = $this->Session->read('Session.mobile');
  175. if ($isMobile !== null) {
  176. return $isMobile;
  177. }
  178. App::uses('UserAgentLib', 'Tools.Lib');
  179. $UserAgentLib = new UserAgentLib();
  180. return (bool)$UserAgentLib->isMobile();
  181. }
  182. /**
  183. * @return bool $success
  184. */
  185. public function detectByWurfl() {
  186. App::import('Vendor', 'WURFL', array('file' => 'WURFLManagerProvider.php'));
  187. $wurflConfigFile = APP . 'Config' . DS . 'wurfl ' . DS . 'config.xml';
  188. $wurflManager = WURFL_WURFLManagerProvider::getWURFLManager($wurflConfigFile);
  189. $requestingDevice = $wurflManager->getDeviceForHttpRequest($_SERVER);
  190. if ($requestingDevice->getCapability('is_wireless_device') == 'true') {
  191. return true;
  192. }
  193. return false;
  194. }
  195. }