Skip to main content
Topic: Router and Dispatcher (Read 4302 times) previous topic - next topic
0 Members and 1 Guest are viewing this topic.

Router and Dispatcher

I've been working on tweaking the dispatcher to make use of the autoloader and namespaces to allow drop-n-play addons to hook actions from their isolated directories under addons/[1].

In doing some research on how PHP frameworks handle dispatching, I came across numerous examples of routers and dispatchers [2]. My knowledge of routers comes from the Golang scene, where I use routers as part of the Revel framework for my clients' websites [3]. It seems that many have created router and dispatcher classes for PHP, which I think would be suitable to use in ElkArte.

At the moment, we have a primitive dispatcher which calls a class and method (and includes the files before my changes), based on two GET parameters: action and subaction. However, I think it would be nicer to see a richer router which could pass parameters to action controllers from anywhere in the URL.

This is, of course, not something that should be considered until 2.0. I personally really like the way that Revel handles routing, and I would suggest following suit, but I'm wondering what others' opinions are on this?

Here's an example of what I mean:
Code: [Select]
$router = new Router();

$router->add('GET', '/', '\\ElkArte\\Controllers\\BoardIndex_Controller', 'action_boardindex');
$router->add('GET', '/activate', '\\ElkArte\\Controllers\\Register_Controller', 'action_activate');
$router->add('GET', '/movetopic/:id', '\\ElkArte\\Controllers\\MoveTopic_Controller', 'action_movetopic');
$router->add('POST', '/movetopic', '\\ElkArte\\Controllers\\MoveTopic_Controller', 'action_movetopic2');

// Fallback
$router->add('GET', '/:action', '\\ElkArte\\Controllers\\:action_Controller', 'action_index');
$router->add('GET', '/:action/:sa', '\\ElkArte\\Controllers\\:action_Controller', 'action_:sa');

This would get rid of all the fallback checks we have currently in the dispatcher and smarten everything up. Any path section leading with : is a variable which is passed to the controller, or even used in the discovery of the class and method to call. Then the dispatcher just checks if it's a 'callable' and if not, defaults to /, which in this case is the board index.

By using the correct HTTP methods to detect the type of action, we could do away with all these <action>2 url forms by looking for POST requests.

Addons could then just use the following to add routes with parameters:

Code: [Select]
$router->add('GET', '/page/:id', '\\ElkArte\\Addons\\Pages\\Pages_Controller', 'action_page');

With a router setup like this, we can implement a router method for reversal, to generate URLs from actions. This would be useful for templates/themes, where links are required, making the URL scheme more flexible, and more human-friendly if required [4].

My examples follow the Revel router style, but any format would do. The standardisation and flexibility of a router and dispatcher is the important part. In Elkarte, it might be best to use PHP's built-in regex format.
Last Edit: August 06, 2015, 05:07:58 am by ant59

Re: Router and Dispatcher

Reply #1

you have broken links.

Spoiler (click to show/hide)
Sorry for my English


Re: Router and Dispatcher

Reply #3

 Spuds likes this approach

Re: Router and Dispatcher

Reply #4

This is something I'm happy to go about attempting in a branch on my fork aiming for 1.1 or 2.0. I'm not sure how complex it will become and how many changes will need to be made, but if it's something that everyone else is happy with, I'll give it a go. Should be a more robust approach than the query strings and dispatcher we use now.


Re: Router and Dispatcher

Reply #6

Okay, so here's my plan based on the research I've done on other router implementations.

Routing
  • Admin installs/uninstalls addon, or upgrades Elkarte
  • Routes are discovered and added to a new Router
  • The Router then compiles the routes to a single regex and dumps to a cache file

Dispatching
  • User makes a URI request
  • Dispatcher is created and performs a preg_match on the cached routes regex
  • If it gets a match, it calls the method from the controller as defined and passes any remaining variables named in the route

I read an interesting article comparing different ways of producing the regex: https://nikic.github.io/2014/02/18/Fast-request-routing-using-regular-expressions.html The article suggests that the fastest route matching can be achieved by using dummy groups to count the routes, reducing overhead of indexing in the regex, and by chunking the regex patterns to 10 at a time to prevent quadratic build-up of dummy groups.

I'm going to attempt to implement his suggested "GCB-10C" method.
Last Edit: September 10, 2015, 03:24:06 pm by Spuds

Re: Router and Dispatcher

Reply #7

Thanks for the link to that. Interesting read. Thinking about if/how I can implement it in the BBC, smiley, autolink, and HTML parsers.

Re: Router and Dispatcher

Reply #8

I feel like I'm re-inventing the wheel here and to be honest, I really can't seem to get anything better than what is already offered by libraries on GitHub. Should I just go ahead and grab a routing library and just adapt it for the Elkarte dispatcher?

Re: Router and Dispatcher

Reply #9

I'd just use Silex.


Re: Router and Dispatcher

Reply #11

Sorry for the late reply, I didn't mark it as unread by mistake and I lost it... :-[

Quote from: Ant59 – Should I just go ahead and grab a routing library and just adapt it for the Elkarte dispatcher?
I wouldn't be against. ;D
Bugs creator.
Features destroyer.
Template killer.

Re: Router and Dispatcher

Reply #12

That phroute router looks really cool ... nice job implementing it so far :D