简体   繁体   中英

CodeIgniter default controller in a sub directory not working

My default_controller in the routes configuration is set as "home.php".

I have a sub directory for my controllers, lets call it "folder". So if I visit http://mysite.com/folder/ , the default controller "folder/home.php" should be called right?

However for some reason this doesn't work, I get a 404. Visiting http://mysite.com/folder/home or http://mysite.com/folder/home/index works as expected. In addition to this, the default controller works in the root directory ( http://mysite.com loads home.php).

Any ideas, has anyone else experienced this? I can't get my head around it - it would appear to be a CI issue but I can't find anybody else having the same problem.

The documentation, from the way I understand it at least, suggests that this should work fine: http://codeigniter.com/user_guide/general/controllers.html#subfolders

Setting the default controller to "folder/home.php" means that http://mysite.com/folder/ works fine as expected. Except for I want the default controller to just be "home.php" - whether in the root or in a sub directory, home.php within that directory should be loaded, as the documentation suggests.

Cheers

For each sub-folder in your controllers folder you must specify a default controller in routes.php . The built in $route['default_controller'] will not work for sub-folders.

eg: For setting the default controller for you folder sub-folder to home add the following to your /application/config/routes.php file:

$route['folder'] = "folder/home";

which means http://mysite.com/folder/ is the same as http://mysite.com/folder/home as URL.

You can extend system router as per requirements,

  1. Create My_Router.php in application/core/ directory

/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */

/**
 * Description of My_Router
 *
 * @author girish
 */
class My_Router extends CI_Router {

    //put your code here
    public function __construct($routing = NULL) {
        parent::__construct($routing);
    }

    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?
    if (sscanf($this->default_controller, '%[^/]/%[^/]/%s', $directory, $class, $method) !== 3) {
        $method = 'index';
    }
    if (is_dir(APPPATH . 'controllers' . DIRECTORY_SEPARATOR . $directory) === true) {

        if (!file_exists(APPPATH . 'controllers' . DIRECTORY_SEPARATOR . $directory . DIRECTORY_SEPARATOR . ucfirst($class) . '.php')) {
            // This will trigger 404 later
            return;
        }
        $this->set_directory($directory);
        $this->set_class($class);
        $this->set_method($method);
    } else {
        if (sscanf($this->default_controller, '%[^/]/%s', $class, $method) !== 2) {
            $method = 'index';
        }
        if (!file_exists(APPPATH . 'controllers' . DIRECTORY_SEPARATOR . ucfirst($class) . '.php')) {
            // This will trigger 404 later
            return;
        }
        $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.');
   }

}

and overwrite _set_default_controller() from custom method, it will work from sub-directory controller as well root directory controller.

And in application/config/routes.php

if you need sub-directory default controller, then

 $route['default_controller'] = "admin/admins/login";
  • admin -- folder
  • admins -- controller
  • login -- method

if you need root-directory default controller, then

 $route['default_controller'] = "welcome/index";
  • welcome -- controller
  • index -- method

not sure it will work in all versions, but tested in CI3.0.6

If you want to stay flexible you need to pass on everything after the starting folder (in application/config/config.php ):

$route['home'] = "home/whatever";
$route['home/(:any)'] = "home/whatever/$1";

Add this line in application/config/routes.php

$this->set_directory( "yourfoldername" );
$route['default_controller'] = 'controller name';

Default route is used to tell CI, which controller class should be loaded if the URI contains no data.

在此处输入图像描述

$route['default_controller'] = "unicorn/best";

So, when I load

http://example.com/index.php/unicorn/

the best controller will be loaded.

also when I load

http://example.com/

or

http://example.com/index.php/horse/

the best controller will be loaded.

MY FOLDER STRUCTURE

--controllers
  --backend
  --frontend
    --home.php
    --products.php
    --productDetail.php
--homeIndex.php

In config/routes.php

$route['default_controller'] = 'homeIndex';
$route['frontend'] = 'frontend/home';
$route['backend'] = 'backend/home';

In controllers/homeIndex.php

<?php    
defined('BASEPATH') OR exit('No direct script access allowed');
require_once(APPPATH.'controllers/frontend/Home.php');    
class homeIndex extends home {    
    public function index() {
        $this->action();
    }    
}

