MobileComponent.php 5.9 KB

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