Effectivement, mais il y a une petite subtilité, on va essayer d'orienter ça sur la norme REST, tu en a déjà entendu parler?
C'est les api ça non?
Oui, il y a certaines api qui sont basées sur l'architecture REST, ce n'est pas ce que l'on va faire aujourd'hui, mais on va s'en inspirer. Le concept est assez simple, on se base sur les méthodes http pour identifier le type d'action à réaliser. De base il peut y avoir quatre types d'actions :
- La lecture
- L'écriture
- La modification
- La supression
C'est le CRUD, j'ai déjà vu ça !
Oui en effet c'est le CRUD, les quatres actions de bases, Create, Read, Update, Delete. Mais sais tu qu'il y a une méthode http pour chacune de ces actions?
Non je ne connais que GET et POST
Et bien sache qu'il y a beaucoup de méthodes Http
Dans notre cas, nous allons utiliser :
- GET pour la lecture
- POST pour l'écriture
- PUT pour la modification
- DELETE pour la supression
Un petit détail qui a son importance tout de même, généralement GET tout comme DELETE vont passer leur paramètre via l'url, alors que POST et PUT passeront leur paramètre dans le body de la requête avec un formData.
Je ne vois pas où tu veux en venir...
Je te reformule ça, les paramètres de GET et DELETE se retrouveront dans l'url, avec l'utilisation d'un preg_match on devrait pouvoir trouver les valeurs, alors qu'il seront, pour POST et PUT dans la variable $_POST
Dans un premier temps, tu va ajouter des paramètres dans la route Login en POST, je te laisse choisir leur noms et format.
{"language":"application/json","content":"[{\n\t\"path\" : \"/\",\n\t\"controller\" : \"Home\",\n\t\"action\" : \"Home\",\n\t\"method\" : \"GET\",\n\t\"param\" : []\n},\n{\n\t\"path\" : \"/Login\",\n\t\"controller\" : \"Home\",\n\t\"action\" : \"Login\",\n\t\"method\" : \"GET\",\n\t\"param\" : []\n},\n{\n\t\"path\" : \"/Login\",\n\t\"controller\" : \"Home\",\n\t\"action\" : \"Authenticate\",\n\t\"method\" : \"POST\",\n\t\"param\" : [\n\t\t\"login\",\n\t\t\"password\"\n\t]\n}]","filename":"route.json"}
Parfait, je te propose que l'on ajoute une méthode dans notre httpRequest, le but étant de parcourir les paramètres définit dans la route trouvée, et de vérifier s'ils ont été passés lors de la requête. Si c'est le cas, on les assigne à la propriété $_param de notre HttpRequest, avec les clés et valeurs !
Mais on ne peut pas prendre tout les $_GET et $_POST et les passer tout simplement?
On pourrait, mais le but ici est de sécuriser notre application, une route attend un nombre précis de paramètres nommés, et en les filtrant on ne traitera que ceux là avant de les envoyer au contrôleur. Ce n'est pas la sécurité ultime, mais ça peut déjà limiter les problèmes d'injection XSS.
En plus de ça, on veux faire des url user-friendly, donc au lieu d'utiliser des paramètres GET, on va décomposer une url selon un format préciser dans le path de la route grace à un preg_match.
Ahhhh je comprend
Je te propose que l'on nomme cette méthode bindParam
Oui ça me va, par contre je doit faire un if pour chaque méthode Http possible?
On pourrais le faire comme ça, mais un switch aurait un net avantage pour le coup, tu n'as probablement jamais vu ça, mais tu peux définir plusieurs case de suite dans un switch qui ont un code en commun, par exemple :
{"language":"application/x-httpd-php","content":"<?php\n\tswitch($string)\n\t{\n\t\tcase \"chaine1\":\n\t\tcase \"chaine2\":\n\t\t\techo \"La chaine 1 ou la chaine 2 ont été trouvée\";\n\t\t\tbreak;\n\t\tcase \"chaine3\":\n\t\t\techo \"La chaine 3 a été trouvée\";\n\t\t\tbreak;\n\t}","filename":"exemple"}
On peut faire ça?!?
Oui tout à fait.
Ok je comprend pourquoi ce sera plus pratique qu'avec des if. Je me lance.
{"language":"application/x-httpd-php","content":"<?php\n\tclass HttpRequest\n\t{\n\t\tprivate $_url;\n\t\tprivate $_method;\n\t\tprivate $_param;\n\t\tprivate $_route;\n\t\t\n\t\tpublic function __construct()\n\t\t{\n\t\t\t$this->_url = $_SERVER['REQUEST_URI'];\n\t\t\t$this->_method = $_SERVER['REQUEST_METHOD'];\n\t\t}\n\t\t\n\t\tpublic function getUrl()\n\t\t{\n\t\t\treturn $this->_url;\t\n\t\t}\n\t\t\n\t\tpublic function getMethod()\n\t\t{\n\t\t\treturn $this->_method;\t\n\t\t}\n\t\t\n\t\tpublic function getParams()\n\t\t{\n\t\t\treturn $this->_params;\t\n\t\t}\n\t\t\n\t\tpublic function setRoute($route)\n\t\t{\n\t\t\t$this->_route = $route;\t\n\t\t}\n\t\t\n\t\tpublic function bindParam()\n\t\t{\n\t\t\tswitch($this->_method)\n\t\t\t{\n\t\t\t\tcase \"GET\":\n\t\t\t\tcase \"DELETE\":\n\t\t\t\t\t\t$this->param[] = preg_match(\"#\" . $this->_route . \"#\",$this->_url);\n\t\t\t\tcase \"POST\":\n\t\t\t\tcase \"PUT\":\n\t\t\t\t\tforeach($this->_route->getParam() as $param)\n\t\t\t\t\t{\n\t\t\t\t\t\t$this->_param[] = $param;\n\t\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}","filename":"HttpRequest.php"}
Je pense que quelque chose m’échappe...
Je te confirme, plusieurs détails t'ont échappé. Le switch est très bien comme ça, on n'y retouchera pas.
Par contre, je te rappelle que pour le POST et PUT le but est de vérifier dans ta boucle, si pour chaque $param, la variable $_POST[$param] existe, et si oui, on l'assigne à la propriété param de notre HttpRequest.
Et pour bien l'assigner, il faudrait que cette propriété param soit dans un premier temps un tableau.
Ah il faut que je l'initialise dans le constructeur.
Du côté du GET et DELETE, il faut effectivement utiliser preg_match, mais tel quel il retourne 0 s'il n'a rien trouvé, et 1 s'il a trouvé quelque chose. ça ne va pas être pratique de mette 0 ou 1 dans les paramètres. Tu peux ajouter un troisième paramètre à preg_match qui contiendra le résultat des parenthèses capturantes de la regex.
Par exemple :
{"language":"application/x-httpd-php","content":"<?php\n\t$url= \"/route/5\";\n\tif(preg_match(\"#/route/([0-9]*)#\",$url,$matches))\n\t{\n\t\tvar_dump($matches);\n\t}","filename":"exemple"}
ce code va afficher :
array(2) {
[0]=>
string(8) "/route/5"
[1]=>
string(1) "5"
}
[0]=>
string(8) "/route/5"
[1]=>
string(1) "5"
}
La case 0 correspond toujours à l'expression complete qui a été trouvée. A partir de la case 1 il s'agit des parenthèse capturantes dans l'ordre dans lequel elles sont présentes dans la regex. Dans notre cas il n'y en a qu'une seule ([0-9]*) qui correspond au 5 de l'url.
Il faudra donc faire une boucle dans ce tableau de résultat, en ignorant la case 0, pour l'ajouter aux param.
{"language":"application/x-httpd-php","content":"<?php\n\tclass HttpRequest\n\t{\n\t\tprivate $_url;\n\t\tprivate $_method;\n\t\tprivate $_param;\n\t\tprivate $_route;\n\t\t\n\t\tpublic function __construct()\n\t\t{\n\t\t\t$this->_url = $_SERVER['REQUEST_URI'];\n\t\t\t$this->_method = $_SERVER['REQUEST_METHOD'];\n\t\t\t$this->_param = array();\n\t\t}\n\t\t\n\t\tpublic function getUrl()\n\t\t{\n\t\t\treturn $this->_url;\t\n\t\t}\n\t\t\n\t\tpublic function getMethod()\n\t\t{\n\t\t\treturn $this->_method;\t\n\t\t}\n\t\t\n\t\tpublic function getParams()\n\t\t{\n\t\t\treturn $this->_params;\t\n\t\t}\n\t\t\n\t\tpublic function setRoute($route)\n\t\t{\n\t\t\t$this->_route = $route;\t\n\t\t}\n\t\t\n\t\tpublic function bindParam()\n\t\t{\n\t\t\tswitch($this->_method)\n\t\t\t{\n\t\t\t\tcase \"GET\":\n\t\t\t\tcase \"DELETE\":\n\t\t\t\t\tif(preg_match(\"#\" . $this->_route->path . \"#\",$this->_url,$matches))\n\t\t\t\t\t{\n\t\t\t\t\t\tfor($i=1;$i<count($matches)-1;$i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$this->_param[] = $matches[$i];\t\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\tcase \"POST\":\n\t\t\t\tcase \"PUT\":\n\t\t\t\t\tforeach($this->_route->getParam() as $param)\n\t\t\t\t\t{\n\t\t\t\t\t\tif(isset($_POST[$param]))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$this->_param[] = $_POST[$param];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}","filename":"HttpRequest.php"}
C'est bien mieux comme ça ! On a terminé pour cette partie. Maintenant on va faire un contrôleur de base.
J'ai terminé cette partie