route class
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?
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<?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' ) );
?>
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' ) );
?>
Even de php-tags geplaatst voor de kleurtjes[/modedit]
Gewijzigd op 07/09/2013 17:20:38 door Nick Dijkstra
example.com/controller/function/id
Dat is hetzelfde als je probeert te bereiken met:
/artikel/bewerk/234/
Als je daarmee alleen bij de class /artikel/ uitkomt, mis je dus nog de mapping naar de methode/functie.
Ward, volgens mij snap je niet helemaal wat ik bedoel. Het gaat met namen over de routes die aangemaakt worden.
Goed overzicht van de routing in CodeIgniter en daarin ook de eerste “note”:
http://ellislab.com/codeigniter/user-guide/general/routing.html
Waarom deze Router niet snel gebruikt zou worden in grote applicaties en grote frameworks:
- Je hebt geen collections. Hierdoor kun je bijv. niet een hele groep routes tegelijkertijd een prefix meegeven. Denk bijv. aan een aparte groep voor admin routes, die je dan de '/admin' prefix geeft.
- Je mist het gebruik van requirements. Ik kan bijv. niet aangeven dat :id een getal moet zijn.
- Je mist default values, ik kan niet zeggen dat /:slug standaard de waarde 'home' krijgt.
- De Route object mag echt niet gaan bepalen dat er een controller naam wordt teruggegeven. Dat is de taak van een FrontController of Kernel.
- De manier hoe jij met controllers omgaat vind ik nu nog een beetje vreemd, maar misschien wordt het straks wel mooi.
Het probleem dat mijn router niet doet wat ik wil en nergens goede / mooie voorbeelden kan vinden zorgt er steeds voor dat ik vast loop.
Graag wil ik gebruik maken van het HMVC pattern.
<#id> moet een getal zijn
<:slug> moet een string zijn
Hopelijk kunnen jullie mij de goede richting in duwen.
Ook lees ik dat vele bij het toevoegen van een route een array meesturen met de Contoller, Module en Action.
Bijvoorbeeld:
Code (php)
1
$router->setRoute( new Route( '/artikel/bewerk/:id', array( 'module' => 'article', 'controller' => 'edit', 'action' => 'index' ) ) );
Waarom wordt er gekozen voor een array? Waarom wordt er niet gekozen voor deze manier?
Gewijzigd op 07/09/2013 01:54:37 door Tom Swinkels
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
$routes = array(
'home',
'contact',
'contact/thanks'
);
$uri = $_SERVER['PATH_INFO'];
$uri = strtolower($uri);
$uri = substr($uri, 1);
if(array_search($uri , $routes))
echo $uri;
else
echo 'not found';
?>
$routes = array(
'home',
'contact',
'contact/thanks'
);
$uri = $_SERVER['PATH_INFO'];
$uri = strtolower($uri);
$uri = substr($uri, 1);
if(array_search($uri , $routes))
echo $uri;
else
echo 'not found';
?>
Iemand anders die er even een oog op wil werpen?
@Tom: waarom er voor een array wordt gekozen? Stel dat de routes uit een configuratiebestand komen (wat heel gebruikelijk is) dan kun je ze via een foreach-loop gemakkelijk inladen. Dan krijg je zoiets als:
Code (php)
1
2
3
4
5
2
3
4
5
<?php
foreach ($routes as $route) {
$router->setRoute(new Route($route['url'], $route['parameters']));
}
?>
foreach ($routes as $route) {
$router->setRoute(new Route($route['url'], $route['parameters']));
}
?>
Tom Swinkels op 22/02/2013 23:03:53:
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?
Dat is waar ik een oplossing op gaf dat natuurlijk verder uitgewerkt kan worden.
Met een array kun je in één keer een compleet verhaal vertellen. Met losse strings blijft het bij die ene instructie.
En voor het antwoord op je vraag, die heb ik al lang beantwoord: "Of je maakt gebruik van ^ en $ in je regex, waardoor je dat probleem niet meer hebt."
Ward van der Put op 07/09/2013 15:40:44:
Met een array kun je in één keer een compleet verhaal vertellen. Met losse strings blijft het bij die ene instructie.
Ward, is toch ook een kwestie van persoonlijke voorkeur?
Je zou een nieuwe user zo kunnen aanmaken:
$user = new User('Piet', 'Amsterdam', 35);
Of zo:
$user_info = array('Piet', 'Amsterdam', 35);
$user = new User($user_info);
Alleen als de informatie niet hard-coded is (wat meestal het geval is), en bijv. uit een configuratiebestand, formulier of database komt, dan lijkt me de laatste optie handiger.
Gewijzigd op 07/09/2013 17:02:55 door Ozzie PHP
Omdat we alleen de waarden noemen maar niet de eigenschappen, kunnen we nooit meer een 35-jarige Piet met voorlopig onbekende woonplaats verwerken:
Tweede punt is dat we zonder array niet Piet én zijn hele voetbalclub in één keer kunnen toevoegen. Nee, zonder array moeten we Piet, Jan, Joris, Corneel allemaal één voor één toevoegen.
Gewijzigd op 07/09/2013 17:24:38 door Ward van der Put
Wat is vooral is in dit voorbeeld: Wie zegt dat die route aan een controller wordt gekoppeld? Dat is helemaal niet de taak van de Routing, dat moet iets als een ControllerResolver of FrontController doen. Omdat dat niet de taak is van Routing moet je in routing ook geen specifieke argumenten maken voor deze dingen.
Een voetbalelftal toevoegen zou je inderdaad in een array doen... maar heeft niks met een user object te maken uiteraard. Maar wat zou dan de stelregel moeten zijn? Alles wat bij elkaar hoort (wat toebehoort aan 1 persoon of ding) in een array stoppen?
Ik denk dat je bij een route altijd een controller, action en model nodig hebt?
Maar ik snap jullie reacties, de vraag is alleen of dat hier voor komt?
Mijn voorkeur gaat altijd naar setters, omdat je dan namelijk weet wat er in die setter thuis hoort.
Wanneer je dus alles direct in de construct gooit, kan het zijn dat je soms niet meer weer welke volgorde e.t.c
- wanneer je iets instelt wat vaak hetzelfde is, gewoon echt de configuratie, gebruik je arrays
- anders gebruik je gewoon setters
- geef iets mee aan de constructor wanneer het nodig is voor de klasse om te werken. Een newsletter kan bijv. best werken zonder mailer, want je kan de nieuwsbrief ook als concept opslaan. Echter een router kan niet zonder routes en de request uri, die voeg je dus mee aan de constructor.
Tevens komen er in php 5.6 waarschijnlijk named arguments. Welke het probleem hierboven met het weglaten van de plaats een stuk makkelijker maakt:
Tevens zou ik nooit false durven gebruiken als ik geen waarde wil opgeven voor een string. Liever null, of nog beter een lege string.
"Tevens zou ik nooit false durven gebruiken als ik geen waarde wil opgeven voor een string. Liever null, of nog beter een lege string."
Klopt. Was ook maar even snel een voorbeeldje. Ik zou in dit geval voor null gaan.
maart/juni/juli 2014