by default homeIndex will be loaded and from homeIndex i call to frontend/home/action function.

In application/config/routes.php just add this

$this->set_directory( "user" );
$route['default_controller'] = 'home/index';

Here, user is my folder name. Then in default controller you can call any controller that is in user folder following by function name

If i use the following code

$this->set_directory( "user" );
$route['default_controller'] = 'home/index';

then another route in another sub directory does not work.

Suppose i am using sub-directory user in controller directory for default controller. but if i like to use FrontEnd sub-directory for another route,

$this->set_directory( "FrontEnd" );
$route['product/(:any)'] = 'product/$1';

then it is not working.

Even though the question has many (and an accepted answer) I, still, would like to post mine.

I figured out that subfolders works for regular routes. For example, I can do:

$route['frontend/test'] = "frontend/Welcome/test";

and if I visit site/frontend/test , it works as expected. The problem is getting "default_controller" to work with subfolders. For example, the following doesn't work:

$route['default_controller'] = "frontend/Welcome/test";

If we examine the URI Routing > Reserved Routes section, it says:

You can NOT use a directory as a part of this setting!

So we need to hack our way in. I've used Girish 's approach . I've examined the system/core/Router.php and created application/core/MY_Router.php .

At first, I thought Girish made a static change to the _set_default_controller method, that it allows only subfolders. I thought it should be dynamic and subfolder should be optional. Later, I realized that he made a case for that too, but his code has duplicate logic and I was already done with mine. So I'm posting it anyway.

<?php

class MY_Router extends CI_Router {
    
    /**
     * The default controller expects a string in the following format: "controller/method".
     * The method at the end is optional. If the method is omitted, the default method is "index".
     * 
     * Examples:
     *  * $route['default_controller'] = "Welcome";
     *  * $route['default_controller'] = "Welcome/index";
     * 
     * Both end up being routed to "Welcome/index".
     * 
     * The default controller does NOT expect a subfolder in the "controllers" folder. So the following won't work:
     *  * $route['default_controller'] = "frontend/Welcome/index"
     * 
     * To make subfolders work, _set_default_controller() needs to be modified, and that's what this MY_Router is for.
     *
     * The modification is kept to a minimum and is marked.
     */
    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.');
        }
        
        /* START MODIFICATION */
        
        /*
            Removing this block, as it only allows/look for "controller/method".
            // Is the method being specified?
            if (sscanf($this->default_controller, '%[^/]/%s', $class, $method) !== 2)
            {
                $method = 'index';
            }
        */
        
        /*
            Instead of just checking for "controller/method", we need to also look for a subfolder.
            Because the latter operations depend on the first segment.
            So, the first thing to do is to figure out if the first segment is a folder or a class/file.
            Possible inputs:
                "Welcome"                   -> class                -> autocomplete
                "Welcome/index"             -> class/method
                "frontend"                  -> folder
                "frontend/Welcome"          -> folder/class         -> autocomplete
                "frontend/Welcome/index"    -> folder/class/method
        */
        
        $segments = explode("/", $this->default_controller);
        $segments = array_filter($segments); // ignore leading and trailing slashes
        
        if (count($segments) > 3) {
            show_error('Invalid controller. Default controller supports only one subfolder.');
        }
        
        $method = null;
        
        // If the first segment is a folder, the second needs to be a class/file.
        if (is_dir(APPPATH.'controllers/'.$segments[0])) {
            $this->set_directory($segments[0]);
            if (!isset($segments[1])) {
                show_error('Invalid controller. A subfolder is provided, but the controller class/file is missing.');
            }
            $class = $segments[1];
            if (isset($segments[2])) {
                $method = $segments[2];
            }
        }
        // If the first segment is NOT a folder, then it's a class/file.
        else {
            $class = $segments[0];
            if (isset($segments[1])) {
                $method = $segments[1];
            }
        }
        
        // If the method isn't specified, assume that it's "index".
        if (!$method) {
            $method = "index";
        }
        
        /* END MODIFICATION */
        
        if ( ! file_exists(APPPATH.'controllers/'.$this->directory.ucfirst($class).'.php'))
        {
            // This will trigger 404 later
            return;
        }
        
        $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.');
    }
    
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM