如果给定的操作不存在,则定义Cakephp Route以调用特定控制器

时间:2017-05-19 07:46:04

标签: php cakephp routes

  

使用CakePHP v3.3.16

我想写一个后备路由,如果URL没有连接到任何操作,那么它应该转到该后备。

为此类

创建了SEO友好网址的路由
   $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 ,它会转到网站/品牌/索引/索引

如果我必须删除它,我必须创建一个像这样的路径

$routes->connect('/cart',['controller' => 'Cart'], ['routeClass' => 'DashedRoute']);

依此类推其他控制器进行访问。

实施例: 我有一个控制器 CartController 操作 addCart

  

案例1

如果我访问网址my_project/cart/addCart/它应该转到购物车控制器操作

  

案例2

如果我访问网址my_project/abc/xyz/并且没有名为abc的控制器,那么它应该转到 BrandsController 操作索引

My Current 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();

2 个答案:

答案 0 :(得分:3)

您的修改完全无效我的第一个答案,所以我决定发布另一个答案。

路由器无法实现您想要实现的目标,因为路由器无法判断特定路由是否存在控制器/操作。这是因为路由器只使用url模板并委托在请求堆栈中加载控制器的任务。

您可以使用Middleware来模拟此功能  检查请求属性params是否已设置,然后根据需要对其进行验证,如果目标控制器不存在,则将其更改为回退控制器。

只需确保将RoutingMiddleware执行放在中间件之前,否则您将无法检查params,因为路由不会被解析。

中间件实现了一种方法__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中自定义错误模板。

答案 1 :(得分:1)

如果我必须删除它,我必须创建一个这样的路径/依此类推到另一个控制器来访问

不需要在模式中指定每个控制器/名称,而是可以先创建所有指定路由,然后在它们下面放置以下路由以捕获所有不匹配的路由。

$routes->connect(':/prefix/:controller/:action/*', [], ['routeClass' => 'DashedRoute']);

也许另一个没有前缀

$routes->connect('/:controller/:action/*', [], ['routeClass' => 'DashedRoute']);

既然你提到你正在使用3.3.*蛋糕版本,你的路线可以写成路线范围的推荐

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