Home > PHP > Multi Level Subfolder Controller in CodeIgniter

Multi Level Subfolder Controller in CodeIgniter

CI logo

CI logo

Well, this is my first post so be gentle to me :).

Recently i’m working on a web based application project using CodeIgniter framework. Problem arises when my boss wants this web application to have more than two level subfolder in controller folder (for example: /controller/company_a/admin/, /controller/company_a/reports/) for organizational purpose.

As the default CodeIgniter version 1.7.2 set up, controllers can’t have multi level subfolder, so I need to find a way to provide the request.

After a little bit of Googling and searching on CodeIgniter forums, I found this thread http://codeigniter.com/forums/viewthread/85554/

There’s a solution for this problem on that thread but i don’t like the idea hacking the CI core so I modified it. So here’s the solution:

  1. Copy this code into your CI application library folder (the default is /system/application/libraries), and name it as MY_Router.php:
    <?php
    
    /*
     * Custom router function v 0.1
     *
     * Add functionality : read into more than one sub-folder
     *
     */
    
    Class MY_Router extends CI_Router
    {
    	Function MY_Router()
    	{
    		parent::CI_Router();
    	}
    
    	function _validate_request($segments)
    	{
    		if (file_exists(APPPATH.'controllers/'.$segments[0].EXT))
    		{
    			return $segments;
    		}
    
    		if (is_dir(APPPATH.'controllers/'.$segments[0]))
    		{
    			$this->set_directory($segments[0]);
    			$segments = array_slice($segments, 1);
    
    			/* ----------- ADDED CODE ------------ */
    
    			while(count($segments) > 0 && is_dir(APPPATH.'controllers/'.$this->directory.$segments[0]))
    			{
    				// Set the directory and remove it from the segment array
        		$this->set_directory($this->directory . $segments[0]);
        		$segments = array_slice($segments, 1);
    			}
    
    			/* ----------- END ------------ */
    
    			if (count($segments) > 0)
    			{
    				if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$segments[0].EXT))
    				{
    					show_404($this->fetch_directory().$segments[0]);
    				}
    			}
    			else
    			{
    				$this->set_class($this->default_controller);
    				$this->set_method('index');
    
    				if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.EXT))
    				{
    					$this->directory = '';
    					return array();
    				}
    
    			}
    
    			return $segments;
    		}
    
    		show_404($segments[0]);
    	}
    }
    
    ?>
    

  2. And we’re done  🙂 . Simple isn’t it?

