Phalcon routing, how to set default parameters? - php

I'm trying to create dynamic routes in Phalcon 1.3.4, but if a parameter is missing (like :action or :params) the route doesn't match.
Here is the (working) code :
$router = new Phalcon\Mvc\Router(TRUE);
$group = new Phalcon\Mvc\Router\Group([
'namespace' => 'App\\Backoffice',
'controller' => 'Index',
]);
// All the routes start with /group
$group->setPrefix('/backoffice');
// Adding route to group
$group->add('', ['action' => 'index']); // matches /backoffice
$group->add('/:controller', ['controller' => 1]); // matches /backoffice/moderate
$group->add('/:controller/:action', ['controller' => 1, 'action' => 2]);
$group->add('/:controller/:action/:params', ['controller' => 1, 'action' => 2, 'params' => 3]);
$router->mount($group);
Is it possible to remove the redundant first three routes and only keep the fourth ? By assigning default values to match /backoffice or /backoffice/moderate.

This is how I initialize my router:
$router = new \Phalcon\Mvc\Router(false);
$router->removeExtraSlashes(true);
$router->notFound([
"module" => "page",
"controller" => 'index',
"action" => 'index',
]);
There is also a setDefaults() method in the docs: http://docs.phalconphp.com/en/latest/api/Phalcon_Mvc_Router.html
Is this helpful?

Related

Phalcon routing correctly pattern

Help with routing settings, there is the following request template with frontend: /books/([0-9]+)/book-authors/([0-9]+)/images
There is a controller located in namespace: Shop\Controllers\Books\BookAuthors\ImagesController
The controller has an indexAction method.
In routing.php I specify the following:
$router = new Router(false);
$router->removeExtraSlashes(true);
$router->setDefaultNamespace('Shop\Controllers');
$router->setDefaultController('index');
$router->setDefaultAction('index');
$router->addGet('/books/([0-9]+)/book-authors/([0-9]+)/images', [
'namespace' => 'Shop\Controllers\Books\BookAuthors',
'bookId' => 1,
'authorId' => 2,
'controller' => 'images',
'action' => 'index',
]);
return $router;
As a result, we get that the redirect always goes to the default controller. Please tell me how to fix...
I tried to debug and check why the template does not fit, but when I checked regex101 on the site, everything matches there and should work, but for some reason it does not work in phalcon.
Application return every time "not found"
The route works fine, although you can try this for simplicity and clarity:
$router->addGet('/books/{bookId:[0-9]+}/book-authors/{authorId:[0-9]+}/images',
[
'controller' => 'images',
'action' => 'index'
]
);
And in your ImagesController define indexAction as:
public function indexAction(int $bookId, int $authorId)
{
echo "BookId: $bookId and AuthorId: $authorId";
}
For /books/10/book-authors/22/images the result should be:
BookId: 10 and AuthorId: 22
Try this:
$router->addGet('/books/:int/book-authors/:int/images', [
'namespace' => 'Shop\Controllers\Books\BookAuthors',
'controller' => 'images',
'action' => 'index',
'bookId' => 1,
'authorId' => 2,
]);
Note that I don't know if you can have multiple ":int" in the router definition and I have not tried this code.
If you can't have multiple ":int" in the line, you may need to restructure and move the bookId and authorId to the end and use :params. Note that I also dropped the "images" controller name since you don't need that in the line.
$router->addGet('/books/book-authors/:params', [
'namespace' => 'Shop\Controllers\Books\BookAuthors',
'controller' => 'images',
'action' => 'index',
'params' => 1,
]);
Your URL would be something along the lines of "/books/book-authors/98/212" for bookID 98 and authorId 212.

Kohana more than one dynamic routing for specific urls

