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

Dynamic routing (with save route in database)

Hi guys!

how to call Route of the database, if it is not in the list of standard routing. This code works, but it does not work for some reason /users/{id} (return 404)

Routes.php:

$router = new Phalcon\Mvc\Router(false);

$router->removeExtraSlashes(true);

$router->notFound(array(
    'controller' => 'Page',
    'action' => '_404'
));

/**
*   See it! ↓
*/
$router->add('{url:[a-zA-Z0-9\.\/]+}', array(
    'controller' => 'url',
    'action' => 'distrib',
));

$router->add('/', array(
    'controller' => 'index',
    'action'     => 'index',
));

$router->add('/login', array(
    'controller' => 'Auth',
    'action'     => 'login',
));

$router->add('/user/{id:[0-9]+}', array(
    'controller' => 'Users',
    'action'     => 'profile',
));

$router->add('/biz/{alias:[a-z0-9-]+}', array(
    'controller' => 'Biz',
    'action'     => 'show',
));

UrlController(distribAction):

public function distribAction() {

    $url = $this->dispatcher->getParam('url');

    $urlFound = Urls::findFirstByUrl($url);

    // Если URL найден
    // If URL found
    if($urlFound) {

        // Если это старый урл, делаем 301 на новый
        // If it a old url, make 301 to new
        if($urlFound->as301) {
            $this->view->disable();
            $this->response->redirect($urlFound->as301, true, 301)->send();

        }

        // Или передаем управление указанному контроллеру
        // Or forward to selected controller
        else {
            $this->dispatcher->forward([
                'controller' => $urlFound->controller,
                'action' => $urlFound->action,
                'params' => $urlFound->params,
            ]);
        }
    }

    // Если URL не найден, отдаем 404
    // If URL not found - forward to 404-Page
    else {

        $this->dispatcher->forward([
            'controller' => 'Page',
            'action' => '_404',
        ]);

    }

}

Database table url:

This route

$router->add('{url:[a-zA-Z0-9\.\/]+}', array(
    'controller' => 'url',
    'action' => 'distrib',
));

should be registered as last because it matches /user/{id:[0-9]+} and also /biz/{alias:[a-z0-9-]+}

David, it work, but not fully.

/biz/blablabla returned 404, although the database has a record with the redefinition let authorization (for the test controller: auth action: login)

sorry for my dialect

maybe need use events manager for detect no-found event in routes, and handmade override controller and action via database... im dont know



9.3k
Accepted
answer
edited Apr '16

Your application and routing logic seems to bee too complicated, I really recommed you to simplify it. I you cant do it, then you can use Error controller as your fallback controller for DB URLs.

Something like this should work, because on all failed matches from regular routes you will try to find them in database and if not found, you will redirect it to error page.

$router = new Phalcon\Mvc\Router(false);

$router->removeExtraSlashes(true);

$router->notFound(array(
    'controller' => 'url',
    'action' => 'distrib'
));

$router->add('/', array(
    'controller' => 'index',
    'action'     => 'index',
));

$router->add('/login', array(
    'controller' => 'Auth',
    'action'     => 'login',
));

$router->add('/user/{id:[0-9]+}', array(
    'controller' => 'Users',
    'action'     => 'profile',
));

$router->add('/biz/{alias:[a-z0-9-]+}', array(
    'controller' => 'Biz',
    'action'     => 'show',
));

Thank you, I will do so and follow your recommendations. In consequence of my inexperience with this framework, the I am more than sure that many things can be simplified. but in your example, I do not understand how I get url distribAction in action, which is to be found in the database.

public function distribAction() 
{
    $url = $this->request->getURI();
    ...
}

Thanks David.