Using Router Annotations with other routes in Phalcon - php

Is it possible to use annotations on top of regular routes in Phalcon. For example, I have this:
$router->add('/', [
'module' => 'home',
'controller' => 'index',
'action' => 'index'
])->setName('home');
$router->notFound([
'module' => 'home',
'namespace' => 'Home\Controller',
'controller' => 'error',
'action' => 'show404'
]);
foreach ($app->getModules() as $key => $module) {
$router->add('/'.$key.'/:params', [
'module' => $key,
'controller' => 'index',
'action' => 'index',
'params' => 1
])->setName($key);
$router->add('/'.$key.'/:controller/:params', [
'module' => $key,
'controller' => 1,
'action' => 'index',
'params' => 2
]);
$router->add('/'.$key.'/:controller/:action/:params', [
'module' => $key,
'controller' => 1,
'action' => 2,
'params' => 3
]);
}
$router->addModuleResource('api', 'Api\\Controller\\Index', '/api/index');
$router->addModuleResource('api', 'Api\\Controller\\Client', '/api/client');
The problem is that the router annotations that I define near the bottom don't seem to work, probably because the routes to /api/index and /api/client have already been defined above.
Also, at the same time, is there a way to define a notFound for a module? Basically, if I'm at some URL that starts with /api/, I would like it to go to an error page in my api module. Otherwise, it should go to error page in the regular module.

Related

Phalcon route conflict

I have a problem with routes on phalcon. I have code:
$router->add('/{aliascat:[0-9\-a-z\-]+}(/?)', array(
'module' => 'frontend',
'controller' => 'category',
'action' => 'view',
'category' => 1,
'lang' => 'md',
))->setName('category_view_cpu');
$router->add('/{lang:[' . $langsDefined . ']{2}+}/{aliascat:[0-9\-a-z\-]+}(/?)', array(
'module' => 'frontend',
'controller' => 'category',
'action' => 'view',
'category' => 2,
'lang' => 1,
))->setName('category_view_cpu');
$router->add('/{controller:[a-z]{3,50}+}(/?)', array(
'module' => 'frontend',
'controller' => 1,
'action' => 'index',
'lang' => 'md',
))->setName('default_module');
$router->add('/{lang:[' . $langsDefined . ']{2}+}/{controller:[a-z]{3,50}+}(/?)', array(
'module' => 'frontend',
'controller' => 2,
'action' => 'index',
'lang' => 1,
))->setName('default_module_lang');
$router->add('/{controller:[a-z]{3,50}+}/:action/', array(
'module' => 'frontend',
'controller' => 1,
'action' => 2,
'lang' => 'md',
))->setName('default_module_controller_action');
$router->add('/{lang:[' . $langsDefined . ']{2}+}/{controller:[a-z]{3,50}+}/:action/', array(
'module' => 'frontend',
'controller' => 2,
'action' => 3,
'lang' => 1,
))->setName('default_module_controller_action_lang');
$router->add('/{controller:[a-z]{3,50}+}/:action/:params/', array(
'module' => 'frontend',
'controller' => 1,
'action' => 2,
'params' => 3,
'lang' => 'md',
))->setName('default_module_controller_action_params');
$router->add('/{lang:[' . $langsDefined . ']{2}+}/{controller:[a-z]{3,50}+}/:action/:params/', array(
'module' => 'frontend',
'controller' => 2,
'action' => 3,
'params' => 4,
'lang' => 1,
))->setName('default_module_controller_action_params_lang');
I get undifined controller for category route, because conflict with default_module route. How I can fix this problem?
I have route: /category-name/
And default: /controller/action/...
Conflict with routes.
Reading your code, I found several improvements that can be made:
1) First, you dont need two hyphens in those regexes. Instead of [0-9\-a-z\-], put [0-9a-z\-].
2) I see there are two repeated category_view_cpu names. Make sure to revise after you copy and paste. ;)
3) The logic for your routes are too broad and thus result in ambiguousness. For example, the routing definition and regex that you have for the category_view_cpu route (1st one) will behave very similar to the default_module route. So, in the 1st route, you are expecting an alphanumeric lowercase string (with optional hyphens), and in the default_module route you are also expecting a letters-only string with a minimum of 3 characters. So, if I type yoursite.com/dummy, the dummy
part will match the 1st route and also the default_module route. Phalcon doesnt have a way to know if dummy is either a controller or a category alias.
I do suggest that you don't make your routes so broad, by using route groups or by specifying controllers for certain routes that will only be handled for any given controller. For example:
$router->add('/categories/{alias:[0-9a-z\-]+}(/?)', array(
'module' => 'frontend',
'controller' => 'categories',
'action' => 'view',
'category' => 1,
'lang' => 'md',
))->setName('category_view_cpu');
Then, below this route ^, you can define the generic/default route that will catch all other requests. Example:
$router->add('/{controller:[a-z]{3,50}+}(/?)', array(
'module' => 'frontend',
'controller' => 1,
'action' => 'index',
'lang' => 'md',
))->setName('default_module');
What will happen with this example is that, if Phalcon gets a URL like /categories, it will match it with the first route that I made. But if it gets a route like: /dummy, then it will not match the first but will match my second route.
Route Groups are also great for helping distinguish and separate your routing logic. I suggest you read it entirely, here: https://docs.phalconphp.com/en/3.2/routing#defining-groups-of-routes

