CakePHP网站手机版

发布于 2024-09-26 08:16:55 字数 208 浏览 5 评论 0原文

我已经使用 CakePHP 框架开发了一个完整的网站,我们想为移动设备(主要是 iPhone/iPad)制作一个非常轻量级的网站版本。

有没有办法将现有网站与新的子域(例如 mobile.mywebsite.com)一起使用,以呈现特定的视图?我想避免复制和简化当前的要求来满足新的要求。我不想“重新开发”一个新的 CakePHP 网站,并且每次需要更改控制器操作时都需要进行两次更改。

I have developed a full website with CakePHP framework and we'd like to make a very light version of the website for mobile devices (mainly iPhone/iPad).

Is there a way to use the existing website with a new sub domain (for instance mobile.mywebsite.com) which will render specific views? I would like to avoid copying and simplifying the current one to match the new one requirements. I do not want to have to "re-develop" a new CakePHP website and do the changes twice every time I need to change a controller action.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

断爱 2024-10-03 08:16:55

我通过在 app_controller.php 文件中的 beforeFilter() 中快速添加来完成此操作。

function beforeFilter() {
     if ($this->RequestHandler->isMobile()) {
        $this->is_mobile = true;
        $this->set('is_mobile', true );
        $this->autoRender = false;
     }
}

它使用 CakePHP RequestHandler 来感知是否是移动设备访问我的网站。它设置属性和视图变量,以允许操作和视图根据新布局进行自我调整。还关闭自动渲染,因为我们将在 afterFilter 中处理它。

在 afterFilter() 中,它会查找并使用移动视图文件(如果存在)。移动版本存储在控制器视图文件夹内的“移动”文件夹中,并且名称与普通非移动版本完全相同。 (即 add.ctp 变为 mobile/add.ctp)

    function afterFilter() {
        // if in mobile mode, check for a valid view and use it
        if (isset($this->is_mobile) && $this->is_mobile) {
            $view_file = new File( VIEWS . $this->name . DS . 'mobile/' . $this->action . '.ctp' );
            $this->render($this->action, 'mobile', ($view_file->exists()?'mobile/':'').$this->action);
        }
     }

I've done this using a quick addition to the beforeFilter() in my app_controller.php file.

function beforeFilter() {
     if ($this->RequestHandler->isMobile()) {
        $this->is_mobile = true;
        $this->set('is_mobile', true );
        $this->autoRender = false;
     }
}

This uses the CakePHP RequestHandler to sense if it's a mobile device visiting my site. It sets a property and view variable to allow actions an views to adjust themselves based on the new layout. Also turns off the autoRender because we'll take care of that in an afterFilter.

In the afterFilter() it looks for and uses a mobile view file if one exists. Mobile versions are stored in a 'mobile' folder inside the controller's view folder and are named exactly the same as the normal non-mobile versions. (ie. add.ctp becomes mobile/add.ctp)

    function afterFilter() {
        // if in mobile mode, check for a valid view and use it
        if (isset($this->is_mobile) && $this->is_mobile) {
            $view_file = new File( VIEWS . $this->name . DS . 'mobile/' . $this->action . '.ctp' );
            $this->render($this->action, 'mobile', ($view_file->exists()?'mobile/':'').$this->action);
        }
     }
往日情怀 2024-10-03 08:16:55

丹的回答对我有用。但是,我使用 file_exists 而不是 File 构造函数,并添加了使用移动布局的功能。 before 过滤器是相同的,但 afterFilter 看起来像这样:

function afterFilter() {
    // if in mobile mode, check for a valid view and use it
    if (isset($this->is_mobile) && $this->is_mobile) {
        $view_file = file_exists( VIEWS . $this->name . DS . 'mobile/' . $this->action . '.ctp' );
        $layout_file = file_exists( LAYOUTS . 'mobile/' . $this->layout . '.ctp' );

        $this->render($this->action, ($layout_file?'mobile/':'').$this->layout, ($view_file?'mobile/':'').$this->action);
    }
 }

Dan's answer worked for me. However, I used file_exists instead of the File constructor and added the ability to use mobile layouts. The before filter was the same, but the afterFilter looked like this:

