MVC friendly urls
Ik ben bezig met het bouwen van een eigen MVC. Nu heb ik een URL /user/edit/2, waarin user de controller is, edit de method en 2 de property of in dit geval het id van de user die we gaan wijzigen. Stel ik heb een URL /news/view/6, waarvan news de controller is, view de method en 6 de id van het nieuwsitem dat we willen laten zien. Hoe kan ik er dan voor zorgen dat de nette URL wordt /nieuws/titel-van-het-nieuwsitem?
Tegenwoordig gebruikt men Routing configuratie bestanden. Op die manier kun je je URL (route) compleet anders doen dan je controller. Een voorbeeldje van Symfony2:
Code (php)
1
2
3
2
3
blog_show:
path: /nieuws/{slug}
defaults: { _controller: AcmeBlogBundle:Blog:showOne }
path: /nieuws/{slug}
defaults: { _controller: AcmeBlogBundle:Blog:showOne }
Dit stelt in dat de url /nieuws/{slug} ({slug} is hier een placeholder, het krijgt de waarde van wat er op die plek in de URL staat) wordt afgehandeld door de Acme\BlogBundle\Controller\BlogController#showOneAction controller. Deze controller heeft dan een parameter die $slug heet, die krijgt dan automatisch de waarde van {slug} in de URL.
Ik begrijp je nog niet helemaal.
Ik heb je een voorbeeld gegeven :) Wat begrijp je er dan niet aan, dan kunnen we wat doelgerichter uitleggen. Ik bedoel, ik kan je wel het complete Routing systeem van Symfony of Laravel gaan uitleggen, maar dan begrijp je denk ik nog minder...
Path is het gedeelte in de url achter de domeinnaam waarbij {slug} variabel is. In Wouter zijn voorbeeld de slug (Titel in URL geldige karakters) van een nieuwsartikel.
Mogelijke url's zijn dan:
Code (php)
1
2
3
4
2
3
4
http://jouwdomijn.nl/nieuws/client-fingerprint
http://jouwdomijn.nl/nieuws/ideen-project-website
http://jouwdomijn.nl/nieuws/mvc-friendly-urls
....
http://jouwdomijn.nl/nieuws/ideen-project-website
http://jouwdomijn.nl/nieuws/mvc-friendly-urls
....
Dan zie je de controller die aangeroepen wordt waarbij het eerste gedeelte naar een Bundle (directory / gedeelte) wijst. het tweede gedeelte is de naam van de controller. (Blog wordt class BlogController) en de derde is de action ofwel de functie die aangeroepen wordt van de class.
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
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
<?php
namespace Acme\BlogBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class BlogController extends Controller
{
public function indexAction()
{
// ....
}
public function showOneAction($slug)
{
$item = $this->getDoctrine()
->getRepository('AcmeBlogBundle:Newsitem')
->findOneBy(array('slug' => $slug));
$data = array(
'newsitem' => $item,
);
return $this->render('BlogBundle:Blog:showOne.html.twig', $data);
}
}
?>
namespace Acme\BlogBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class BlogController extends Controller
{
public function indexAction()
{
// ....
}
public function showOneAction($slug)
{
$item = $this->getDoctrine()
->getRepository('AcmeBlogBundle:Newsitem')
->findOneBy(array('slug' => $slug));
$data = array(
'newsitem' => $item,
);
return $this->render('BlogBundle:Blog:showOne.html.twig', $data);
}
}
?>
Gewijzigd op 31/03/2014 13:38:20 door Frank Nietbelangrijk
Aah oke, ik begin het een beetje te begrijpen. Met een Routing class kan ik dus bepalen welke controller bij welke URL hoort? Hoe ziet zo'n Routing configuratie er dan uit?
Gewijzigd op 01/04/2014 20:02:39 door Roy B
1. Haal informatie uit $_SERVER en herleid het gedeelte achter de naam van de frontcontroler
moet worden:
2. explode het resultaat op de '/'. Je krijgt dan een array:
3. nu ga je met een foreach stap voor stap alle routes af. die explode je ook op dezelfde manier.
Daarna laat je voor iedere route een vergelijkfunctie aanroepen die de arrays gaat vergelijken:
Code (php)
4. de vergelijkfunctie:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
public function compare($routeArray , $urlArray)
{
// als eerste als de arrays geen gelijk aantal elementen hebben dan is er iig geen match
if(count($routeArray) != count($urlArray)
return false;
// daarna vergelijken we element voor element uit beiden arrays. bij een variabele ( {slug} ) is er altijd een match
for($i = 0 ; $i < count($routeArray) ; $i++)
if($routeArray[$i] != $urlArray[$i] && $routeArray[$i][0] != '{')
return false;
return true;
}
?>
public function compare($routeArray , $urlArray)
{
// als eerste als de arrays geen gelijk aantal elementen hebben dan is er iig geen match
if(count($routeArray) != count($urlArray)
return false;
// daarna vergelijken we element voor element uit beiden arrays. bij een variabele ( {slug} ) is er altijd een match
for($i = 0 ; $i < count($routeArray) ; $i++)
if($routeArray[$i] != $urlArray[$i] && $routeArray[$i][0] != '{')
return false;
return true;
}
?>
5. als er dan een geldige route gevonden is kun je $route['controller'] uitlezen en de juiste controller aanroepen. Dit gebeurt in een paar stappen:
Code (php)
1
2
3
4
2
3
4
1. variabelen uit de URL halen: $var[] = 'titel-van-het-nieuwsitem'; // in werkelijkheid heb je hier ook een functie voor nodig
2. BlogController.php includen. (Liefst met een autoloader)
3. BlogContoller class instantiren: $controller = new BlogController();
4. de juiste method aanroepen: $controller->showOneAction($var[0]);
2. BlogController.php includen. (Liefst met een autoloader)
3. BlogContoller class instantiren: $controller = new BlogController();
4. de juiste method aanroepen: $controller->showOneAction($var[0]);
Toevoeging op 01/04/2014 21:32:53:
Zoals je zult merken is het al bij al nog niet zo eenvoudig. Zoals vaker wordt opgemerkt op dit board:
Ga liever gewoon aan de slag met een goed framework als Symfony of Zend.
Neemt niet weg dat het maken van een eigen framework erg leerzaam is en je ook helpt bij het begrijpen wat een framework doet. Maar een echt serieus project begin je pas met Symfony of Zend naar mijn mening.
Gewijzigd op 01/04/2014 21:20:42 door Frank Nietbelangrijk
Het is sowieso altijd goed om met een framework te beginnen. Of je dan daarna je eigen framework gaat maken maakt mij niet zoveel uit, maar je hebt nu nog niet eens door wat een framework hoort te doen en je bent nog niet thuis in de begrippen en -veel belangrijker- OO principes. Leer eerst goed hoe alles werkt van een framework (kan ook Laravel zijn, die komt waarschijnlijk dichter bij je toekomstige framework in de buurt) en ga dan pas nadenken over het zelf beginnen.