Cakephp 3 routing with language parameter - php

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

Related

Php routing always contains Pages

Everytime i try and reference a file or anything, /Pages/ always is at the start of the URL. so i get these errors, and need to change all button links to ../
My routes.php file is as such
Router::scope('/', function (RouteBuilder $routes) {
$routes->connect('/', ['controller' => 'Pages', 'action' => 'display', 'home']);
$routes->connect('Pages/*', ['controller' => 'Pages', 'action' => 'display']);
I'm using cakephp inside codeanywhere (dont ask).
Try:
$routes->connect('/Pages/*', ['controller' => 'Pages', 'action' => 'display']);

defined route is missing - Missing Route in Cakephp 3.4

I am trying to use the prefix "student". When I create a link in template or layout file I am getting this error as shown in the image:
code in routes.php
<?php
use Cake\Core\Plugin;
use Cake\Routing\RouteBuilder;
use Cake\Routing\Router;
use Cake\Routing\Route\DashedRoute;
Router::defaultRouteClass(DashedRoute::class);
Router::scope('/', function (RouteBuilder $routes) {
$routes->connect('/', ['controller' => 'Pages', 'action' => 'display', 'home']);
$routes->connect('/pages/*', ['controller' => 'Pages', 'action' => 'display']);
$routes->fallbacks(DashedRoute::class);
});
Router::prefix('admin', function ($routes) {
$routes->connect('/users/', [ 'controller' => 'MyUsers', 'action' => 'index', 'plugin'=>false]);
$routes->connect('/login', [ 'controller' => 'MyUsers', 'action' => 'login', 'plugin'=>false, 'prefix'=>'admin']);
$routes->connect('/', [ 'controller' => 'MyUsers', 'action' => 'dashboard', 'plugin'=>false]);
$routes->fallbacks(DashedRoute::class);
});
Router::prefix('trainer', function ($routes) {
$routes->connect('/users/', [ 'controller' => 'MyUsers', 'action' => 'index', 'plugin'=>false]);
$routes->connect('/login', [ 'controller' => 'MyUsers', 'action' => 'login', 'plugin'=>false]);
$routes->connect('/', [ 'controller' => 'MyUsers', 'action' => 'dashboard', 'plugin'=>false]);
$routes->fallbacks(DashedRoute::class);
});
Router::prefix('student', function ($routes) {
$routes->connect('/courses/', array ( 'controller' => 'Courses', 'action' => 'index', 'plugin' => false, 'prefix' => 'student', '_ext' => NULL, ));
$routes->connect('/', array ( 'controller' => 'MyUsers', 'action' => 'dashboard', 'plugin' => false));
});
/**
* Load all plugin routes. See the Plugin documentation on
* how to customize the loading of plugin routes.
*/
Plugin::routes();
layout file student.ctp has only one line of code:
<li><?php echo $this->Html->link('Courses', [ 'controller' => 'Courses', 'action' => 'index', 'plugin' => false, 'prefix' => 'student', '_ext' => NULL, ]);?></li>
AppController.php:
<?php
namespace App\Controller;
use Cake\Controller\Controller;
use Cake\Event\Event;
use Cake\Core\Configure;
use Cake\Network\Exception\NotFoundException;
class AppController extends Controller
{
public $helpers = array(
'CakeDC/Users.AuthLink',
'CakeDC/Users.User',
);
public function initialize()
{
parent::initialize();
$this->loadComponent('RequestHandler');
$this->loadComponent('Flash');
$this->loadComponent('CakeDC/Users.UsersAuth');
$this->loadComponent('Utils.GlobalAuth');
$this->Auth->config('loginRedirect', array('controller'=>'Courses', 'action'=>'index', 'plugin'=>FALSE));
$this->Auth->config('logoutRedirect', array('controller'=>'MyUsers', 'action'=>'login', 'plugin'=>FALSE));
$this->Auth->config('unauthorizedRedirect', array('controller'=>'Courses', 'action'=>'index', 'prefix'=>$this->Auth->user('role')));
$this->Auth->config('loginAction', array('controller'=>'MyUsers', 'action'=>'login'));
$this->Auth->allow(['login', 'logout']);
}
public function beforeRender(Event $event)
{
if (!array_key_exists('_serialize', $this->viewVars) &&
in_array($this->response->type(), ['application/json', 'application/xml'])
) {
$this->set('_serialize', true);
}
$this->_renderLayout();
}
private function _renderLayout()
{
$prefix = isset($this->request->params['prefix'])?$this->request->params['prefix']:FALSE;
if(!$prefix)
{
return;
}
$this->viewBuilder()->setLayout($prefix);
}
}
I have checked this solution : CakePHP 3: Missing route error for route that exists
You cannot feed the special plugin key with a boolean, it must either be null, or a string with the name of the plugin.
Also there is no need to define the plugin or prefix keys when connecting routes, the Router::prefix() method will take care of adding the prefix. Similarily Router::plugin() will add the plugin name, and when not using Router::plugin(), a default of null is being assumed for the plugin key.
Furthermore defining _ext with null only makes sense if you want to disallow generating URLs with extensions. And specifying it when generating URLs is only neccessary when it has been defined as a non-null value, which is also true for the plugin key (unless you need to break out of the current plugin context).
Long story short, connecting the route only requires the controller and action keys:
$routes->connect('/courses/', [
'controller' => 'Courses',
'action' => 'index'
]);
And generating the URL only needs the additonal prefix key, plugin is optional if not used in plugin context:
$this->Html->link('Courses', [
'controller' => 'Courses',
'action' => 'index',
'plugin' => null,
'prefix' => 'student'
]);
See also
Cookbook > Routing > Prefix Routing
Cookbook > Routing > Plugin Routing
Cookbook > Routing > Routing File Extensions

Set Default Prefix in CakePHP 3 based on sub domain

I want to build multiple sub domain which point to same source code of CakePHP v3
Scenario is
If domain is "admin.localhost.com" then prefix value should be admin.
If domain is "xyz.localhost.com",'abc.localhost.com' or any on sub domain then prefix value should be vendor
If domain is "localhost.com" or "www.localhost.com" then prefix value should be false as cakephp 3 have by default.
I have tryied to findout from CakePHP 3 document. but I didint get how to set default prefix.
Thanks in Advance
I got Answer of my question myself
We have to set prefix in config/routs.php by exploding HTTP_HOST
$exp_domain= explode(".",env("HTTP_HOST"));
$default_prefix=false; // default prefix is false
if(count($exp_domain)>2 && $exp_domain[0]!="www")
{
if($exp_domain[0]=="admin") $default_prefix="admin";
else $default_prefix="vendor";
}
if($default_prefix=="admin")
{
// default routes for vendor users with base scope and pass prefix as admin ($default_prefix)
Router::scope('/', function ($routes) use($default_prefix) {
$routes->connect('/', ['controller' => 'admins', 'action' => 'dashboard','prefix'=>$default_prefix]);
$routes->connect('/:action', ['controller' => 'admins','prefix'=>$default_prefix]);
$routes->connect('/:controller/:action', ['controller' => 'controller', 'action' => 'action','prefix'=>$default_prefix]);
$routes->connect('/:controller/:action/*', ['controller' => 'controller', 'action' => 'action','prefix'=>$default_prefix]);
});
}
else if($default_prefix=="vendor")
{
// default routes for vendor users with base scope and pass prefix as vendor ($default_prefix)
Router::scope('/', function ($routes) use($default_prefix) {
$routes->connect('/', ['controller' => 'vendors', 'action' => 'dashboard','prefix'=>$default_prefix]);
$routes->connect('/:action', ['controller' => 'vendors','prefix'=>$default_prefix]);
$routes->connect('/:controller/:action', ['controller' => 'controller', 'action' => 'action','prefix'=>$default_prefix]);
$routes->connect('/:controller/:action/*', ['controller' => 'controller', 'action' => 'action','prefix'=>$default_prefix]);
});
}
else
{
// default routes for normal users with base scope
Router::scope('/', function ($routes) use($default_prefix) {
$routes->connect('/', ['controller' => 'users', 'action' => 'dashboard');
$routes->connect('/:action', ['controller' => 'users');
$routes->connect('/:controller/:action', ['controller' => 'controller', 'action' => 'action');
$routes->connect('/:controller/:action/*', ['controller' => 'controller', 'action' => 'action');
});
}
So main trick is need to pass prefix on root scope.

Phalcon routing, how to set default parameters?

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?

Different view route in CakePHP

I can somehow change the generated and accepted routes for simple urls, in the routes.php:
Router::connect('/login', array('controller' => 'users', 'action' => 'login'));
Router::connect('/logout', array('controller' => 'users', 'action' => 'logout'));
Router::connect('/register', array('controller' => 'users', 'action' => 'add'));
This works like a charm. However, this doesn't:
Router::connect('/eintrag/:id', array('controller' => 'entries', 'action' => 'view'));
Router::connect('/bearbeiten/:id', array('controller' => 'entries', 'action' => 'edit'));
When I try to get a route for this, via echo $this->Html->url(array('controller' => 'entries', 'action' => 'view', $entry['id'])), I get /entries/view/1. And the url /eintrag/1 is not accepted by the router.
How can I prettify my view and edit routes like I can do with parameterless routes?
You need to use a third param in your route, as you are passing it :id specifically.
// SomeController.php
public function view($id = null) {
// some code here...
}
// routes.php
Router::connect(
'/eintrag/:id', // e.g. /eintrag/1
array('controller' => 'entries', 'action' => 'view'),
array(
// this will map ":id" to $id in your action
'pass' => array('id'),
'id' => '[0-9]+'
)
);
should do it.
More info # the cookbook
$this->Html->url() is just a Helper Function, that simply generates a URL according to paramaters passed, however when you actually open this Url then it will route request made for /eintrag/1 to /entries/view/1

Categories