I don't know if someone else is using kohana (koseven with new name) framework for develepment. I need help about routing. I am migrating an asp site to php with using koseven ( kohana) framework and I must keep all the url routing on current site. Because of this I must use more than one routing on my project.
Url structer must be like this:
domain.com/contenttype/contentid -> contenttype is dynamic and gets data over Content Controller
domain.com/profile/username ->profile is the controller and index is the action. I must get the user name from id parameter.
domain.com/categories/categorname (Works fine-> categories is the controller, index is the action and categorname is the id parameter.
There is an admin page on my site and using a directory route on it.
Here is my route on bootstrap.php file:
Route::set('panel', '<directory>(/<controller>(/<action>(/<id>)))', array('directory' => 'panel'))
->defaults(array(
'controller' => 'panel',
'action' => 'index',
));
Route::set('kategori','<kategori>(/<id>)', array('id'=>'.*'))
->defaults([
'controller'=>'kategori',
'action'=>'index',
]);
Route::set('default', '(<controller>(/<action>(/<id>)))', array('id'=>'.*'))
->defaults([
'controller' => 'anasayfa',
'action' => 'index',
]);
First Problem: If I copy kategori route for profile it uses kategori route instead of profile.
Second Problem: How can I get dynamic routing for the contenttype. Content controller is the default controller and it will list the contents under the dynamic contenttype if there isn't given any content title on the id parameter. If the id parameter is identified at this time it will Show the detail of content.
Thanks.
Route::set('panel', 'panel(/<controller>(/<action>(/<id>)))', ['controller' => '\w+', 'action' => '\w+', 'id' => '[-\w]+'])
->defaults(array(
'directory' => 'panel',
'controller' => 'dashboard',
'action' => 'index',
'id' => null,
));
Route::set('kategori','<kategori>(/<id>)', ['kategori' => '[-\w]+', 'id' => '[-\w]+'])
->defaults([
'controller' => 'kategori',
'action' => 'index',
'id' => null,
])
->filter(function ($route, $params, $request) {
$model = ORM::factory('Kategori', ['kategori' => $params['kategori'], 'id' => $params['id']]);
if ($model->loaded()) {
$params['model'] = $model;
return $params;
}
return false;
});
Route::set('default', '(<controller>(/<action>(/<id>)))', ['controller' => '\w+', 'action' => '\w+', 'id' => '[-\w]+'])
->defaults([
'controller' => 'anasayfa',
'action' => 'index',
'id' => null,
]);

Cakephp 3 routing with language parameter

I'm trying to convert cakephp 2.x to 3.x. I was using Router::connect() rules, but I try to convert them to scope version.
Regarding to myold routing rule, in config/routes.php I added this.
Router::defaultRouteClass('Route');
Router::scope('/', function ($routes) {
$routes->connect('/:language/:controller/:action/*', ['language' => 'ar|de|en|fr']);
$routes->connect('/:language/:controller', ['action' => 'index', 'language' => 'ar|de|en|fr']);
$routes->connect('/:language', ['controller' => 'Mydefault', 'action' => 'index', 'language' => 'ar|de|en|fr']);
$routes->redirect('/gohere/*', ['controller' => 'Mycontroller', 'action' => 'myaction'], ['persist' => array('username')]);
$routes->connect('/', ['controller' => 'Mydefault', 'action' => 'index']);
$routes->fallbacks('InflectedRoute');
});
But this fails in example.com/en/works. I get this error: Error: worksController could not be found. Because my controller file is WorksController.php.
Does controller name part hanged to sentence casein cakephp 3 ? http://book.cakephp.org/3.0/en/intro/conventions.html#controller-conventions
Also example.com/foo/bar gives this error: Error: barController could not be found.. But foo is controller and bar is action.
How can I fix this routing problem ?
Edit:
Changing Route::defaultRouteClass('Route') to Route::defaultRouteClass('InflectedRoute') solved problem 1. But problem 2 exists.
Options, such as route element patterns, must be passed via the third argument of Router::connect(), the $options argument.
This route:
$routes->connect(
'/:language/:controller',
['action' => 'index', 'language' => 'ar|de|en|fr'
]);
will catch your /foo/bar URL, it will match foo for the :language element, and bar for the :controller element. Basically the language key in the URL array will be treated as the default value, and it will always be overwritten by the :language element value.
The correct way of defining the route is:
$routes->connect(
'/:language/:controller',
['action' => 'index'],
['language' => 'ar|de|en|fr']
);
The other routes need to be adapted accordingly.
See also Cookbook > Routing > Connecting Routes
The best way is using Routing scopes
<?php
$builder = function ($routes) {
$routes->connect('/:action/*');
};
$scopes = function ($routes) use ($builder) {
$routes->scope('/questions', ['controller' => 'Questions'], $builder);
$routes->scope('/answers', ['controller' => 'Answers'], $builder);
};
$languages = ['en', 'es', 'pt'];
foreach ($languages as $lang) {
Router::scope("/$lang", ['lang' => $lang], $scopes);
}
Router::addUrlFilter(function ($params, $request) {
if ($request->param('lang')) {
$params['lang'] = $request->param('lang');
}
return $params;
});
Code taken from:
https://github.com/steinkel/cakefest2015/blob/c3403729d7b97015a409c36cf85be9b0cc5c76ef/cakefest/config/routes.php
Extending on default router from CakePHP 3 application skeleton
original routes.php removed comments
<?php
use Cake\Routing\RouteBuilder;
use Cake\Routing\Router;
use Cake\Routing\Route\DashedRoute;
Router::defaultRouteClass(DashedRoute::class);
Router::scope('/', function (RouteBuilder $routes) {
$routes->applyMiddleware('csrf');
$routes->connect('/', ['controller' => 'Pages', 'action' => 'display', 'home']);
$routes->connect('/pages/*', ['controller' => 'Pages', 'action' => 'display']);
$routes->fallbacks(DashedRoute::class);
});
modified with language from defined set
<?php
use Cake\Routing\RouteBuilder;
use Cake\Routing\Router;
use Cake\Routing\Route\DashedRoute;
Router::defaultRouteClass(DashedRoute::class);
$routerCallback = function (RouteBuilder $routes) {
$routes->applyMiddleware('csrf');
$routes->connect('/', ['controller' => 'Pages', 'action' => 'display', 'home']);
$routes->connect('/pages/*', ['controller' => 'Pages', 'action' => 'display']);
$routes->fallbacks(DashedRoute::class);
};
// support only for 3 languages, other language will throw 404/NotFoundException
// or will cause different routing problem based on your routes
Router::scope('/', $routerCallback);
foreach (["en", "fr", "de"] as $language) {
Router::scope('/' . $language, ['language' => $language], $routerCallback);
}
// to access the language param, or default to 'en', use
// $this->request->getParam('language', 'en')
// from AppController, PagesController, etc...
rooter.php
$routes->connect('/:lang/:controller/:action',[],[ 'lang' => '[a-z]{2}','pass' => ['lang']]);
$routes->connect('/:lang/', ['controller' => 'Pages', 'action' => 'index'],[ 'lang' => '[a-z]{2}','pass' => ['lang']]);
$routes->connect('/:lang/index', ['controller' => 'Pages', 'action' => 'index'],[ 'lang' => '[a-z]{2}','pass' => ['lang']]);
$routes->connect('/:lang/pages/*', ['controller' => 'Pages', 'action' => 'index'],[ 'lang' => '[a-z]{2}','pass' => ['lang']]);
$routes->connect('/:lang/contact', ['controller' => 'Pages', 'action' => 'contact'],[ 'lang' => '[a-z]{2}','pass' => ['lang']]);
$routes->connect('/:lang/about', ['controller' => 'Pages', 'action' => 'about'],[ 'lang' => '[a-z]{2}','pass' => ['lang']]);
Class Appcontroller
public function beforeFilter(Event $event)
{
$this->Auth->allow(['']);
if(isset($this->request->params['pass'][0]))
$lang = $this->request->params['pass'][0];
else $lang = 'en';
I18n::locale($lang);
}

Phalcon route doesn't work

My phalcon app has worked fine with standard MVC route convention.
However, I want to handle some variable via URL, then I have a route:
$router = new \Phalcon\Mvc\Router();
$router->add("/timesheet/some/{year:[0-9]+}/{month:[0-9]{2}}/{day:[0-9]{2}}", "Timesheet::some");
$router->add("/timesheet/getreport/{type:[a-z]}/{year:[0-9]+}/{month:[0-9]{2}}/{day:[0-9]{2}}", "Timesheet::getreport");
$router->addPost("/user/auth", "User::auth");
return $router;
The first route (timesheet/some) worked fine, I can access to "year", "month" variable using $year = $this->dispatcher->getParam("year");, however the second route (timesheet/getreport) doesn't work. In this case, $year = $this->dispatcher->getParam("year"); return null.
If I changed to
$router = new \Phalcon\Mvc\Router(false);
$router->add("/:controller/:action", array(
"controller" => 1,
"action" => 2,
));
$router->add("/timesheet/some/{year:[0-9]+}/{month:[0-9]{2}}/{day:[0-9]{2}}", "Timesheet::some");
$router->addPost("/timesheet/getreport/{type:[a-z]}/{year:[0-9]+}/{month:[0-9]{2}}/{day:[0-9]{2}}", "Timesheet::getreport");
$router->addPost("/user/auth", "User::auth");
return $router;
every request will be routed to index/index. My project URL is localhost/fpas, and I already try both route /fpas/timesheet/some and /timesheet/some but it always redirect to index/index. What's wrong with it? (security/auth is commented out, so it's not result from authentication).
From my understand, the default route, $router = new \Phalcon\Mvc\Router(); only allow you to follow MVC convention, while $router = new \Phalcon\Mvc\Router(false); do but you have to specific all routes for every controller/action. Can I keep the convention for most of the action, while have specific rewrite routes for some action. How can I do that?
Thank you very much.
It works for me:
$router = new Phalcon\Mvc\Router();
$router->add("/", array(
'controller' => 'index',
'action' => 'setLanguage',
));
$router->add("/{language:[a-z]{2}}", array(
'controller' => 'index',
'action' => 'index',
'language' => 1
));
this one get's default routing just with language in the beginning
$router->add("/{language:[a-z]{2}}/:controller/:action", array(
'controller' => 2,
'action' => 3,
'language' => 1
));
with default action "index" when it's not in url
$router->add("/{language:[a-z]{2}}/:controller", array(
'controller' => 2,
'action' => 'index',
'language' => 1
));
some other routes
$router->add("/{language:[a-z]{2}}/:controller/:action/:params", array(
'controller' => 2,
'action' => 3,
'language' => 1,
'params' => 4
));
$router->add("/{language:[a-z]{2}}/question/add/{type}", array(
'language' => 1,
'controller' => 'question',
'action' => 'add',
));

