Love Fuel?    Donate

FuelPHP Forums

Ask your question about FuelPHP in the appropriate forum, or help others by answering their questions.
Can I route this?
  • Hi guys, I have a question about routing and modules. I currently have setup a catch-all routing in the main config/routes.php file. I want all the requests directed to one main controller.
    '(:section_uri)/(:page_uri)' => 'web/index',
    

    The section_uri corresponds with a specific module. This relationship is stored in the database.
    // $module is retrieved from database
    $widget = $module.'/web/'.$this->param('page_uri');
    $this->response = Request::factory($widget, false)->execute()->response();
    

    Now I would like to use the module routing to further process the request. But since I have a catch-all routing setup in my main routing file, this one always takes preference. I've fiddled around with setting the $route variable of the Request::factory(), and the main routes file. But so far I've only succeeded to get results with changing the main routes.php. Any ideas?
  • Any entry in config/routes.php is per definition public. If the result of your database lookup is a URI that is public (routeable), you can feed the result back into a new request object, and route it. But you don't have to make it so complicated, as a simple redirect would do the same trick. You then use the _404_ route as a catch-all to your web controller. If the result of the lookup is not public, you can't run it through the routing engine. But why should you? You have the mapping in the database, wouldn't it be more logical to make a change there, instead of in a config file? If your looking for specific in-module routing, you might be able to do the following:
    // reset the router so only module routes are used
    \Router::routes = array();
    
    // route the widget request
    $this->response = Request::factory($widget)->execute()->response();
    

    disclaimer: from memory, not tested at all! And don't forget to deal with 404's in the module as well, as you're response will be Fuel's default 404 page is $widget can't be routed (because there is no more global 404 route).
  • Hi WanWizard, Thanks for your reply. Unfortunately your code to reset the routes produces an error (ErrorException [ Parsing Error ]: syntax error, unexpected '='). But that was part of the disclaimer ;) Maybe it's better if I give you some more background information, to what my actual situation is. Maybe there is a smarter way to handle this. Ok, I'm re-building an existing CMS application to Fuel. The basic idea of the URLs within the CMS is that the first segment references to the 'section' and the rest of the segments make up the 'page url', within that section. The section segment can be whatever the user chooses (e.g. english, website, test etc.) and in the database is stored which module-type the section is (e.g. website, blog, forum etc.). So what I have so far is 1 main controller that handles all the requests. It does a lookup in the database which module we are handling now, and then should hand the control over to the appropriate module. Then to keep my application modular I figured it makes sense to have the module handle the specific routing from that point on (e.g. a 'reply' segment for a forum-module would have a different route). So far I'm trying different approaches with invoking the module-controller from my main controller (static calls and HMVC requests), but it doesn't work all that well yet. I hope you understand where I'm going with this, and would appreciate your view on it! Thanks a lot in advance!
  • Should be \Routes::$routes. It's a static class property. I do something similar, but my modules don't produce pages, only widgets. So by front controller sets up the theme, fetches the defined widgets from the database, launches requests for each of the widgets and passes the result on to the theme template.
  • Harro Verton wrote on Tuesday 28th of June 2011:
    Should be \Routes::$routes. It's a static class property.

    Yeah .. I just figured that out too ;)
    Harro Verton wrote on Tuesday 28th of June 2011:
    I do something similar, but my modules don't produce pages, only widgets. So by front controller sets up the theme, fetches the defined widgets from the database, launches requests for each of the widgets and passes the result on to the theme template.

    That's an option as well, but that would mean that the front controller handles all the logic for the modules, isn't it? Which method do you use for calling the module functions? Via HMVC or through static calls? What would be the advantage of either?
  • There's no real logic in the front controller. I use Joomla-style templates, with defined sections. A query from the database gives me a list of sections for the requested URI, and per section the widgets to display. These are processed according to their definitions (it's a bit more complex than this), and added to the template via a Theme class. I only use Request, no static calls, as I want my modules as loosly coupled as possible. After processing the template is rendered. It will determine the asset path, the assets to load, it also loads assets defined by widgets (for example extra js code), and then simply inserts the widget output in the correct div structure of the template.
  • I've been trying out your code resetting \Routes::$routes, but that actually doesn't work. After looking closer to what is happening, I see that my issue would be solved if the routes of the module would be prepended to \Routes::$routes, instead of appended. Wouldn't this also make more sense? Since you're doing a request for a specific module, you want to make sure that those routing rules are followed for sure and not possibly overriden by the standard routing. You might even want to have the opportunity to override the standard routing in a module. I managed to get this to work in a quick-and-dirty way by adding a method 'add_before' to the Router class:
     public static function add_before($path, $options = null)
     {
      
      if (is_array($path))
      {
       foreach ($path as $p => $t)
       {
        static::add_before($p, $t);
       }
       return;
      }
    
      $name = $path;
      if (is_array($options) and array_key_exists('name', $options))
      {
       $name = $options['name'];
       unset($options['name']);
       if (count($options) == 1 and ! is_array($options[0]))
       {
        $options = $options[0];
       }
      }
    
      $route[$name] = new \Route($path, $options);
      
      static::$routes = array_merge($route, static::$routes);
    
     }
    

    And changing 2 little things in the Request class:
    // check if the module has custom routes
    if (file_exists($modpath .= 'config/routes.php'))
    {
     // load and add the routes
     \Config::load(\Fuel::load($modpath), 'routes', true); // added true, to force reload        
     \Router::add_before(\Config::get('routes')); // now calling add_before instead of add
    }
    

    I haven't thoroughly tested this, and I'm sure it's not the most efficient way of doing things, but it was done to figure out where my problem was. I also don't know if this approach would break setups other than mine. But maybe it is useful in the next update? That is, if you agree with the idea that module specific routes should get preference. -Michiel
  • I'm struggling to understand what the logical difference is between prepending them, and resetting the array (which would make it the only contents). The only difference can be that a non-module route is matched in the first case... Module routes are required to always start with 'modulename/' on the lefthand side. If you have violated that rule, there could be a mixup with your global routes.
  • Well, isn't this they way that Fuel also works with other config files? Comment from the config class:
    // Reverse the file list so that we load the core configs first and
    // the app can override anything.
    

    If you reset the routes, they are gone. If you prepend the module routes, the old ones still exist, allowing you to set defaults that are valid for all modules, while still being able to overwrite the ones that should be different for that specific module.
  • Harro Verton wrote on Tuesday 28th of June 2011:
    Module routes are required to always start with 'modulename/' on the lefthand side. If you have violated that rule, there could be a mixup with your global routes.

    I see you added this after I replied your message. My module routes do start with the modulename, but since they are appended to the catch-all route, they are never processed, since the catch-all route is always invoked. Hence my solution to prepend the module routes.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion