MobileComponent.php 5.3 KB

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