CakePHP route with regex

I have a controller setup to accept two vars: /clients/view/var1/var2
And I want to show it as /var1/var2
SO i tried
Router::connect('/*', array('admin'=>false, 'controller' => 'clients', 'action' => 'view'));
But this stops all other controllers working as /* routes everything
All other pages that are on the site are within the admin prefix so basically i need a route that is ignored if the current prefix is admin! I tried this (regex is from Regular expression to match a line that doesn't contain a word?):
Router::connect('/:one', array('admin'=>false, 'controller' => 'clients', 'action' => 'view'), array(
'one' => '^((?!admin).*)$'
));
But I think the regex is incorrect because if i naviate to /test it asks for the tests controller, not clients
My only other routes are:
Router::connect('/admin', array('admin'=>true, 'controller' => 'clients', 'action' => 'index'));
Router::connect('/', array('admin'=>false, 'controller' => 'users', 'action' => 'login'));
What am I doing wrong? Thanks.
I misunderstood your question the first time. I tested your code and didn't get the expected result either. The reason might be that the regex parser doesn't support negative lookahead assertion. But I still think you can solve this with reordering the routes:
The CakeBook describes which routes are automatically generated if you use prefix routing. In your case these routes have to be assigned manually before the '/*'-route to catch all admin actions. Here is the code that worked for me:
// the previously defined routes
Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
Router::connect('/admin', array('controller' => 'clients', 'action' => 'index', 'admin' => true));
// prefix routing default routes with admin prefix
Router::connect("/admin/:controller", array('action' => 'index', 'prefix' => 'admin', 'admin' => true));
Router::connect("/admin/:controller/:action/*", array('prefix' => 'admin', 'admin' => true));
// the 'handle all the rest' route, without regex
Router::connect(
'/*',
array('admin'=>false, 'controller' => 'clients', 'action' => 'view'),
array()
);
Now I get all my admin controller actions with the admin prefix and /test1/test2 gets redirected to the client controller.
I think the solution is described in the bakery article on routing - "Passing parameters to the action" (code not tested):
Router::connect(
'/clients/view/:var1/:var2/*',
array(
'controller' => 'clients',
'action' => 'view'
),
array(
'pass' => array(
'var1',
'var2'
)
)
);
The controller action would look like:
public function view($var1 = null, $var2 = null) {
// do controller stuff
}
Also you have too look at the order of your routes (read section "The order of the routes matters"). In your example the '/*' stops all other routes if it comes first, if you assign the rule after the others it handles only requests which didn't match any other route.

Categories