Phalcon two single routes

I have a problem. I have two routes:
$router->add('/news/{alias:[a-z\-]+}(/?)', array(
'module' => 'frontend',
'controller' => 'news',
'action' => 'view',
'news_id' => 1,
'lang' => 'md',
))->setName('news_view_short_e'); //=> /news/282334-alias-news
AND route => /news/index/:
$router->add('/{lang:[' . $langsDefined . ']{2}+}/{controller:[a-z]{3,50}+}(/?)', array(
'module' => 'frontend',
'controller' => 2,
'action' => 'index',
'lang' => 1,
))->setName('default_module_lang');
When I use these routes. site.com/news/index not working. But if I remove route with alias. Route site.com/news/index working good. How I can resolve conflict?
Probably because it matches your "index" as alias parameter too, so first rule wins. There's no magic solution other than just fixing your regex or reordering your routes.
Reversing your routes order will bring a new problem though, reversely because it will also match the controller instead of your alias.
I prefer to stick with the default routing, and mount a router group here's my router right now:
//From my config
'router' => array(
'defaults' => array(
'namespace' => 'My\\Default\\Namespace\\Controllers',
'module' => 'frontend',
'controller' => 'index',
'action' => 'index'
),
'notFound' => array(
'controller' => 'errors',
'action' => 'notFound'
)
),
// From my service
$router = new Router();
$router->removeExtraSlashes(true);
$router->setDefaults($this->config->router->defaults->toArray()?: $this->defaults);
$router->notFound($this->config->router->notFound->toArray()?: $this->notFound);
$router->mount(new ModuleRoute($this->getDefaults(), true));
class ModuleRoute extends RouterGroup
{
public $default = false;
public function __construct($paths = null, $default = false)
{
$this->default = $default;
parent::__construct($paths);
}
public function initialize()
{
$path = $this->getPaths();
$routeKey = '/' . $path['module'];
$this->setPrefix('/{locale:([a-z]{2,3}([\_\-][[:alnum:]]{1,8})?)}' . ($this->default ? null : $routeKey));
$this->add( '/:params', array(
'namespace' => $path['namespace'],
'module' => $path['module'],
'controller' => $path['controller'],
'action' => $path['action'],
'params' => 3
))->setName($routeKey);
$this->add( '/:controller/:params', array(
'namespace' => $path['namespace'],
'module' => $path['module'],
'controller' => 3,
'action' => $path['action'],
'params' => 4
))->setName($routeKey);
$this->add( '/:controller/([a-zA-Z0-9\_\-]+)/:params', array(
'namespace' => $path['namespace'],
'module' => $path['module'],
'controller' => 3,
'action' => 4,
'params' => 5
))->setName($routeKey);
$this->add( '/:controller/:int', array(
'namespace' => $path['namespace'],
'module' => $path['module'],
'controller' => 3,
'id' => 4,
))->setName($routeKey);
}
}

Phalcon URL assembly - how to supply parameters

I have the following Phalcon route:
$router->add('/:controller/:action/:params', [
'module' => 'secured',
'controller' => 1,
'action' => 2,
'params' => 3,
'namespace' => 'My\Namespace\Controllers'
])->setName('main');
I am trying to assemble URL for that route, which should look like this:
/user/register/admin/john
Where, "user" is controller name, "register" is action and there are two params: [0] = 'admin', [1] = 'john'.
I am assembling it as follows:
$url = $this->di['url']->get([
'for' => 'main',
'controller' => 'user',
'action' => 'regiser',
'params' => [
'admin',
'john'
]
]);
However, parameters are not in the $url:
/user/register
How can I make :params go into final URL?
Thanks!
I cannot check this right now, but does:
array(
'for' => 'main',
'controller' => 'user',
'action' => 'regiser',
'admin'
'john'
);
works as you wish?
I found the only way how to do this. Do it myself:
$this->url->get(array(
'for' => 'main',
'controller' => 'user',
'action' => 'register',
'params' => implode("/", array('admin', 'john'))
));

PaginatorHelper includes routing prefixes when default routes are disabled