function afterFilter() {
    // if in mobile mode, check for a valid view and use it
    if (isset($this->is_mobile) && $this->is_mobile) {
        $view_file = file_exists( VIEWS . $this->name . DS . 'mobile/' . $this->action . '.ctp' );
        $layout_file = file_exists( LAYOUTS . 'mobile/' . $this->layout . '.ctp' );

        $this->render($this->action, ($layout_file?'mobile/':'').$this->layout, ($view_file?'mobile/':'').$this->action);
    }
 }
情栀口红 2024-10-03 08:16:55

您可以使用 CakePHP 2.x 中的主题功能进行移动布局。

简单地做:

if($this->RequestHandler->isMobile())
    $this->theme = 'mobile';

我发现这更好,因为您可以轻松地在移动和桌面主题上共享视图文件。

You can use Theme feature in CakePHP 2.x for mobile layout.

Simply do:

if($this->RequestHandler->isMobile())
    $this->theme = 'mobile';

I found this better, as you can share View file on mobile and desktop theme easily.

ゝ杯具 2024-10-03 08:16:55

我为 CakePHP 2.1 应用程序修改了这项技术。这是我的 beforeFilter()

public function beforeFilter() {

if ($this->request->isMobile()){
    $this->is_mobile = true;
        $this->set('is_mobile', true );
        $this->autoRender = false;
}

}

这是我的 afterFilter()

function afterFilter() {
    // if in mobile mode, check for a valid view and use it
    if (isset($this->is_mobile) && $this->is_mobile) {
        $view_file = file_exists( 'Views' . $this->name . DS . 'mobile/' . $this->action . '.ctp' );
        $layout_file = file_exists( 'Layouts' . 'mobile/' . $this->layout . '.ctp' );
        if($view_file || $layout_file){
            $this->render($this->action, ($layout_file?'mobile/':'').$this->layout, ($view_file?'mobile/':'').$this->action);
        }
    }
 }

这有助于解释 CakePHP 2 中已弃用的措辞和常量。

I modified this technique for a CakePHP 2.1 app. Here is my beforeFilter():

public function beforeFilter() {

if ($this->request->isMobile()){
    $this->is_mobile = true;
        $this->set('is_mobile', true );
        $this->autoRender = false;
}

}

And here is my afterFilter():

function afterFilter() {
    // if in mobile mode, check for a valid view and use it
    if (isset($this->is_mobile) && $this->is_mobile) {
        $view_file = file_exists( 'Views' . $this->name . DS . 'mobile/' . $this->action . '.ctp' );
        $layout_file = file_exists( 'Layouts' . 'mobile/' . $this->layout . '.ctp' );
        if($view_file || $layout_file){
            $this->render($this->action, ($layout_file?'mobile/':'').$this->layout, ($view_file?'mobile/':'').$this->action);
        }
    }
 }

This helps account for deprecated verbiage and constants in CakePHP 2.

疯了 2024-10-03 08:16:55

简单的解决方案是使用相应的样式表创建一个新的“移动”布局,并在 AppController 中将其打开:

public $components = array('RequestHandler');
public function beforeRender() {
    parent::beforeRender();
    if ($this->RequestHandler->isMobile()) {
        $this->layout = 'mobile';
    }
}

beforeRender() 中执行此操作非常重要,以防万一您更改 控制器方法中的 $this->layout

The simple solution is to create a new 'mobile' layout with respective stylesheet(s) and turn it on in AppController:

public $components = array('RequestHandler');
public function beforeRender() {
    parent::beforeRender();
    if ($this->RequestHandler->isMobile()) {
        $this->layout = 'mobile';
    }
}

It is important to do that in beforeRender() in case if you change $this->layout in your controllers' methods.

Smile简单爱 2024-10-03 08:16:55

CakePHP v2.2.1 解决方案(+ Cookie 以保留移动/桌面/其他布局)

该解决方案基于 @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 com/pages/home/a/b/c:d?this=that&foo=bar&forcedLayout=desktop

对于更强大的设备用户代理检测,请考虑使用 Mobile Detect PHP 库...然后您可以定位平板电脑,甚至特定的设计操作系统版本...哦,多有趣! ^_^

CakePHP v2.2.1 Solution (+ Cookies to persist mobile/desktop/other layout)

This solution is based on answers by @Dan Berlyoung, @deewilcox and @Chris K.

