views:

4427

answers:

13

I'm looking for the simplest implementation of a routing framework in PHP, in a typical PHP environment (Running on Apache, or maybe nginx) ..

It's the implementation itself I'm mostly interested in, and how you'd accomplish it.

I'm thinking it should handle URL's, with the minimal rewriting possible, (is it really a good idea, to have the same entrypoint for all dynamic requests?!), and it should not mess with the querystring, so I should still be able to fetch GET params with $_GET['var'] as you'd usually do..

So far I have only come across .htaccess solutions that puts everything through an index.php, which is sort of okay. Not sure if there are other ways of doing it.

How would you "attach" what URL's fit to what controllers, and the relation between them? I've seen different styles.

One huge array, with regular expressions and other stuff to contain the mapping.

The one I think I like the best is where each controller declares what map it has, and thereby, you won't have one huge "global" map, but a lot of small ones, each neatly separated.

So you'd have something like:

class Root {
    public $map = array(
        'startpage' => 'ControllerStartPage'
        );
}

class ControllerStartPage {
    public $map = array(
        'welcome' => 'WelcomeControllerPage'
        );
}

// Etc ...

Where:

'http://myapp/' // maps to the Root class
'http://myapp/startpage' // maps to the ControllerStartPage class
'http://myapp/startpage/welcome' // maps to the WelcomeControllerPage class
'http://myapp/startpage/?hello=world' // Should of course have $_GET['hello'] == 'world'

What do you think? Do you use anything yourself, or have any ideas?

I'm not interested in huge frameworks already solving this problem, but the smallest possible implementation you could think of. I'm having a hard time coming up with a solution satisfying enough, for my own taste.

There must be something pleasing out there that handles a sane bootstrapping process of a PHP application without trying to pull a big magic hat over your head, and force you to use "their way", or the highway! ;)

+1  A: 

I personally really like having an index.php everything goes through, so my current setup is more or less routing any requests to my index.php, where I first check if the 'default' setup has been changed through a $routes array, otherwise I look for /controllers/{$controller}.php and call the function $page, in addition to your usual callbacks.

Paolo Bergantino
+1  A: 

I haven't seen a solution that doesn't rewrite all URLs through a single script. You can check some of the minimal frameworks out there (PHP or not):

1) Nice dog (PHP)

http://tiago.zusee.com/code/nicedog/

2) web.py (python)

http://webpy.org/

URL handling: http://webpy.org/tutorial2.en

daremon
I found out about Nice Dog here. I modified it slightly: http://github.com/daveroberts/happypuppy/tree/master
Dave
A: 

I've used something similar to what you are saying with a few differences.

First, I didn't store the mapping in a class but in an array. Something like:

$map = array(
    'startpage' => 'mystartpage',
    'welcome' => array('WelcomeClass', 'welcome_page'),
);

Then I used call_user_func_array to send in either the function (like mystartpage),or a class with a method (like array('WelcomeClass', 'welcome_page')). You could, also, detect the array as a class, build the object, and call the method.

This is one of those problems that has many possible solutions.

Matt Farina
+2  A: 

