如果给定的操作不存在,则定义 Cakephp 路由以调用特定的控制器
Posted
技术标签:
【中文标题】如果给定的操作不存在,则定义 Cakephp 路由以调用特定的控制器【英文标题】:Define Cakephp Route to call specific controller if given action not exists 【发布时间】:2017-10-19 05:55:01 【问题描述】:使用 Cakephp v3.3.16
我想以这样一种方式编写一个后备路由,如果 URL 未连接到任何操作,那么它应该转到该后备。
为这样的 SEO 友好 URL 创建路由
$routes->connect(
':slug',
['prefix'=>'website','controller' => 'Brands', 'action' => 'index'],
['routeClass' => 'DashedRoute']
);
$routes->connect(
':slug/*',
['prefix'=>'website','controller' => 'Products', 'action' => 'index'],
['routeClass' => 'DashedRoute']
);
但它也包含所有控制器操作,所以如果我尝试调用控制器 ex: cart/index 它会转到 website/brands/index/index
如果我必须删除排除它,我必须创建这样的路线/
$routes->connect('/cart',['controller' => 'Cart'], ['routeClass' => 'DashedRoute']);
等到其他控制器去访问。
示例: 我有一个控制器 CartController 动作 addCart
案例 1
如果我访问 URL my_project/cart/addCart/
它应该转到购物车控制器操作
案例 2
如果我访问 URL my_project/abc/xyz/
并且没有名为 abc 的控制器,那么它应该转到 BrandsController 操作 index
我当前的 routes.php 看起来像这样
Router::defaultRouteClass(DashedRoute::class);
Router::scope('/', function (RouteBuilder $routes)
$routes->connect('/', ['prefix'=>'website','controller' => 'Home', 'action' => 'index']);
$routes->connect('/trending-brands', ['prefix'=>'website','controller' => 'Brands', 'action' => 'trending']);
$routes->connect('/users/:action/*',['prefix'=>'website','controller' => 'Users'], ['routeClass' => 'DashedRoute']);
$routes->connect('/cart',['prefix'=>'website','controller' => 'Cart'], ['routeClass' => 'DashedRoute']);
$routes->connect('/cart/:action/*',['prefix'=>'website','controller' => 'Cart'], ['routeClass' => 'DashedRoute']);
$routes->connect(
':slug',
['prefix'=>'website','controller' => 'Brands', 'action' => 'index'],
['routeClass' => 'DashedRoute']
);
$routes->connect(
':slug/*',
['prefix'=>'website','controller' => 'Products', 'action' => 'index'],
['routeClass' => 'DashedRoute']
);
$routes->connect(':controller', ['prefix'=>'website'], ['routeClass' => 'DashedRoute']);
$routes->connect(':controller/:action/*', ['prefix'=>'website'], ['routeClass' => 'DashedRoute']);
$routes->fallbacks(DashedRoute::class);
);
Router::prefix('website', function (RouteBuilder $routes)
$routes->fallbacks(DashedRoute::class);
);
Plugin::routes();
【问题讨论】:
您确实应该将无效的 URL 发送到 404 页面。 请问您的问题好吗?你的意思是如果 domain.comcart/any 动作然后它会去购物车控制器,否则它会去麸皮控制器? 是的,但如果购物车控制器存在。例如:如果我们点击 domain.com/cart/any 并且购物车控制器不存在,它将转到品牌,否则它将转到品牌控制器,购物车被视为 slug 【参考方案1】:您的编辑完全使我的第一个答案无效,所以我决定只发布另一个答案。
路由器无法完成您想要实现的目标,因为路由器无法判断特定路由是否存在控制器/动作。这是因为路由器只使用 url 模板并委托在请求堆栈中加载控制器的任务。
您可以使用Middleware 来模拟此功能
检查是否设置了请求属性params
,然后适当地验证它们,如果目标控制器不存在,则将它们更改为您的备用控制器。
只需确保将 RoutingMiddleware
执行放在中间件之前,否则您将没有要检查的参数,因为路由不会被解析。
中间件实现一种方法__invoke()
。
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Cake\Http\ControllerFactory;
use Cake\Routing\Exception\MissingControllerException;
class _404Middleware
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $next)
//$params = (array)$request->getAttribute('params', []);
try
$factory = new ControllerFactory();
$controller = $factory->create($request, $respond);
catch (\Cake\Routing\Exception\MissingControllerException $e)
// here you fallback to your controllers/action or issue app level redirect
$request = $request->withAttribute('params',['controller' =>'brands','action' => 'index']);
return $next($request, $response);
然后附上你的App\Application
,另见attaching middlewares
$middlewareStack->add(new _404Middleware());
请记住清理代码,因为我没有在真实的开发环境下测试它。
经过深思熟虑:如果您希望为所有未找到的资源创建一个错误页面,那么您不需要所有这些,而是只需自定义 Template/Error/error404.ctp
中的错误模板。
【讨论】:
你能举个例子吗?会更合适【参考方案2】:如果我必须删除排除它,我必须创建一个这样的路由/等到另一个控制器访问。
不需要在模式中指定每个控制器/名称,而是可以先创建所有指定的路由,然后在它们下面放置以下路由以捕获所有不匹配的路由。
$routes->connect(':/prefix/:controller/:action/*', [], ['routeClass' => 'DashedRoute']);
也许还有一个不带前缀的
$routes->connect('/:controller/:action/*', [], ['routeClass' => 'DashedRoute']);
并且由于您提到您使用的是3.3.*
cake 版本,您的路线可以利用路线范围
Router::prefix('website', function ($routes)
// All routes here will be prefixed with `/prefix`
// And have the prefix => website route element added.
$routes->fallbacks(DashedRoute::class);
$routes->connect(
'/:slug',
['controller' => 'Brands', 'action' => 'index']
);
$routes->connect(
':slug/*',
['controller' => 'Products', 'action' => 'index']
);
【讨论】:
尝试无法正常工作,因为我的 url 与第一条规则匹配,但它不会与其他规则匹配。 4 或 5,但我想概括一下,因为它可以根据需要扩展。 你所有的控制器都加前缀了吗?给我看看你所有的自定义路由。以上是关于如果给定的操作不存在,则定义 Cakephp 路由以调用特定的控制器的主要内容,如果未能解决你的问题,请参考以下文章