I have disabled CakePHP default routes and have added some of my own. I have first create a routing prefix:
Configure::write('Routing.prefixes', array('settings));
And then I have added some routes:
Router::connect('/users', array('controller' => 'users', 'action' => 'index', 'settings' => true));
Router::connect('/users/add', array('controller' => 'users', 'action' => 'add', 'settings' => true));
Router::connect('/users/:id', array('controller' => 'users', 'action' => 'view', 'settings' => true), array('pass' => array('id'), 'id' => '[0-9]+'));
Router::connect('/users/:id/edit', array('controller' => 'users', 'action' => 'edit', 'settings' => true), array('pass' => array('id'), 'id' => '[0-9]+'));
Router::connect('/users/:id/delete', array('controller' => 'users', 'action' => 'delete', 'settings' => true), array('pass' => array('id'), 'id' => '[0-9]+'));
Building links with Html::link method works quite right:
$this->Html->link('Users', '/users')
generates
'/users'
and the action within UsersController is settings_index as expected.
However, PaginatorHelper::sort prepends /settings, like this:
'/settings/users/index/sort:username/direction:asc'
which actually only works if I enable the built-in routes. So I have two questions:
How can I make PaginatorHelper not to prepend '/settings'?
How can I make the PaginatorHelper named parameters work with my custom routes, so that I can have URL like '/users/sort:email/direction:desc'?
Thanks!!
Try using this command before your sort functions:
$this->Paginator->options(array('url' => array_merge(array('settings' => false), $this->passedArgs)));
This essentially sets some defaults for the paginator helper to use before it runs those functions. By setting settings to false, you will tell it not to set that route.
The answer to my problem actually involves two things since default routes are disabled.
First I have to provide named parameters for PaginationHelper:
Router::connectNamed(array(
'sort' => array('action' => 'index', 'controller' => array('users')),
'direction' => array('action' => 'index', 'controller' => array('users')),
));
And then I have to provide routes for controllers and actions using pagination:
Router::connect('/users/index/*', array(
'controller' => 'users',
'action' => 'index',
'settings' => true
));
It is important to say that this route should be at the end of the routes starting with '/users'. Otherwise the asterisk will take precedence. So my final set of routes looks like this:
Router::connectNamed(array(
'sort' => array('action' => 'index', 'controller' => array('users')),
'direction' => array('action' => 'index', 'controller' => array('users')),
));
Router::connect('/users', array('controller' => 'users', 'action' => 'index', 'settings' => true));
Router::connect('/users/add', array('controller' => 'users', 'action' => 'add', 'settings' => true));
Router::connect('/users/:id', array('controller' => 'users', 'action' => 'view', 'settings' => true), array('pass' => array('id'), 'id' => '[0-9]+'));
Router::connect('/users/:id/edit', array('controller' => 'users', 'action' => 'edit', 'settings' => true), array('pass' => array('id'), 'id' => '[0-9]+'));
Router::connect('/users/:id/delete', array('controller' => 'users', 'action' => 'delete', 'settings' => true), array('pass' => array('id'), 'id' => '[0-9]+'));
Router::connect('/users/index/*', array(
'controller' => 'users',
'action' => 'index',
'settings' => true
));

ZF: routing. How to make correct route?

I have several templates:
/admin/
/somecode1/somecode2/
/staticpage.htm
Trying to enter on /admin/. Doing follow:
$router->addRoutes(array(
'adminsys' => new Zend_Controller_Router_Route('/:module/:controller/:action/*', array('module' => 'admin', 'controller' => 'index', 'action' => 'index')),
'page_catalog' => new Zend_Controller_Router_Route('/:code/:page', array('module' => 'default', 'controller' => 'Staticcatalog', 'action' => 'index', 'code' => '', 'page' => '')),
'static' => new Zend_Controller_Router_Route_Regex('([\wА-Яа-я\-\_]+)\.(htm|html)', array('module' => 'default', 'controller' => 'static', 'action' => 'index')
));
also I tried to change 'adminsys' on :
'adminsys' => new Zend_Controller_Router_Route('/admin/:controller/:action/*', array('module' => 'admin', 'controller' => 'index', 'action' => 'index')),
or
'adminsys' => new Zend_Controller_Router_Route('/admin/*', array('module' => 'admin', 'controller' => 'index', 'action' => 'index')),
But all time it routes on 'page_catalog'.
If I comment it, I can enter /admin/. But not with 'page_catalog'.
What I'm doing wrong here?
When you define routes, you define the general one first, and then you go more and more specific after. The router takes your routes 'last one first' and stops on the first that matches.
This means that if '/admin' could also work for the 'page_catalog' route, it would use this one, before even trying to match 'adminsys' route. And that's the thing, '/admin' could be a 'page_catalog' url where :code param would be 'admin'.
The second variant of the adminsys route is a good one, you just have to make it the last one of your routes in order to avoid any more general route to match first :
$router->addRoutes(array(
'page_catalog' => new Zend_Controller_Router_Route('/:code/:page', array('module' => 'default', 'controller' => 'Staticcatalog', 'action' => 'index', 'code' => '', 'page' => '')),
'static' => new Zend_Controller_Router_Route_Regex('([\wА-Яа-я\-\_]+)\.(htm|html)', array('module' => 'default', 'controller' => 'static', 'action' => 'index')),
'adminsys' => new Zend_Controller_Router_Route('/admin/:controller/:action/*', array('module' => 'admin', 'controller' => 'index', 'action' => 'index'))
));

Categories