Check out Zend Framework which has a pretty simple routing system (and it's especially simple if you use the standard app/controller/action setup.

It allows you to auto-setup URLs that map directly to MVC controllers and their actions, like: http://example.com/controller/action/param1/value1/param2/value2/...

In that case, all code is routed through an index.php bootstrap and it's really easy to add custom routes there.

Jough Dempsey
+1  A: 

After searching for a simple tutorial that I could use to build my own custom solution, I found this article by Chris Corbyn to be the most helpful: http://w3style.co.uk/a-lightweight-and-flexible-front-controller-for-php-5

Alternatively, I know that you indicated that you're not inclined to use a large framework for your front controller but you might consider looking at Zend Framework as it offers a highly extensible take it or leave style of architecture. You can extend any of their existing classes and you can choose to use just the front-end controller and leave everything else behind.

Noah Goodrich
+1  A: 

Why reinvent the wheel?

Symfony has a great routing framework built-in.

See the symfony book for more info:
Chapter 9 - Links And The Routing System

andyuk
A: 

I quite like CodeIgniter. It, too, uses the "route everything through index.php" pattern - but I don't think there's anything necessarily wrong with that.

It's very easy to learn and quite fast and intuitive. It also has a lot of other helper classes such as form validation.

If you're looking for something more lightweight than the Zend Framework (as someone else mentioned) this could be good for you.

Phill Sacre
Yes, CodeIgniter is very nice. I use it myself, but I'm not sure this is what the OP wanted.
Christian Davén
+3  A: 

While I could second the recommendations to the Zend Framework and CodeIgniter, you don't have to throw a framework at it, just use the Net_URL_Mapper.

There is a pretty comprehensive example on the package's proposal which illustrates how easy it is to use Net_URL_Mapper: http://pear.php.net/pepr/pepr-proposal-show.php?id=428

Till
+28  A: 

As far as I know, there are basically three types of dispatching patterns around. We can call them page controller, front controller, and hierarchical controller -- each with increasing levels of abstraction. They go a little like this:

Page controller

The web server has multiple files. Eg. there may be a users.php and comments.phpetc. URL's to the system would reflect this as http://example.org/users.php?user_id=42. For PHP, this is the native scheme.

Page controller works very well for simple sites, because it strongly couples controller with view. This is also its weakness.

Front controller

All requests go through a global mapping mechanism, and is then delegated to a handler. In its most basic incarnation, you can simply take a page controller design and bolt some mod_rewrite rules on top of it. Other implementations involved routing everything to index.php, and then do the mapping in PHP-code instead. A handler will then often have the form of a class, rather thsan a file.

The main motivation for front controller is to get URL's that are more meaningful. Some say pretty. You would typically have something like http://example.org/users/42.

Hierarchical controller

This design extends front controller. Instead of having a single, global mapping, the first controller only maps the first node in the path element of the URL. It then delegates to a handler (Just like the front controller does), but this handler will again map the next node and dispatch. This continues for as many times as there are nodes in the path.

Because the mapping isn't global, but relative, it's easier to reuse handlers in a hierarchical controller design, than in a front controller one.

...

To my experience, page controller is largely being replaced by front controller, usually under the catchy name of MVC framework (Even though that's a confusing mixup of concepts). Meaningful URL's seems to be the visible benefit that drives this change, but there are more subtle benefits, in terms of maintainability. There's also a slight cost in complexity, so for smaller projects, and projects where the developers level of education is low, page controller still prevails.

Hierarchical controllers are rare. There is a library called Konstrukt (Which the examples in this question suggests that you're already familiar with), and I have seen a few other projects come and go, using the same design. Konstrukt isn't overly popular, which is probably because the gain over a front controller is rather abstract. It's also slightly more abstract, than front controller, so there is a price in terms of complexity.

Note that I'm biased in that I'm the main author of Konstrukt.

troelskn
Yeah, i know konstrukt. It's the framework of my choice at the moment, but i still find it unfinished in some areas. Not really able to pinpoint exactly what, but it has some warts, and i've seen k2 is under development -- so .. looking forward to what kind of magic you can produce with that :)
David
david you sound like a complete buzz-word-hungry-nub-padawan
A: 

You could easily execute the right function on the associative class using reflection. I would suggest using a /controller/action structure. Something I made myself a few days back.

class Dispatcher {
    function run($controller, $action) {
        if(file_exists("Controller". $controller .".php") {
            require_once("Controller". $controller .".php");
            $controller = new "Controller". $controller();
            if(method_exists($controller,$action)) {
                return $controller->$aciton();
            }

        }

    }
}

class ControllerStartPage {
    public function welcome() {

    }
}
Johnny
"file_excists" is not going to do what you want.
Adriano Varoli Piazza
+2  A: 

Just for completeness, I'm a fan of Kohana (http://kohanaphp.com/) which is based on CodeIgniter but pure PHP5.

James Socol
+3  A: 

LightVC is a simple PHP implementation of the VC parts of the MVC pattern. It handles mapping requests to views + controllers without really saying much about what you do inside your own code.

Sean McSomething
A: 

try this one: dphpb.com

simple step by step tutorial with sample code

Tom