• 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Controllers in Unlimited Nested Folders

#1
[eluser]Peter Goodman[/eluser]
So, limiting users to one level of sub folders was a real "wtf?" decision on the part of the devs imo, especially since working with an unlimited nesting of folders is *so* easy. Here's an extended version of the CI_Router class that changes a few of the things deep in the code. You can see the code I modified by the comments. It's a very similar modification in the end and actually requires *less* code then that class uses if the CI devs would just up an implement it. Here it is:

NEW VERSION!! you no longer need the custom URI library to work with this either.

Code:
<?php

/**
* Router Extension to allow controllers in unlimited nesting of folders.
* Discussion thread at: http://ellislab.com/forums/viewthread/56100/
* @author Peter Goodman
* @copyright Copyright 2007 Peter Goodman, all rights reserved.
*/
class Router extends CI_Router {
    
    function _set_route_mapping() {
        parent::_set_route_mapping();
        
        // re-routed url
        if($this->rsegments != $this->segments) {
            array_unshift($this->rsegments, $this->directory);
        }
    }
    
    function _pluck_directory($segments) {
        $this->directory = '';
        
        foreach($segments as $segment) {
            $segment = trim($segment);
            if($segment != '') {
                if(is_dir(APPPATH .'controllers/'. $this->directory . $segment)) {
                    $this->directory .= array_shift($segments) .'/';
                } else {
                    break;
                }
            } else {
                array_shift($segments);
            }
        }
        
        // quick an easy forced reindexing
        $segments = array_values($segments);
        
        // put the entire directory path back into the segment as the first
        // item
        $dir = trim($this->directory, '/');
        if(!empty($dir)) {
            array_unshift($segments, $dir);
        }
        
        $this->segments = $segments;
        
        return $segments;
    }
    
    function _validate_segments($segments) {
        return parent::_validate_segments($this->_pluck_directory($segments));
    }
}

#2
[eluser]Phil Sturgeon[/eluser]
Nicely done, saved me having to work that one out.

In the future if you could try and post PHP4 compatible code it wouldnt cause as much confusion, but from looking at I methinks its only a matter of removing the access keywords (public/private).

#3
[eluser]Peter Goodman[/eluser]
Yeah, the only php5 thing about this is the public/private Smile

#4
[eluser]Peter Goodman[/eluser]
Make sure to update your router class to the above, I changed it (again) and also get the code from the post below.

This was a bit of a hack, leading my to the conclusion that the CI router system needs a total rewrite.

#5
[eluser]Peter Goodman[/eluser]
You will also need this for scaffolding.

EDIT: THIS CODE NO LONGER NEEDED!

#6
[eluser]bjk2007[/eluser]
Just a note that I had problems with this router replacement when using a path like example.com/nested1/nested2/ . In this case, Code Igniter is supposed to load welcome.php (or whatever you change the configuration to), which this does, but it also throws an error first about $segments[0] not being defined around line 103. Here's my quick fix I made in case anyone else has this problem.
Simply replace this:
Code:
if (file_exists(APPPATH.'controllers/'. $this->directory . $segments[0] .EXT)) {
with this:
Code:
if (isset($segments[0]) and file_exists(APPPATH.'controllers/'. $this->directory . $segments[0] .EXT)) {
thereby making sure that $segments[0] is defined first.

The other option is to adjust your error sensitivity. Either way works, but this stops it all together.

#7
[eluser]Peter Goodman[/eluser]
Thanks! I've updated the above code to reflect your bug fix. If you're working with scaffolding and it doesn't work, just make sure that you have *all* of the code above including a custom URI library. I added a lot of this stuff in after the main post (but updated it) as I found things not working (then fixed them). If you follow along how it all works, it's a pretty ugly hack (unsetting $this->directory, but storing a $this->dir) because of the fact that route segments are hard coded.

#8
[eluser]Peter Goodman[/eluser]
EVERYONE! I have made a new version that is simpler! Check out the code at the top and make sure to change your Router library to that one. Also, if you used the URI library I made, you can remove it!! It's no longer needed! I hope this new version helps.

Again.. make sure to update to the new code in the first post and only that code (remove custom URI lib) to get routes working in multiple subfolders!

The new version works by not overwriting the way CI does stuff but by merely taking advantage of it. A simple explanation:

If we have this route: /a/b/controller/action/ Then CI will see a and see that it's a folder. It will then see b and assume that it is the controller. This was poor thinking on the part of the CI devs. So, instead, what I do is we let CI split up the route as usual in whatever way it wants, then I manually go through the parts, see that a and b are directories and merge them.

Code:
<?php

// Normal way CI splits up the parts of a route:
array(
   [0] => a  // folder
   [1] => b  // sub-folder, CI doesn't recognize this
   [2] => controller
   [3] => action
)

// what happens when you use this extension:
array(
   [0] => a/b // folder with sub-folder(s), CI can work as normal with this
   [1] => controller
   [2] => action
)

#9
[eluser]bjk2007[/eluser]
OK, I just got done replacing your old version with the new one, but this is what I get when I try going to a URL.
http://aedisit.com/home/buildapc/customize.php
(/folder1/folder2/controller)
Code:
A PHP Error was encountered

Severity: Warning

Message: include({CONTROLLERDIR}/home/buildapc/home/buildapc.php) [function.include]: failed to open stream: No such file or directory

Filename: codeigniter/CodeIgniter.php

Line Number: 135

----------------------------------------

A PHP Error was encountered

Severity: Warning

Message: include() [function.include]: Failed opening '{CONTROLLERDIR}/home/buildapc/home/buildapc.php' for inclusion (include_path='.;\xampp\php\pear\')

Filename: codeigniter/CodeIgniter.php

Line Number: 135

----------------------------------------


An Error Was Encountered

Unable to load your default controller. Please make sure the controller specified in your Routes.php file is valid.
For purposes of clarification, I have the script currently posted at the top of the page in the libraries/MY_router.php file. This problem is only affecting controllers deeper than 1 folder level; everything else still routes fine.
You sure you have this working properly? I'm just going to stick with the old version for now until I figure this out.

#10
[eluser]bjk2007[/eluser]
Just solved it. I had an old controller sitting at the same level as that subfolder with the same name. I simply removed the controller and everything works fine.


Digg   Delicious   Reddit   Facebook   Twitter   StumbleUpon  


  Theme © 2014 iAndrew  
Powered By MyBB, © 2002-2021 MyBB Group.