Feel free to test it and give your opinion. Any suggestions will be very much appreciated. Thanks!

  1. October 21, 2009 at 9:43 pm

    Indeed, well done sir.

    • October 21, 2009 at 10:34 pm

      Glad to share some information 🙂

  2. utie..
    October 22, 2009 at 9:43 pm

    Brilliant..I’m very proud of you 🙂

  3. October 23, 2009 at 11:39 am

    Very use full for developers… nice think

  4. October 30, 2009 at 10:07 am

    Still Fuzzy with this things, I’m familiar with cisco command than this one Ge…
    😀

    • October 30, 2009 at 11:33 pm

      Well,you have to learn the basic first before you use this framework 😉

  5. November 2, 2009 at 11:06 am

    Thank you for this! I especially like how you implemented it over other suggestions from the forums.

    • November 2, 2009 at 7:28 pm

      You’re welcome. I just modify it a little so it still follow Codeigniter rules about overriding the core. But thanks for your word 🙂

  6. November 3, 2009 at 3:33 pm

    Nice Sir. Thank you.

  7. December 6, 2009 at 10:53 pm

    Perfect… Thanks in advance.

  8. January 17, 2010 at 9:23 am

    Thanks for this, works perfectly!

    This has made my day! 🙂

  9. February 18, 2010 at 1:48 am

    Nice effort put forth in doing this and sharing it to others. Its a shame that even though CI is open source everything is pretty much only done by EllisLabs (which I am grateful for) but if it was more open CI could have major improvements regularly such as this one.

    We are constantly forced to hack or extend (a more elegant hack) it to meet our needs however if development was more open to community patches that pass all tests required to conform to CI’s quality it would probably cut the hacking of it down by 50% at the very least.

    Regardless, at least they have the wiki which is a somewhat happy medium and where I post my contributions (hacks).

    Thanks!

    • March 4, 2010 at 10:00 am

      That’s why there’s Kohana 🙂
      But i agree about your opinion. CI need a more “open development” to community patches.

      Nice to know you 🙂

  10. Toby
    April 12, 2010 at 7:54 pm

    Thanks a lot! This has made my day too! Simple and well thought, and indeed, this could be implemented in CI…

  11. Mariano
    April 14, 2010 at 11:09 am

    Glenn,

    Thanks for sharing you just saved my arse 🙂

    Cheers,

  12. June 3, 2010 at 1:29 am

    You are the fu**** Master!!! thanks

  13. Adam Brenner
    June 13, 2010 at 4:02 am

    Glenn,

    Thanks for the useful post. I believe you made a typo, in that you are supposed to place the MY_Router.php file in /system/applications/libraries folder (not library) as you have.

    Thanks again!
    -Adam

    • October 6, 2010 at 1:32 pm

      thanks for your correction. Corrected 😉

  14. hamza khan
    June 30, 2010 at 10:20 pm

    nothing happening for me still getting 404 ERROR.

    my form action to add region
    http://localhost/server/connectionspot/admin/geographic/region/add
    when i click submit to add regions my url will look like this
    http://localhost/server/connectionspot/admin/regions/?lang=ch

    geographic automatically removed plz help me our

    controllers
    !_admin
    !_geographic
    !_regions

    i use my_route but still nothing happening

  15. waqas
    July 9, 2010 at 4:12 pm

    God bless u .. thanx

  16. Cesar
    August 13, 2010 at 3:35 pm

    Okay I understood it. Thans a lot!

  17. September 6, 2010 at 1:25 pm

    Nice one!
    Still useful till now.

    Why don’t you write anymore? 😉

    • October 6, 2010 at 1:22 pm

      thanks for your attention 🙂 i’ll start to write something pretty soon 🙂

  18. September 7, 2010 at 11:00 pm

    Fanstastic! That’s exactly what I needed. Thanks.

  19. Bhavani
    September 15, 2010 at 2:31 pm

    Hi Glenn,

    Good to see your post. I am new to CodeIgniter. I would like to know, how the one level folder url path will look like.

    I have created “Products” folder in the “Controllers” directory and placed the main router file which I have copy/pasted from the above given code of My_Router.

    ——Controller
    |
    —Products – placed the Product_Router here (Let me know whether this is the right place of the file)
    |
    ——Reports1
    ——Reports2

    I am trying to call the Reports1 controller sampleReport() method

    Url I tried out is:

    http://localhost/CodeIgniter/index.php/products/reports1/products_router/sampleReport

    Is the above url correct. If not, can you kinldy let me know the correct url.

  20. Bhavani
    September 21, 2010 at 6:04 pm

    I got the solution. Thanks

    • October 6, 2010 at 1:28 pm

      sorry for late answer. Good for you then 🙂

  21. vee w
    October 11, 2010 at 11:38 am

    hey, it’s work!
    thank you

  22. chamil sanjeewa
    November 4, 2010 at 7:26 pm

    thank u very much. its help me to keep my project folder stature well

  23. qwer
    November 21, 2010 at 8:07 pm

    wel done sir. tks

  24. surath
    November 24, 2010 at 2:23 pm

    saved my day! now things are working like a charm..

    great post, I must say

    thanks a lot 🙂

  25. barry
    November 26, 2010 at 5:10 am

    Cheers, saved me some time. Please have this virtual beer as a token of my appreciation. (if it doesnt break)

    _.._..,_,_
    ( )
    ]~,”-.-~~[
    .=])’ (; ([
    | ]:: ‘ [
    ‘=]): .) ([
    |:: ‘ |
    ~~—-~~

    • barry
      November 26, 2010 at 5:10 am

      It broke.. sorry pal 😉

      • December 22, 2010 at 2:17 pm

        haha.. 😀

  26. SaintMak
    November 30, 2010 at 1:36 am

    I’m newbie to codeigniter and implemented custom router function. I have currently http://localhost/services/webdesign which webdesign page works now but how do I also have content for services as when I create a services controller it then stops the webdesign controller from loading?

    Thanks in advance!

    • December 22, 2010 at 2:17 pm

      U cant have services controller if you want webdesign controller to work. U can move webdesign controller to another folder, or u can make webdesign method in services controller.
      Hope this will help u. Cheers

  27. December 24, 2010 at 5:46 am

    thank you very much.. this is my real solution… thanks a lot

  28. December 28, 2010 at 3:44 pm

    Word of warning:

    not that any of you would be this dumb but something to look out for:

    Don’t name the subdirectory the same name as another controller… took me WAAAY too long to debug that.

    Naming the subdirectory the same name as another controller in the same directory fails a check in MY_Router.php. I had a file: “api.php” and a subdir “api”. The way in which CI checks for a valid subdir is to immediately append a “.php” on the end of a subdir and see if it exists… well in my case it did exist, but it was checking for the wrong one…

    I’m not going to comment on this algorithm, but watch out.

    Decent MVC otherwise.

  29. December 29, 2010 at 12:28 am

    With your added code, I don’t think you can use 2+ deep directories. The “set_directory” command seems to screw things up in Router.php. The reason is that function removes all forward slashes then appends a forward slash on the end… that’s not what we want to do if you have more than 1 deep. Your mod helped with a single subdir, but not 2.

    I’ve tried the mod I’m suggesting on several levels deep:
    application/controller/file.php
    application/controller/subdir/file.php
    application/controller/subdir1/subdir2/file.php

    Unless they changed the code for Router.php in the past – I’m running 1.7.3.

    The following code should work in replacement of your modification. You should be able to easily see what I changed – I just commented it out:

    /* ———– ADDED CODE ———— */
    while(count($segments) > 0 && is_dir(APPPATH.’controllers/’.$this->directory.$segments[0]))
    {
    // Set the directory and remove it from the segment array
    $this->directory = $this->directory . $segments[0] . ‘/’;
    //$this->set_directory($this->directory . $segments[0]);
    $segments = array_slice($segments, 1);
    }
    /* ———– END ———— */

    Nevertheless, thanks a ton for your mod, I would have been stuck for a long while without your fix.

    • March 23, 2011 at 10:28 am

      Hmm, i’m not check this mod for version 1.7.3, but thanks for your mod. I’ll try this. 🙂

    • May 7, 2011 at 10:18 am

      Hi, there. It’s me, again 🙂

      I’ve just noticed that this won’t work with CI 1.7.3. I’ve got mine work well previously with 1.7.2.
      The change in Router.php from 1.7.2 to 1.7.3 might have deals with it.

      But as DonJohnII suggests, a little change in your code:

      // $this->set_directory($this->directory . $segments[0]);
      $this->directory = $this->directory . $segments[0] . '/';
      

      work as magic and my code work well again as before. 😀

      Thanks, guys.

      PS: I wonder if this would work also in the latest version of CI: 2.0.2. Anyone have tried it?

      PPS: I’m still waiting for your next writing 😉

  30. Maul
    March 9, 2011 at 5:16 pm

    i’m sorry i don’t get this. how do we use it? aren’t we supposed to call my_router function or class?

    • March 23, 2011 at 10:29 am

      you dont have to call this class, it will automatically override native core of CI itself. Cheers

  31. Fredy
    April 13, 2011 at 2:04 pm

    Thanks for this library …. it’s work brot

  32. July 1, 2011 at 1:36 pm

    this is not working with codeiginater 2.0 Please help me

  33. August 8, 2011 at 8:48 pm

    This doesn’t work for me either in 2.0. please help

    • April 30, 2012 at 1:12 am

      you can use version 2.1 and see this instead

  34. biecyber
    January 22, 2012 at 1:39 pm

    gw coba nyang punya loe bro, trus filenya gw taro di application/libraries/ gak bisa bro, trus gw cari di forum codeigniter, type nya sih sama ama yg punya loe bro, tapi kalo dia naronya di application/core, and it work ^^
    coba kesini kalo ada yang masih belum bisa:

    http://codeigniter.com/forums/viewthread/202176/

    • April 30, 2012 at 1:15 am

      ci yg gue pake ci lama bro. Itu utk ci 2 ke atas ya. Anyway thanks.

  35. February 16, 2012 at 12:40 am

    Hi Glenn, thanks very much for a job well done. Here are some fixes to your code to bring it in line with CI 2.0:

    1) Like Don Jon posted above, you need to set $this->directory directly instead of using set_directory (allowed b/c it’s public). New code:
    /* ———– ADDED CODE ———— */
    while(count($segments) > 0 && is_dir(APPPATH.’controllers/’.$this->directory.$segments[0]))
    {
    // Set the directory and remove it from the segment array
    $this->directory = $this->directory . $segments[0] . ‘/’;
    $segments = array_slice($segments, 1);
    }
    /* ———– END ———— */

    2) My_Router.php needs to be in the “application/core/” folder, not “libraries”.

    If you can just update your post, I don’t know if many readers would scroll down this far just to make it compatible with more recent installations.

    Cheers and thanks again,
    Mike

    • April 30, 2012 at 1:15 am

      thanks for your fix 🙂

  1. November 2, 2009 at 11:14 am
  2. November 7, 2009 at 9:04 am

Leave a reply to Glenn Cancel reply