在 CakePHP 中为每个 URL 添加前缀

Adding a prefix to every URL in CakePHP

提问人:deceze 提问时间:11/25/2009 最后编辑:deceze 更新时间:9/28/2012 访问量:16303

问:

在 CakePHP 中为每个 URL 添加前缀的最干净的方法是什么,比如语言参数?

http://example.com/en/controller/action
http://example.com/ru/admin/controller/action

它需要使用“真实”前缀,例如 ,理想情况下,裸 URL 可以重定向到 。admin/controller/action/DEFAULT-LANGUAGE/controller/action

它现在对我来说正在一个改装的应用程序中工作,但它是一种黑客攻击,我需要在大多数链接中手动包含语言参数,这并不好。

所以问题有两个方面:

  • 构建路由的最佳方式是什么,以便默认情况下隐式包含语言参数,而不必为每个新定义的路由指定?
    • Router::connect('/:controller/:action/*', ...)应隐式包含前缀。
    • 该参数应在 中可用,或在类似的地方可用,以便在 中计算。$this->params['lang']AppController::beforeFilter()
  • 如果没有明确指定,如何自动将前缀包含在 URL 中?Router::url()
    • Router::url(array('controller' => 'foo', 'action' => 'bar'))应该返回/en/foo/bar
    • 由于 ,甚至直接需要具有相同的行为,因此覆盖每个函数并不是一个真正的选项。 例如,应该生成一个无前缀的 URL。Controller::redirect()Form::create()Router::url()Html::image()

以下方法似乎调用 .Router::url

  • Controller::redirect
  • Controller::flash
  • Dispatcher::__extractParams通过Object::requestAction
  • Helper::url
  • JsHelper::load_
  • JsHelper::redirect_
  • View::uuid,但仅适用于哈希生成

在这些方法中,似乎需要覆盖 Controller 和 Helper 方法,我可以没有 .我的想法是编写一个通用函数,或者可能只是编写一个通用函数来处理参数插入。重写的 Controller 和 Helper 方法将使用此函数,如果我想手动调用 ,我也会使用此函数。这就足够了吗?JsHelperAppControllerbootstrap.phpRouter::url

cakephp 路由 前缀

评论


答:

5赞 Joe Phillips 11/25/2009 #1

来自 IRC 的 rchavik 推荐了这个链接: 基于 CakePHP URL 的语言切换,用于 i18n 和 l10n 国际化和本地化

一般来说,覆盖似乎是解决方案。Helper::url

评论

0赞 deceze 11/25/2009
根据评论,覆盖将为控制器做到这一点。到目前为止一切顺利,还有别的吗?其他部分直接调用吗?AppController::urlRouter::url
14赞 deceze 12/10/2009 #2

这基本上是我最终为解决这个问题而实现的所有代码(至少我认为仅此而已;-)):

/config/bootstrap.php

define('DEFAULT_LANGUAGE', 'jpn');

if (!function_exists('router_url_language')) {
    function router_url_language($url) {
        if ($lang = Configure::read('Config.language')) {
            if (is_array($url)) {
                if (!isset($url['language'])) {
                    $url['language'] = $lang;
                }
                if ($url['language'] == DEFAULT_LANGUAGE) {
                    unset($url['language']);
                }
            } else if ($url == '/' && $lang !== DEFAULT_LANGUAGE) {
                $url.= $lang;
            }
        }

        return $url;
    }
}

/config/core.php

Configure::write('Config.language', 'jpn');

/app_helper.php

class AppHelper extends Helper {

    public function url($url = null, $full = false) {
        return parent::url(router_url_language($url), $full);
    }

}

/app_controller.php

class AppController extends Controller {

    public function beforeFilter() {
        if (isset($this->params['language'])) {
            Configure::write('Config.language', $this->params['language']);
        }
    }

    public function redirect($url, $status = null, $exit = true) {
        parent::redirect(router_url_language($url), $status, $exit);
    }

    public function flash($message, $url, $pause = 1) {
        parent::flash($message, router_url_language($url), $pause);
    }

}

/config/routes.php

Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
Router::connect('/pages/*', array('controller' => 'pages', 'action' => 'display'));
Router::connect('/:language/', array('controller' => 'pages', 'action' => 'display', 'home'), array('language' => '[a-z]{3}'));
Router::connect('/:language/pages/*', array('controller' => 'pages', 'action' => 'display'), array('language' => '[a-z]{3}'));
Router::connect('/:language/:controller/:action/*', array(), array('language' => '[a-z]{3}'));

这允许默认 URL 喜欢使用默认语言(在我的情况下是 JPN),而 URL 喜欢使用替代语言。这个逻辑可以很容易地在函数中改变。/controller/action/eng/controller/actionrouter_url_language()

为此,我还需要为每条路由定义两条路由,一条包含参数,一条不包含参数。至少我无法弄清楚如何以另一种方式做到这一点。/:language/

评论

2赞 deceze 12/16/2010
@gacrux 请注意,这在 Cake 1.3 中应该不那么复杂,其中包括可自定义的前缀。以上适用于 Cake 1.2,它只知道一个前缀。:)
0赞 Simon East 9/28/2012 #3

一种更简单的方法可能是将所选语言存储在 cookie 中,然后不必重写所有 URL。您还可以自动检测用户的浏览器语言。

但是,搜索引擎不太可能选择各种语言,如果有人试图共享链接,您也会失去该语言。

但是喜欢您发布的完整解决方案,非常全面,谢谢。:-)

评论

1赞 deceze 9/28/2012
“无 URL”语言切换的问题在于搜索引擎。他们只会为一种语言编制索引,或者如果他们在同一 URL 上看到不同的内容,他们会把他们的内裤分成一堆。这仅适用于您网站的私人(仅限登录)区域。
0赞 Simon East 9/28/2012
哦,是的,这是一个很好的观点。我将更新我的答案以注意这一点。