CakePHP v2.2.1 解决方案(+ Cookies 保持移动/桌面/其他布局)
此解决方案基于@Dan Berlyoung、@deewilcox 和@Chris K 的回答。
这些答案的一部分在 CakePHP 2.2.1 中(对我来说)不起作用。
我还扩展了该解决方案,以支持从前端“强制”移动/桌面/其他布局 - 对于调试和不想被“移动”主题布局卡住的用户很有用。
/app/Controller/AppController.php
class AppController extends Controller {
public $components = array('Cookie');
public $is_mobile = false;
public $layouts = array('desktop', 'mobile');
// executed before every action in the controller
function beforeFilter()
{
// Using "rijndael" encryption because the default "cipher" type of encryption fails to decrypt when PHP has the Suhosin patch installed.
// See: http://cakephp.lighthouseapp.com/projects/42648/tickets/471-securitycipher-function-cannot-decrypt
$this->Cookie->type('rijndael');
// When using "rijndael" encryption the "key" value must be longer than 32 bytes.
$this->Cookie->key = 'qSI242342432qs*&sXOw!adre@34SasdadAWQEAv!@*(XSL#$%)asGb$@11~_+!@#HKis~#^'; // When using rijndael encryption this value must be longer than 32 bytes.
// Flag whether the layout is being "forced" i.e overwritten/controlled by the user (true or false)
$forceLayout = $this->Cookie->read('Options.forceLayout');
// Identify the layout the user wishes to "force" (mobile or desktop)
$forcedLayout = $this->Cookie->read('Options.forcedLayout');
// Check URL paramaters for ?forcedLayout=desktop or ?forcedLayout=mobile and persist this decision in a COOKIE
if( isset($this->params->query['forcedLayout']) && in_array($this->params->query['forcedLayout'], $this->layouts) )
{
$forceLayout = true;
$forcedLayout = $this->params->query['forcedLayout'];
$this->Cookie->write('Options.forceLayout', $forceLayout);
$this->Cookie->write('Options.forcedLayout', $forcedLayout);
}
// We use CakePHP's built in "mobile" User-Agent detection (a pretty basic list of UA's see: /lib/Cake/Network/CakeRequest.php)
// Note: For more robust detection consider using "Mobile Detect" (https://github.com/serbanghita/Mobile-Detect) or WURL (http://wurfl.sourceforge.net/)
if( ( $forceLayout && $forcedLayout == 'mobile' ) || ( !$forceLayout && $this->request->is('mobile') ) ) {
$this->is_mobile = true;
$this->autoRender = false; // take care of rendering in the afterFilter()
}
$this->set('is_mobile', $this->is_mobile);
}
// executed after all controller logic, including the view render.
function afterFilter() {
// if in mobile mode, check for a vaild layout and/or view and use it
if( $this->is_mobile ) {
$has_mobile_view_file = file_exists( ROOT . DS . APP_DIR . DS . 'View' . DS . $this->name . DS . 'mobile' . DS . $this->action . '.ctp' );
$has_mobile_layout_file = file_exists( ROOT . DS . APP_DIR . DS . 'View' . DS . 'Layouts' . DS . 'mobile' . DS . $this->layout . '.ctp' );
$view_file = ( $has_mobile_view_file ? 'mobile' . DS : '' ) . $this->action;
$layout_file = ( $has_mobile_layout_file ? 'mobile' . DS : '' ) . $this->layout;
$this->render( $view_file, $layout_file );
}
}
}
/app/View/Elements/default_footer.ctp
<ul>
<?php
$paramsQuery = $this->params->query;
if(!is_array($paramsQuery))
{
$paramsQuery = array();
}
$paramsQuery['url'] = ( isset($paramsQuery['url']) ) ? $paramsQuery['url'] : '';
$url = $paramsQuery['url'];
unset($paramsQuery['url']);
$params = $paramsQuery;
$mobile_url = '/' . $url . '?' . http_build_query( array_merge( $params, array( 'forcedLayout' => 'mobile' ) ) );
$desktop_url = '/' . $url . '?' . http_build_query( array_merge( $params, array( 'forcedLayout' => 'desktop' ) ) );
?>
<?php if($is_mobile): ?>
<li><?= $this->Html->link('Desktop Site', $desktop_url, array('target' => '', 'class' => '')) ?></li>
<?php else: ?>
<li><?= $this->Html->link('Mobile Site', $mobile_url, array('target' => '', 'class' => '')) ?></li>
<?php endif; ?>
</ul>
/app/View/Layouts/default.ctp
<h1>Desktop Site Layout</h1>
<?= $this->fetch('content') ?>
/app/View/Layouts/mobile/default.ctp
<h1>Mobile Site Layout</h1>
<?= $this->fetch('content') ?>
/app/View/Pages/home.ctp
<h2>Home - on Desktop</h2>
<?= $this->element('default_footer') ?>
/app/View/Pages/mobile/home.ctp
<h2>Home - on Mobile</h2>
<?= $this->element('default_footer') ?>
用法
使用default_footer 链接更改布局 - 或这些直接网址
http://example.com/pages/home?forcedLayout=desktop
http://example.com/pages/home?forcedLayout=mobile
会话 COOKIE 会保留您选择的选项...例如尝试设置为“移动”,然后访问没有forcedLayout= 参数的网址。
http://example.com/pages/home
default_footer 链接保留现有参数(“片段”#gohere 除外)
http://example.com/pages/home/a/b/c:d?this=that&foo=bar#gohere
桌面网址为:
http://example.com/pages/home/a/b/c:d?this=that&foo=bar&forcedLayout=desktop
要获得更强大的设备用户代理检测,请考虑使用Mobile Detect PHP 库...然后您可以针对平板电脑,甚至特定的设计操作系统版本...哦,真有趣! ^_^