Door
Tom Swinkels
op 22-02-2013 23:03
gewijzigd op 07-09-2013 17:20
6.848 views
Beste Developers,
Ik zie vaak allemaal ingewikkelde routers tegen komen op internet.
Na even te zoeken kwam ik een vrij simpele router tegen hier op PHPHulp.
Wat is de reden van een uitgebreide moeilijke router? Na mijn mening is dit toch prima?
Enige probleem dat ik nu nog heb, is dat wanneer ik nu naar /artikel/bewerk/234/ dat hij de route /artikel/ pakt, hoe kan ik dit op de beste manier oplossen? Alles een prioriteit meegeven, sorteren op langste route? Wat is de beste manier hiervoor? Of gewoon een kwestie van de routes aanmaken in de goede volgorde?
<?php
class Router
{
private $_routes;
public function __construct()
{
$this->_routes = array();
}
public function setRoute( Route $route )
{
$this->_routes[] = $route;
}
public function match( $query )
{
$routes = $this->_routes;
if( $routes )
{
foreach( $routes as $route )
{
$match = $route->match( $query );
if( $match )
{
return $match;
}
}
}
return false;
}
}
class Route
{
private $_regex;
private $_controller;
public function __construct( $pattern, $controller )
{
$this->_regex = preg_replace( '#:([a-z])+#','(?P<$1>[^/]+)', $pattern );
$this->_controller = $controller;
}
public function match( $query )
{
if( !preg_match( '#'.$this->_regex.'#', $query, $matches ) )
{
return false;
}
$controller = new Controller();
$controller->setName( $this->_controller );
return $controller;
}
}
class Controller
{
private $_name;
public function setName( $name )
{
$this->_name = $name;
}
public function getName()
{
return $this->_name;
}
}
$router = new Router();
$router->setRoute( new Route( '/artikel/', 'article.view.module') );
$router->setRoute( new Route( '/artikel/bewerk/:id', 'article.edit.module') );
$router->setRoute( new Route( '/artikel/verwijder/:id', 'article.delete.module') );
$controller = $router->match( $request->server( 'REDIRECT_URL' ) );
?>
De routes toevoegen wordt natuurlijk in een configuratie bestand gezet. Andere punten:
- de router heeft niks van doen met het koppelen van een route aan een controller, dit moet de front controller of een controller resolver doen.
- regel 22 van de router is nodeloos geheugen verspilling
- gebruik liever count om te kijken of er routes zijn
- een method addRoute beschrijft de functie beter
- gebruik in het geval van ids natuurlijk wel <#id>
- geen routes om in te zoeken zou ik opvatten als een fout
- Ik return enkel de data, en in de FrontController roep ik de nieuwe controllers aan bedoel je?
- Regel 22?
- Waarom zou je dat met count kijken?
- Dit had ik nog niet aangepast.
- Wat bedoel je met geen routes om in te zoeken?
Hoe zou jij een default route afhandelen / toevoegen?
Verder geeft het bovenstaande stuk matches op alles.
- Nee, je retourneert gewoon de hele route en laat de front controller lekker uitzoeken wat hij daarna met die route wil doen, dat gaat de router niks aan.
- Ja, regel 22:
[code s=19]<?php
public function getRoute( $query )
{
$routes = $this->_routes;
?>[/code]
- Omdat je een array hebt en geen boolean value. Gewoon een kwestie van netjes scripten. Zoals ik altijd zeg "PHP is awesome because it's noobproof, a PHP developer is awesome if he doesn't use those noobproof-features".
- Nou, stel $this->_routes is leeg, dan zou ik een exceptiontje gooien
- Ok, maar wie roept de router aan? Aangezien de routes uit de config komen?
- Welke array bedoel je? Het is toch logies om alle routes in een array te gooien?
Ik bedoel wanneer er geen route is opgegeven, bijvoorbeeld www.site.nl hoe bepaal ik welke route er dan standaard wordt uitgevoerd?
- De frontcontroller roept de router aan. Routes uit config kun je erg simpel doen met:
[code file=routes.php]<?php
$router->addRoute(new Route(...));
// ...
?>[/code]
[code file=frontcontroller.php]<?php
class FrontController
{
public function terminate(...)
{
// ...
Zelf gebruik ik een aparte compiler voor het maken van de reguliere expressie en een matcher die de goede route zoekt bij de url
Naar mijn mening is zo'n route class die je als voorbeeld stelt genoeg voor kleine applicaties. Echter als je zoals Symfony ook vette dingen wilt doen als url's genereren per route bijvoorbeeld, dan moet je wat extra code toevoegen