为CakePHP中的每个URL添加前缀

时间:2009-11-25 03:17:11

标签: cakephp routing prefix

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

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

它需要使用admin之类的“真实”前缀,理想情况下,可以将裸网址/controller/action重定向到/DEFAULT-LANGUAGE/controller/action

它现在正在为我提供一个改装的应用程序,但它有点像黑客,我需要在大多数链接中手动包含语言参数,这是不好的。

所以问题是双重的:

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

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

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

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

3 个答案:

答案 0 :(得分:14)

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

<强> /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}'));

这允许/controller/action等默认网址使用默认语言(在我的情况下为JPN),而/eng/controller/action等网址则使用其他语言。可以在router_url_language()函数中轻松更改此逻辑。

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

答案 1 :(得分:5)

来自IRC的rchavik建议使用此链接:CakePHP URL based language switching for i18n and l10n internationalization and localization

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

答案 2 :(得分:0)

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

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

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