Parts of those answers failed to work (for me) in CakePHP 2.2.1.

I also extended the solution to support "forcing" a mobile/desktop/other layout from the frontend - useful for debugging and for users that don't want to be stuck on a "mobile" themed layout.

/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') ?>

Usage

Use the default_footer links to change layout - or these direct urls
http://example.com/pages/home?forcedLayout=desktop
http://example.com/pages/home?forcedLayout=mobile

A session COOKIE persists the option you've chosen... e.g. try setting to "mobile" and then visit a url without the forcedLayout= param.
http://example.com/pages/home

The default_footer links persist existing params (except for the "fragment" #gohere)
http://example.com/pages/home/a/b/c:d?this=that&foo=bar#gohere

Desktop Site url is:
http://example.com/pages/home/a/b/c:d?this=that&foo=bar&forcedLayout=desktop

For more robust device User-Agent detection consider using the Mobile Detect PHP Library ... you could then target Tablets, and even specific devise OS versions.... Oh what fun! ^_^

一花一树开 2024-10-03 08:16:55

我采用的解决方案是基于此处的一些答案对 CakePHP 2.5.5 进行的轻量级修改。处理全部在 beforeRender 中完成(请注意,beforeRender 仅在实际渲染页面的控制器操作上运行,因此与私有方法的 beforeFilter/afterFilter 相比,这节省了开销):

$mobile = $this->request->is('mobile');
$this->set('mobile',$mobile);
//Check if an alternate mobile view and/or layout exists for this request.
if($mobile){
    if(file_exists(APP.'View'.DS.$this->name.DS.'mobile'.DS.$this->view.'.ctp')){
        //Render this action on its mobile view.
        $this->view = 'mobile'.DS.$this->view;
    }
    if(file_exists(APP.'View'.DS.'Layouts'.DS.'mobile'.DS.$this->layout.'.ctp' )){
        //Render this action on its mobile layout.
        $this->layout = 'mobile'.DS.$this->layout;
    }
}

$mobile 变量可以在任何视图上使用如果您需要进行一些小调整,否则您可以选择使用 View/{controller}/mobile/same_file_name.ctp 替换任何视图,或使用 View/Layouts/mobile/same_file_name.ctp 替换布局,以完全拥有独立的页面结构。

请注意,这使用 $this->view 和 $this->layout 然后修改它们,而不是使用 $this->action 和 $this->render(view,layout),因为你的视图不会始终匹配您的操作(同一视图,多个操作,例如,使用 $this->action 进行中断),并且此解决方案无需担心何时强制 $this->render() ,并允许它发生自然。

The solution I went with was a lightweight modification based on a few of the answers here, for CakePHP 2.5.5. The handling is all done in the beforeRender (note that beforeRender is only run on controller actions that will actually render a page, so this saves overhead as opposed to beforeFilter/afterFilter for private methods):

$mobile = $this->request->is('mobile');
$this->set('mobile',$mobile);
//Check if an alternate mobile view and/or layout exists for this request.
if($mobile){
    if(file_exists(APP.'View'.DS.$this->name.DS.'mobile'.DS.$this->view.'.ctp')){
        //Render this action on its mobile view.
        $this->view = 'mobile'.DS.$this->view;
    }
    if(file_exists(APP.'View'.DS.'Layouts'.DS.'mobile'.DS.$this->layout.'.ctp' )){
        //Render this action on its mobile layout.
        $this->layout = 'mobile'.DS.$this->layout;
    }
}

The $mobile variable can be used on any view if you have small tweaks to make, otherwise you can optionally replace any view with View/{controller}/mobile/same_file_name.ctp or layout with View/Layouts/mobile/same_file_name.ctp to have a separate page structure entirely.

Note that this uses $this->view and $this->layout and then modifies them, instead of using $this->action and $this->render(view,layout), because your view won't always match your action (same view, multiple actions, for example, break using $this->action), and this solution prevents needing to worry about when $this->render() will be forced, and allows it to happen naturally.

逆夏时光 2024-10-03 08:16:55

是的,您可以重新使用所有域和控制器,请查看 Tera-WURLF

更好的是,您不需要移动版本的子域。

Yes, you can re use all of your domain and controllers, have a look to Tera-WURLF

And even better, you don't need a subdomain for the mobile version.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文