We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Catch all route

I have a route of the form: /{parent}/{child}/ which I pass to the CategoryController. However, if the {parent} category does not exist, I want to just continue the routing lookup. For example, if that /post/1 was received, and the CategoryController cannot find a category called "post" it will automatically pass it off the the PostController (which is the default behavior). Is there a good way to accomplish this?

Looking forward to this framework.



29.4k

You should use forward method

<?php
class CategoryController extends \Phalcon\Mvc\Controller
{
    public function indexAction()
    {
        // simple example
        if($this->dispatcher->getParam('category') == 'post')
        {
            return $this->dispatcher->forward(array(
                'controller' => 'post',
                'action'     => 'index'
            ));
        }
    }
}


9.1k

Is it possible to do that without enumerating all the possible "non-categories" such as 'post', 'authors', 'popular', etc? Otherwise I fear my code will require me to update the CategoryController and keep it in sync with all new controllers I add down the line.

Further, some of the new controllers may have multiple params such as authors/2233/posts/business which would mean the forward() method would need to be very generic to be able to handle all such requests and pass them along to the appropriate controller.

Thanks a bunch!



29.4k

First of all you have to consider routing, think about any possible URL paths and specify all this parameters in the router. Controller should not worry about it.



9.1k

According to your suggestion I would have to modify my CategoryController every time I add a new route:

if( in_array($this->dispatcher->getParam('category'), array('post', 'author', 'foo', 'bar' )) ...

If tomorrow I add a new controller 'donations' then I must go back to CategoryController and add 'donations'` to that list. Right now, I don't add each controller to the routes list since by convention, it is called automatically.



29.4k

No. You should set all available routes in the router.

$router->add('/(\w+)/:params', [
    'controller' => 'category',
    'category' => 1,
    'params' => 2,
]);

$router->add('/(post|author|foo|bar)/:params', [
    'controller' => 1,
    'params' => 2,
]);


9.1k

Hmm, that's exactly what I was hoping to avoid but I'll use that for lack of a better approach.

Right now in Phalcon and most MVC frameworks, a user creates 'FooController' and all routes starting with '/foo/' go to that controller automatically. This is a big part of MVC's "convention over configuration" approach. With your proposed solution, I'd have to configure every single route and that means the whole idea of using convention is negated (route names map to controllers of the same name which work with views and models of the same name, in most scenarios).



29.4k

You able to set route like this

$router->add(
    "/:controller/:action/:params",
    array(
        "controller" => 1,
        "action"     => 2,
        "params"     => 3,
    )
);

and all routes starting with '/foo/' go to 'FooController' automatically

Check docs https://docs.phalcon.io/en/latest/reference/routing.html



9.1k

It works but I ran into another minor snag. If the URL is /about/index it loads fine, but not if the URL is /about/. I tried adding

$router->setDefaultController("index");
$router->setDefaultAction("index");

but no luck. In AboutController's Intiailize() method I tried die($this->router->getActionName()); which returns an empty string, meaning the action is empty and the default action is not called.



9.1k

It seems more complicated than that, the routes defined prior are handling the request instead of the generic :controller/:action/:params route which is defined at the bottom. Changing the order doesn't help either.

If each route has corresponding controller and action and you want to catch those that don't, you can use notFound method of a router.

If routes are handled by controller that then decides whether request is valid or not valid by looking let's say in the database to check if category is there then controller itself should catch all not found data.

Please clarify and provide some examples.