-Myproject
-application
-controllers
-subfolder1
-subfolder2
-subfolder3
-subfolder(..n)
Controller.php
And need to set routes.php
$route['default_controller'] = 'subfolder1/subfolder2/subfolder3/subfolder(..n)/controller';
According to the examples in the docs it does not appear that you can put a Controller more than one level deep inside a subdirectory.
example.com/index.php/subdirectory/controller/function
I also don't think your route looks correct. You would not have home/ at the start of the route unless "home" is a controller or subdirectory name. See examples here.
$route['default_controller'] = 'subdirectory/controller';
I have researched and found in codeigniter 3 system/core/Router.php library file's method _set_default_controller() can not support default controller in subfolder. So i have overrided/ customized this method _set_default_controller() and now it supports n level subfolders and working fine for me.
I have created application/core/MY_Router.php with the below code to override this method _set_default_controller()
<?php
/**
* Override Set default controller
*
* #author : amit
*
* #return void
*/
protected function _set_default_controller()
{
if (empty($this->default_controller))
{
show_error('Unable to determine what should be displayed. A default route has not been specified in the routing file.');
}
// Is the method being specified?
$x = explode('/', $this->default_controller);
$dir = APPPATH.'controllers'; // set the controllers directrory path
$dir_arr = array();
foreach($x as $key => $val){
if(!is_dir($dir.'/'.$val)){
// find out class i.e. controller
if(file_exists($dir.'/'.ucfirst($val).'.php')){
$class = $val;
if(array_key_exists(($key+1), $x)){
$method = $x[$key+1]; // find out method i.e. action
}else{
$method = 'index'; // default method i.e. action
}
}else{
// show error message if the specified controller not found
show_error('Not found specified default controller : '. $this->default_controller);
}
break;
}
$dir_arr[] = $val;
$dir = $dir.'/'.$val;
}
//set directory
$this->set_directory(implode('/', $dir_arr));
$this->set_class($class);
$this->set_method($method);
// Assign routed segments, index starting from 1
$this->uri->rsegments = array(
1 => $class,
2 => $method
);
log_message('debug', 'No URI present. Default controller set.');
}
?>
Now we can set default controller in application/config/routes.php like below
// without action method name
$route['default_controller'] = 'subfoler1/subfoler2/subfolder3/subfolder(..n)/controller';
OR
// with action method name
$route['default_controller'] = 'subfoler1/subfoler2/subfolder3/subfolder(..n)/controller/action';
If we will pass the action method name it will detect that method as action and if we will not pass action name then it will assume index as a action.
Related
In codeigniter 3 application i have directory structure like this:
-Myproject
-application
-controllers
-home
Welcome.php //This is my controller inside home directory
How to set Welcome controller as default controller?
I use below code
$route['default_controller'] = 'home/Welcome';
This routing works for previous versions of codeigniter.
By default, you are not allowed to do that. To get around this, you need to hack your system Router.php:
codeigniter/system/core/Router.php
Edit a few lines of code so that it becomes like this:
line 1. if (!sscanf($this->default_controller, '%[^/]/%[^/]/%s', $directory, $class, $method) !== 2)
line 2. if ( ! file_exists(APPPATH.'controllers'. DIRECTORY_SEPARATOR . $directory. DIRECTORY_SEPARATOR .ucfirst($class).'.php'))
line 3. $this->set_directory($directory);
Once you've done, you can call the default controller under directory.
$route['default_controller'] = 'home/Welcome';
You need not to change anything from files inside CODEIGNITER system folder. Codeigniter allows developer to extend their feature. You can create a file named as MY_Router.php.
<?php
class MY_Router extends CI_Router {
protected function _set_default_controller() {
if (empty($this->default_controller)) {
show_error('Unable to determine what should be displayed. A default route has not been specified in the routing file.');
}
if (sscanf($this->default_controller, '%[^/]/%s', $class, $method) !== 2) {
$method = 'index';
}
if( is_dir(APPPATH.'controllers/'.$class) ) {
$this->set_directory($class);
$class = $method;
if (sscanf($method, '%[^/]/%s', $class, $method) !== 2) {
$method = 'index';
}
}
if ( ! file_exists(APPPATH.'controllers/'.$this->directory.ucfirst($class).'.php')) {
return;
}
$this->set_class($class);
$this->set_method($method);
$this->uri->rsegments = array(
1 => $class,
2 => $method
);
log_message('debug', 'No URI present. Default controller set.');
}
}
Note: Do not change the file name.
Try This in routes.php
$route['default_controller'] = 'welcome';
$route['404_override'] = '';
$route['translate_uri_dashes'] = FALSE;
Im using PHP MVC for my site and I have an issue with routing.
When I go to the index (front page), I use http://www.example.com or http://www.example.com/index.
When I go to the contact page, I use http://www.example.com/contact.
When I go to the services or about pages, I use http://www.example.com/content/page/services or http://www.example.com/content/page/about.
My index and contact pages have their own controllers because they are static pages. But the services and about pages are pulled from my db, thus dynamic. So I created a controller, named it content and just pass the parameters needed to get whatever page I want.
I want to make my URLs more consistent. If I go to the services or about pages, I want to use http://www.example.com/services or http://www.example.com/about.
How can I change my routing to meet this requirement? I ultimately would like to be able to create pages in my db, and then pull the page with a URL that looks like it has its own controller. Instead of having to call the content controller to get it to work.
Below are my controllers and what methods they contain, as well as my routing code.
Controllers:
IndexController
function: index
ContentController
function: page
function: sitemap
ContactController
function: index
function: process
Routing
class Application
{
// #var mixed Instance of the controller
private $controller;
// #var array URL parameters, will be passed to used controller-method
private $parameters = array();
// #var string Just the name of the controller, useful for checks inside the view ("where am I ?")
private $controller_name;
// #var string Just the name of the controller's method, useful for checks inside the view ("where am I ?")
private $action_name;
// Start the application, analyze URL elements, call according controller/method or relocate to fallback location
public function __construct()
{
// Create array with URL parts in $url
$this->splitUrl();
// Check for controller: no controller given ? then make controller = default controller (from config)
if (!$this->controller_name) {
$this->controller_name = Config::get('DEFAULT_CONTROLLER');
}
// Check for action: no action given ? then make action = default action (from config)
if (!$this->action_name OR (strlen($this->action_name) == 0)) {
$this->action_name = Config::get('DEFAULT_ACTION');
}
// Rename controller name to real controller class/file name ("index" to "IndexController")
$this->controller_name = ucwords($this->controller_name) . 'Controller';
// Check if controller exists
if (file_exists(Config::get('PATH_CONTROLLER') . $this->controller_name . '.php')) {
// Load file and create controller
// example: if controller would be "car", then this line would translate into: $this->car = new car();
require Config::get('PATH_CONTROLLER') . $this->controller_name . '.php';
$this->controller = new $this->controller_name();
// Check for method: does such a method exist in the controller?
if (method_exists($this->controller, $this->action_name)) {
if (!empty($this->parameters)) {
// Call the method and pass arguments to it
call_user_func_array(array($this->controller, $this->action_name), $this->parameters);
} else {
// If no parameters are given, just call the method without parameters, like $this->index->index();
$this->controller->{$this->action_name}();
}
} else {
header('location: ' . Config::get('URL') . 'error');
}
} else {
header('location: ' . Config::get('URL') . 'error');
}
}
// Split URL
private function splitUrl()
{
if (Request::get('url')) {
// Split URL
$url = trim(Request::get('url'), '/');
$url = filter_var($url, FILTER_SANITIZE_URL);
$url = explode('/', $url);
// Put URL parts into according properties
$this->controller_name = isset($url[0]) ? $url[0] : null;
$this->action_name = isset($url[1]) ? $url[1] : null;
// Remove controller name and action name from the split URL
unset($url[0], $url[1]);
// rebase array keys and store the URL parameters
$this->parameters = array_values($url);
}
}
}
In order to do this you should map your urls to controllers, check following example:
// route mapping 'route' => 'controller:method'
$routes = array(
'/service' => 'Content:service'
);
also controller can be any php callable function.
Answer Version 2:
Brother in the simplest mode, let's say you have an entity like below:
uri: varchar(255), title: varchar(255), meta_tags: varchar(500), body: text
and have access to StaticPageController from www.example.com/page/ url and what ever it comes after this url will pass to controller as uri parameter
public function StaticPageController($uri){
// this can return a page entity
// that contains what ever a page needs.
$page = $pageRepository->findByUri($uri)
// pass it to view layer
$this->renderView('static_page.phtml', array('page' => $page));
}
I hope this helps.
Rewrite URL if user tried to access any non existing controller.
Ex:- If user tried to access http://example.com/project/anyvalue . In my program there is no controller with name 'anyvalue'. In this situation I want to redirect to
http://example.com/project/profile/anyvalue
How is this possible using routing in codeigniter?
Use default route to redirect requests to some particular page if controller is missing
You can find routes location in
/application/admin/config/routes.php
$route['default_controller'] = "welcome";
Also use following in case of page not found
$route['404_override'] = 'default_page';
Add routes to all existing controllers under "/project/..."
Add a route that will match any paths under "/project"
Example:
/* Currently available controllers under "/project/" */
$route['project/profile'] = "project/profile";
$route['project/add'] = "project/add";
$route['project/edit'] = "project/edit";
/* Catch all others under "/project/" */
$route['project/(:any)'] = "project/profile/$1";
/* if controller class name is Profile and function name is index */
$route['project/(:any)'] = 'project/profile/index/$1';
What you want is Vanity URLs, you can find a guide for performing this in code igniter here:
http://philpalmieri.com/2010/04/personalized-user-vanity-urls-in-codeigniter/
Essentially you're adding this to your routes file:
$handle = opendir(APPPATH."/modules");
while (false !== ($file = readdir($handle))) {
if(is_dir(APPPATH."/modules/".$file)){
$route[$file] = $file;
$route[$file."/(.*)"] = $file."/$1";
}
}
/*Your custom routes here*/
/*Wrap up, anything that isnt accounted for pushes to the alias check*/
$route['([a-z\-_\/]+)'] = "aliases/check/$1";
I am trying to implement URL based translation in Zend Framework so that my site is SEO friendly. This means that I want URLs like the below in addition to the default routes.
zend.local/en/module
zend.local/en/controller
zend.local/en/module/controller
zend.local/en/controller/action
The above are the ones I have problems with right now; the rest should be OK. I have added a controller plugin that fetches a lang parameter so that I can set the locale and translation object in the preDispatch method. Here are some of my routes (stored in a .ini file):
; Language + module
; Language + controller
resources.router.routes.lang1.type = "Zend_Controller_Router_Route_Regex"
resources.router.routes.lang1.route = "(^[a-zA-Z]{2})/(\w+$)"
resources.router.routes.lang1.defaults.controller = index
resources.router.routes.lang1.defaults.action = index
resources.router.routes.lang1.map.1 = "lang"
resources.router.routes.lang1.map.2 = "module"
; Language + module + controller
; Language + controller + action
resources.router.routes.lang2.type = "Zend_Controller_Router_Route_Regex"
resources.router.routes.lang2.route = "(^[a-zA-Z]{2})/(\w+)/(\w+$)"
resources.router.routes.lang2.defaults.module = default
resources.router.routes.lang2.defaults.action = index
resources.router.routes.lang2.map.1 = "lang"
resources.router.routes.lang2.map.2 = "controller"
resources.router.routes.lang2.map.3 = "action"
As the comments indicate, several URL structures will match the same route, which makes my application interpret the format incorrectly. For instance, the following two URLs will be matched by the lang1 route:
zend.local/en/mymodule
zend.local/en/mycontroller
In the first URL, "mymodule" is used as module name, which is correct. However, in the second URL, "mycontroller" is used as module name, which is not what I want. Here I want it to use the "default" module and "mycontroller" as controller. The same applies for the previous lang2 route. So I don't know how to distinguish between if the URL is of the structure /en/module or /en/controller.
To fix this, I experimented with the code below in my controller plugin.
// Get module names as array
$dirs = Zend_Controller_Front::getInstance()->getControllerDirectory();
$modules = array_keys($dirs);
// Module variable contains a module that does not exist
if (!in_array($request->getModuleName(), $modules)) {
// Try to use it as controller name instead
$request->setControllerName($request->getModuleName());
$request->setModuleName('default');
}
This works fine in the scenarios I tested, but then I would have to do something similar to make the lang2 route work (which possibly involves scanning directories to get the list of controllers). This just seems like a poor solution, so if it is possible, I would love to accomplish all of this with routes only (or simple code that is not so "hacky"). I could also make routes for every time I want /en/controller, for instance, but that is a compromise that I would rather not go with. So, if anyone knows how to solve this, or know of another approach to accomplish the same thing, I am all ears!
I've reproduced your problem here and come out with the following (not using config files though):
Router
/**
* Initializes the router
* #return Zend_Controller_Router_Interface
*/
protected function _initRouter() {
$locale = Zend_Registry::get('Zend_Locale');
$routeLang = new Zend_Controller_Router_Route(
':lang',
array(
'lang' => $locale->getLanguage()
),
array('lang' => '[a-z]{2}_?([a-z]{2})?')
);
$frontController = Zend_Controller_Front::getInstance();
$router = $frontController->getRouter();
// Instantiate default module route
$routeDefault = new Zend_Controller_Router_Route_Module(
array(),
$frontController->getDispatcher(),
$frontController->getRequest()
);
// Chain it with language route
$routeLangDefault = $routeLang->chain($routeDefault);
// Add both language route chained with default route and
// plain language route
$router->addRoute('default', $routeLangDefault);
// Register plugin to handle language changes
$frontController->registerPlugin(new Plugin_Language());
return $router;
}
Plug-in
/**
* Language controller plugin
*/
class Plugin_Language extends Zend_Controller_Plugin_Abstract
{
/**
* #var array The available languages
*/
private $languages = array('en', 'pt');
/**
* Check the URI before starting the route process
* #param Zend_Controller_Request_Abstract $request
*/
public function routeStartup(Zend_Controller_Request_Abstract $request)
{
$translate = Zend_Registry::get('Zend_Translate');
$lang = $translate->getLocale();
// Extracts the URI (part of the URL after the project public folder)
$uri = str_replace($request->getBaseUrl() . '/', '', $request->getRequestUri());
$langParam = substr($uri, 0, 3);
// Fix: Checks if the language was specified (if not, set it on the URI)
if((isset($langParam[2]) && $langParam[2] !== '/') || !in_array(substr($langParam, 0, 2), $this->languages)) { {
$request->setRequestUri($request->getBaseUrl() . '/' . $lang . "/" . $uri);
$request->setParam('lang', $lang);
}
}
}
Basically, there's the route chain for applying the language settings within the module default route. As a fix, we ensure that the URI will contain the language if the user left it out.
You'll need to adapt it, as I'm using the Zend_Registry::get('Zend_Locale') and Zend_Registry::get('Zend_Translate'). Change it to the actual keys on your app.
As for the lang route: [a-z]{2}_?([a-z]{2})? it will allow languages like mine: pt_BR
Let me know if it worked for you.
I created a module and there exists a default controller inside that. Now I can access the index action (default action) in the default controller like /mymodule/. For all other action i need to specify the controller id in the url like /mymodule/default/register/ . I would like to know is it possible to eliminate the controller id from url for the default controller in a module.
I need to set url rule like this:
before beautify : www.example.com/index.php?r=mymodule/default/action/
after beautify : www.example.com/mymodule/action/
Note: I want this to happen only for the default controller.
Thanks
This is a little tricky because the action part might be considered as a controller or you might be pointing to an existing controller. But you can get away with this by using a Custom URL Rule Class. Here's an example (I tested it and it seems to work well):
class CustomURLRule extends CBaseUrlRule
{
const MODULE = 'mymodule';
const DEFAULT_CONTROLLER = 'default';
public function parseUrl($manager, $request, $pathInfo, $rawPathInfo)
{
if (preg_match('%^(\w+)(/(\w+))?$%', $pathInfo, $matches)) {
// Make sure the url has 2 or more segments (e.g. mymodule/action)
// and the path is under our target module.
if (count($matches) != 4 || !isset($matches[1]) || !isset($matches[3]) || $matches[1] != self::MODULE)
return false;
// check first if the route already exists
if (($controller = Yii::app()->createController($pathInfo))) {
// Route exists, don't handle it since it is probably pointing to another controller
// besides the default.
return false;
} else {
// Route does not exist, return our new path using the default controller.
$path = $matches[1] . '/' . self::DEFAULT_CONTROLLER . '/' . $matches[3];
return $path;
}
}
return false;
}
public function createUrl($manager, $route, $params, $ampersand)
{
// #todo: implement
return false;
}
}