Welcome Guest, Not a member yet? Register   Sign In
CI Router Bug for default_controller into a subfolder and other little corrections + User guides requested modification.
#1

[eluser]Unknown[/eluser]
Ok before to describe the problems into the Router.php library, I think I have to clarify some things about the new CI 1.6 Router and URI engine. And I hope that some one of the CI dev team tell me if I'm right.
May be we have to update some user guide pages about segments and rsegment features explanations.

:exclaim: Now we can say that rsegment array never contain the contoller subdirectory (even if we use routes).

accordingly we should add the following entry to the user guide:
1- URI and RURI (and also uri->segments and uri->rsegment) are no more the same when we don't use a route. In other words the old rules that say URI=RURI if URI doesn't use a route is wrong since CI 1.6.

2- the first argument of the controller method (if the URI use args) is always in the 3th place in RURI (uri->rsegment[3] or uri->rsegment('3')) whereas it could be in the 3th or the 4th in URI depending if the controller is or not into a subfolder.
This new rule is also available if we use route.
So it is a more sure way to retrieve function params.

:exclaim: Other important things to add in the user guide about RURI:

We also should add that since CI 1.6 RURI always contain the requested controller and function, even when CI Router deal with default controller and index method.
It is some thing different with the CI previous versions, now even when URI='' or URI='contoller_name' RURI is completed with controller and method so RURI='default_controller/index' or RURI='contoller_name/index'
The CI Router bug explain after is in fact a little case that doesn't match with this rule.

:question: Introduction to the Router.php problem:

As I have well read the code (I work on some extension of the CI Router) I think that new CI Router and URI library add many good things in the CI URI features but it also add a best structure and clarity into the code itself first by the separation between routing and uri functions into two class, and also by a clearest tasks distribution between Router function.
Specialy for _validate_request() and _set_request() function.
_validate_request(): only deal with controller subfolder detection.
_set_request(): deal with controller (class) and function (method) detection.
So in addition to the little debug I think that we can move some little code line that broke this task distribution and help to make a minimal code change for the final solution.

There is 3 functions involved into my changes : _set_routing(), _validate_request() and _set_request().


_set_routing() The most simple correction, I think this is an old remaining peace of code.

original code is:
Code:
if ($this->uri->uri_string == '')
{
if ($this->default_controller === FALSE)
{
show_error("Unable to determine what should be displayed. A default.........");
}
$this->set_class($this->default_controller);
$this->set_method('index');
$this->_set_request(array($this->default_controller, 'index'));
//.....
As I have said before $this->_set_request() deal with the class and method detection so when we call it with default controller and index method as arguments we know that the function will set this 2 value right.
So we can remove two lines as follow.
Code:
if ($this->uri->uri_string == '')
{
if ($this->default_controller === FALSE)
{
show_error("Unable to determine what should be displayed. A default.........");
}
//$this->set_class($this->default_controller);
//$this->set_method('index');
$this->_set_request(array($this->default_controller, 'index'));
//.....

The Bug:
If we use an URI with only a controller subfolder name URI = "subfolder" we ave 3 possibles RURI, if we follow the router code we can see that:
- we first search if there is a controller with the default_controller name in this subfolder
- then we unset the subfolder and search the default_controller in the root controller folder.
- and then we show the 404 error.
SO IF WE FOLLOW THE NEW CI 1.6 RURI RULE the two first cases should have RURI ='default_controler/index' the differences is that in the first cases we have router->directory="subfolder".
But in fact in the both case RURI is EMPTY(it is the problem).

First have a look into _set_request() function:

Code:
function _set_request($segments = array())
{        
    $segments = $this->_validate_request($segments);
        
    if (count($segments) == 0)
    {
        return;        
    }

As I said before _validate_request() feature is to detect controller subfolder and remove it from the segment array so if URI ="subfolder" => $this->_validate_request($segments)= array()
so we return and uri->rsegment is not set.
#2

[eluser]Unknown[/eluser]
(la suite)

so the complete function should be:

Code:
function _set_request($segments = array())
{    
        
    $segments = $this->_validate_request($segments);    
    if (count($segments) == 0)
    {
        //CHANGE
        //we re-introduice the default_controller into the rsegments even
        //when we point to a default controller in a subdirectory
        $segments[0]= $this->default_controller;    
    }
                        
    $this->set_class($segments[0]);
    if (isset($segments[1]))
    {
       // A scaffolding request. No funny business with the URL
       if ($this->routes['scaffolding_trigger'] == $segments[1] AND $segments[1] != '_ci_scaffolding')
        {
            $this->scaffolding_request = TRUE;
            unset($this->routes['scaffolding_trigger']);
        }
        else
        {
            // A standard method request
            $this->set_method($segments[1]);
        }
    }
    else
    {
        // This lets the "routed" segment array identify that the default
        // index method is being used.
        $segments[1] = 'index';
    }
    // Update our "routed" segment array to contain the segments.
    // Note: If there is no custom routing, this array will be
    // identical to $this->uri->segments
    $this->uri->rsegments = $segments;
}

This way segment is set with the default controller and index method.
according to this modification we can add a little simplification into the _validate_request() function when there is a directory and no controller in URI (our cases).

Code:
function _validate_request($segments)
{
   // Does the requested controller exist in the root folder?
   if (file_exists(APPPATH.'controllers/'.$segments[0].EXT))
   {
     return $segments;
   }

   // Is the controller in a sub-folder?
   if (is_dir(APPPATH.'controllers/'.$segments[0]))
   {        
     // Set the directory and remove it from the segment array
     $this->set_directory($segments[0]);
     $segments = array_slice($segments, 1);
            
     if (count($segments) > 0)
     {
         // Does the requested controller exist in the sub-folder?
         if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$segments[0].EXT))
         {
            show_404();    
         }
      }
      else
      {
         //??? Because of the change into the _set_request() function
         //??? And also because it is not the right place to set class and method
         //??? We can remove this two lines.
         //CHANGE
         //$this->set_class($this->default_controller);
         //$this->set_method('index');

         // Does the default controller exist in the sub-folder?
         if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.EXT))
         {
           $this->directory = '';
           return array();
         }
      }        
     return $segments;
   }
   // Can't find the requested controller...
   show_404();    
}

Don't forgot that if you want to use this correction instead of adding this changes into the Router.php Lib Create A MY_Router.php file into your application/libraries folder with only the 3 functions.
download the file:
http://www.myfw.org/releases_files/CI1.6..._debug.zip

Sorry for my english....
See you
#3

[eluser]macigniter[/eluser]
Seriously. The user guide needs some info on that changed behaviour.

I just stumbled over this when using rsegment with a subfolder. I didn't know that $this->uri->segment(1) actually returns the subfolder and $this->uri->rsegment(1) doesn't. Now I know... Undecided




Theme © iAndrew 2016 - Forum software by © MyBB