CodeIgniter default controller in a sub directory not working

Viewed 54114

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

9 Answers

Add this line in application/config/routes.php

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

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