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.
Related
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']);
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
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);
}
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?
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.