当用户请求缺少控制器时,路由规则中的CakePHP 2.x语言前缀未应用

当用户请求缺少控制器时,路由规则中的CakePHP 2.x语言前缀未应用,php,exception,cakephp,routing,cakephp-2.x,Php,Exception,Cakephp,Routing,Cakephp 2.x,我想这是一个有点模糊的问题。我已成功为所有路由规则设置语言前缀,以处理本地化。当用户请求应用程序中存在的控制器(例如,/users/view/4)时,一切都非常有效。在我的AppController中,我让应用程序成功地将任何缺少语言前缀的请求重定向到具有语言前缀的URL(例如,/eng/users/view/4) 当用户请求无效的控制器时,会出现问题。在这种情况下,在重定向用户后,应用程序抛出MissingControllerException(它应该这样做),但它报告为无效的控制器是语言前缀

我想这是一个有点模糊的问题。我已成功为所有路由规则设置语言前缀,以处理本地化。当用户请求应用程序中存在的控制器(例如,/users/view/4)时,一切都非常有效。在我的AppController中,我让应用程序成功地将任何缺少语言前缀的请求重定向到具有语言前缀的URL(例如,/eng/users/view/4)

当用户请求无效的控制器时,会出现问题。在这种情况下,在重定向用户后,应用程序抛出MissingControllerException(它应该这样做),但它报告为无效的控制器是语言前缀本身(例如,“EngController”),而不是请求URI中紧跟其后的控制器

这表示在错误状态下,Cake应用程序不再知道任何语言前缀路由。这表明我需要向routes.php添加另一个路由规则,该规则只针对无效的请求,并确保在由CakeErrorController(接管这些类型异常的核心控制器)处理的任何请求中预期并考虑语言前缀

但是我已经浏览了文档,我不知道如何制定这样一条路线。谢谢你的帮助

以下是我的routes.php文件:

<?php


$lang_settings = ['language' => '[a-z]{3}'];

// ElStats homepage vs tenant homepage
if(!TENANT) {
    Router::connect('/', ['controller' => 'pages', 'action' => 'index'], $lang_settings);
    Router::connect('/:language', ['controller' => 'pages', 'action' => 'index'], $lang_settings);
} else {
    Router::connect('/', ['controller' => 'pages', 'action' => 'index'], $lang_settings);
    Router::connect('/:language', ['controller' => 'pages', 'action' => 'index'], $lang_settings);
}


/**
 * ...and connect the rest of 'Pages' controller's urls.
 */

Router::connect('/:language/pages/*', ['controller' => 'pages', 'action' => 'display'], $lang_settings);
Router::connect('/:language/contests/search/*', ['controller' => 'contests', 'action' => 'index'], $lang_settings);
Router::connect('/:language/contests/:action/*', ['controller'=>'contests'], $lang_settings);
Router::connect('/:language/contests/*', ['controller' => 'contests', 'action' => 'index'], $lang_settings);
Router::connect('/:language/candidates/search/*', ['controller' => 'candidates', 'action' => 'index'], $lang_settings);
Router::connect('/:language/candidates/:action/*', ['controller'=>'candidates'], $lang_settings);
Router::connect('/:language/candidates/*', ['controller' => 'candidates', 'action' => 'index'], $lang_settings);

// If just /search, then default to /contests/search
Router::connect('/:language/search/*', ['controller' => 'contests', 'action' => 'index'], $lang_settings);

/**
 * Full-controller alias routing
 */

// ballot_questions => contests
Router::connect('/:language/ballot_questions/search/*', ['controller' => 'contests', 'action' => 'index'], $lang_settings);
Router::connect('/:language/ballot_questions/:action/*', ['controller'=>'contests'], $lang_settings);
Router::connect('/:language/ballot_questions/*', ['controller'=>'contests', 'action' => 'index'], $lang_settings);
Router::connect('/:language/admin/ballot_questions/:action/*', ['controller'=>'contests','admin' => true], $lang_settings);
Router::connect('/:language/admin/ballot_questions/*', ['controller'=>'contests', 'action' => 'index', 'admin' => true], $lang_settings);

// Admin Routing
Router::connect('/:language/admin', [ 'controller'=> 'pages', 'action'=> 'index','admin' => true], $lang_settings);
Router::connect('/:language/admin/:controller/:action/*',['admin' => true], $lang_settings);
Router::connect('/:language/admin/:controller/*',['admin' => true], $lang_settings);
Router::connect('/:language/:controller/:action/*',[], $lang_settings);

require CAKE . 'Config' . DS . 'routes.php';

编辑:更新路由器,使其使用应用程序支持的语言进行反向前瞻

下面是一个示例正则表达式:

^(?!(spa|eng|swe)){1}.*
任何不是以spaengswe开头的路线,您都会将其重定向到控制器和您选择的操作

在您的路由器中

Router::connect(
    '/:language/candidates/search/*',
    array('controller' => 'errorController', 'action' => 'index'),
    array('language' => '^(?!(spa|eng|swe)).*')
);
由于url参数的数量不同,因此每个部分都需要此路由模式

您可以使用各种在线正则表达式工具测试正则表达式。来验证它是否有效


原创帖子:

你可能想得太多了

您的问题是如何为丢失的控制器添加路由,这只有在开发(调试模式)时才会发生。在生产中,这变成了404

因为向开发人员展示缺少的东西是任何适当的框架都应该做的事情(包括CakePHP),所以您不应该为这些情况编写自己的ExceptionHandler来尝试使用一些奇怪的解决方案

相反,您应该看看如何处理404,因为,如前所述,一旦投入生产,该错误消息将默认为404错误消息

以下是相同(缺失)路线的外观:

在开发模式中:

在生产模式中:

处理404 如果要显示404,请说明如何自定义此错误页面

如果您想在404发生时重定向到某个地方,可以执行以下操作():

要捕获和处理404错误,需要扩展ErrorHandler 类并重写error404方法。为此,请创建该文件 app/app_error.php,包含以下代码:

两个旁注

<> >为了使自己更容易理解,请考虑更改路由方案以将语言作为请求参数来代替。否则,搜索引擎(如果你的网站应该是索引的话)会抓取你的语言页面,而这并不总是你想要的

这意味着您将有如下路线:

candidates/list?lang=eng
这样,通过执行以下操作,您可以更轻松地管理无效语言代码的处理:

    // In a controller
    $languageCode = $this->request->params['lang'];
    if (!in_array($language, ['eng', 'spa', 'swe'])) {
      // Set a variable to view to display a wrong error code, or redirect to a default language.
    }

希望所有这些都有意义。

你能用routes.php文件更新你的问题吗?谢谢你的回答。我非常明确地询问如何修复调试模式错误,以使错误不会对我和其他开发人员产生误导。(我很清楚这些是404在生产中。)我有一种感觉,我可以在routes中添加一条班轮来解决这个问题。我宁愿不重构我的路由范式。答案最初有一部分是关于为MissingControllerException编写自定义异常处理程序的,但这个想法太可怕了,我把它删除了。您可以在此处阅读如何创建自己的异常处理程序:@AdamFriedman答案现在有一个更新的建议。看看这个,如果这对你有帮助,请接受答案。
    // In a controller
    $languageCode = $this->request->params['lang'];
    if (!in_array($language, ['eng', 'spa', 'swe'])) {
      // Set a variable to view to display a wrong error code, or redirect to a default language.
    }