1

我正在尝试在实时站点上测试一些新功能。

我的目标是有一个前缀(例如“dev”),并让该前缀显示具有默认操作的完整站点,除了我定义为 dev_{action_name} 的那些。

例子:

/dev/orders/create

寻找 OrdersController::dev_create() 动作,如果没有找到,使用 OrdersController::create()。

到目前为止,我设法为路由器制作了一个标准的“dev”前缀,并添加了一些 beforeFilter 魔法,例如:

<?php
//bootstrap.php code:
Configure::write('Routing.prefixes', array('admin', 'dev'));

// AppController::beforeFilter() code:
if (preg_match('/^dev_(.*)$/', $this->params['action'], $subs)){
   $new_action = $subs[1];
   if (method_exists($this, $new_action)){
          $this->params['action'] = $new_action;
    } 
}
?>

这按预期工作,除了完整的路由模式未复制到“dev”,这意味着所有链接都在没有“dev 前缀的情况下呈现,并且我的自定义路由被忽略。

我考虑过使用 .htaccess 规则修复它并在查询字符串中放置一个 dev=true :

#webroot/.htaccess
RewriteRule ^dev(.*)$ index.php?dev=true&%{QUERY_STRING}
#... rewrite conds ...
RewriteRule ^(.*)$ index.php [QSA,L] #original Cake rewrite

但这没有产生任何结果(Cake 仍在解析原始 URL,而不是重新编写的 URL)。

有这样做的“正确”方式吗?

4

2 回答 2

1

我已经用 CakePHP 2.2.1 成功地实现了这一点。这很丑,很长,违反规则,但它有效!:D

文件:/app/webroot/.htaccess

RewriteEngine On
RewriteRule ^dev/(.*)$ $1 //my hack
    //      /dev/orders/create => /orders/create 
    //      /dev/css/main.css => /css/main.css
    // This only changes the url for the next rule
    // Cake would have still parsed /dev/orders/create
    // but this is needed for the sake of static files in app/webroot
//cake native rewrite
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]

文件:bootstrap.php

$url = (!empty($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : ''; 
    //$url is still /dev/orders/create, despite the rewrites

Configure::write('App.dev', false); 
//we use this to check if we're in "dev" mode
//anywhere in the app, just call: 
    //  if ( Configure::read('App.dev') ) ...

//check if URL starts with /dev
if (preg_match('|^/dev|', $url)){ 
    /* the most important thing is to trick CakePHP
    into thinking it's on a /dev/ subfolder on the server
    this preserves all the routing as it 
            should be, not making it prefixed route */
    Configure::write('App.base', '/dev');
    Configure::write('App.dev', true);
    //this changes /dev/orders/create to /orders/create 
            //for Cake's Route parser
    $_SERVER['REQUEST_URI'] = preg_replace('|/dev|', '', $_SERVER['REQUEST_URI']); 
}
?>

至此,我们已经拥有了让 CakePHP 在 /dev/ 下显示站点的完整副本所需的一切。Cake 执行所有默认操作+视图,所有链接都按预期工作(只要您对 URL 使用帮助程序),所有静态文件都得到服务。所有应用程序路径和常量保持不变。

现在来看看一些方法魔法:

<?php
//file: AppController.php
public function invokeAction(CakeRequest $request) {

    if (Configure::read('App.dev')) {
        $new_action = 'dev'.$request->params['action'];
        if (method_exists($this, $new_action)){
            $request->params['action'] = $new_action;
        }
    }


    return parent::invokeAction($request);
}
?>

所有这些使我们能够:

  • 在 /dev/ 上拥有站点的完整工作别名,其中包括路由、前缀、静态文件、数据库连接等。
  • 使用名称前面的“dev”覆盖 ACTION。
  • 有一个用于“dev”或“not dev”的开关(App.dev 配置)

例如:

<?php
//OrdersController.php

//gets called on /admin/orders/view
public function admin_view(){} 

//gets called on /dev/admin/orders/view
public function devadmin_view(){ 
    //views have to be defined manually for DEV actions
    $this->render('devadmin_view'); 
}

//gets called on /admin/orders/add 
//            AND /dev/admin/orders/add
public function admin_add() {} 

?>
于 2012-10-02T07:06:32.647 回答
1

像这样的东西应该做你想做的事。在调用该操作之前,它会检查它是否存在,如果不存在则回退到原始操作。如果您稍后执行此操作,则会引发异常,因为该操作不存在。

可能还有更多,但这是一个开始。

// need to override invokeAction
public function invokeAction(CakeRequest $request) {
  if ($request->prefix == 'dev') {
    if (!method_exists($request->action)) {
      $request->action = str_replace($request->prefix.'_', '', $request->action);
      $request->prefix = null;
    }
  }
  return parent::invokeAction($request);
}
于 2012-10-02T01:11:56.730 回答