Bonjour à tous.
J'avais commencé le tutoriel Développer un site de A à Z (Modèle MVC) il y à moment, puis j'ai arrêté, je m'y suis remis, et j'ai un problème comme vous l'auriez deviné.
Lorsqu'une requête doit être du type /Controller/Action/Param ,
par exemple : /blog/edit/1 (Pour éditer l'article d'id 1)
et que la personne fait la requête de cette forme /Controller/Action
par exemple : /blog/edit
Alors le paramètre $id est manquant lors de l'appel de la méthode edit() dans la classe Blog.
Warning: Missing argument 1 for Blog::edit() in C:\wamp\www\framework\admin\controller\blog.php on line 23
J'ai réussis à faire mon FrameWork MVC sans aucun problème, tout le reste marche parfaitement bien, en cas de Controller ou d'Action non-existante, alors l'utilisateur est redirigé sur la page d'erreur 404 sans problème.
Mais si c'est un Param qui est manquant alors ça m'affiche une série d'erreur.
Ce que j'aimerais donc c'est de pouvoir corriger ça, par exemple en vérifiant si le paramètre est manquant. et si il est manquant alors on déclenche une erreur, au lieu de charger le Controller et l'Action.
Une idée ? =D
Merci d'avance.
Après un an, presque jour pour jour ^^
J'ai trouvé la solution à mon problème.
De base voilà comment fait Grafikart dans son tuto; depuis le dispatcher il appelle l'action du controller de cette manière
if(!in_array($this->request->action, array_diff(get_class_methods($controller), get_class_methods('Controller')))) {
$this->error('Erreur, méthode non trouvée...');
}
else {
call_user_func_array(array($controller, $this->request->action, $this->request->params);
$controller->render($this->request->action);
}
Et voilà ce que je vous propose
$class = $controller;
$method = $this->request->action;
$params = $this->request->params;
// On récupère les actions du controller
$classMethods = array_diff(
get_class_methods($class),
get_class_methods(get_parent_class($class))
);
// Si la méthode correspondante existe on l'appelle
if(in_array($method, $classMethods)) {
// On récupère le prototype de la méthode
$prototype = new ReflectionMethod($class, $method);
// Si on fournit assez d'argument à la méthode on l'appelle
if(count($params) >= $prototype->getNumberOfRequiredParameters()) {
// Ce switch rend l'appel de l'action du controller plus rapide qu'un simple "call_user_func_array()"
// dans le cas ou le nombre de paramètres est inférieur à 6 (Ce qui est souvent le cas)
switch(count($params)) {
case 0:
$class->{$method}();
case 1:
$class->{$method}($params[0]);
case 2:
$class->{$method}($params[0], $params[1]);
case 3:
$class->{$method}($params[0], $params[1], $params[2]);
case 4:
$class->{$method}($params[0], $params[1], $params[2], $params[3]);
case 5:
$class->{$method}($params[0], $params[1], $params[2], $params[3], $params[4]);
default:
call_user_func_array(array($class, $method), $params);
break;
}
// Et pour finir on rend l'action
$controller->render($this->request->action);
}
// Sinon on déclenche une erreur (nombre d'argument insuffisant)
else {
$this->error('Erreur, nombre de paramètre passé insuffisant...');
}
}
// Sinon on déclenche une erreur (la méthode n'existe pas)
else {
$this->error('Erreur, méthode non trouvée...');
}
Cette structure à 3 avantages, le premier est que si une action d'un contrôleur est appelée avec un nombre insuffisant d'argument, alors le dispatcher déclenche une erreur; ce qui vous évites dans vos contrôleur de préciser que tout les paramètres sont optionnels et de déclencher une erreur dans le contrôleur si ils en manquent.
Et l'appel de l'action sera aussi plus rapide qu'un call_user_func_array() dans le cas ou il y à moins de 6 arguments passés à la méthode (Grâce au switch); et c'est très rare d'avoir 6 ou + de 6 arguments.
Et dernier avantage, je trouve ce bout de code beaucoup plus lisible et compréhensible que celui de Grafikart, bien que plus long.
Oui, voilà
function edit($id) {
$r'conditions']'id'] = $id;
$this->request->data = $this->query->findFirst($r);
$this->request->relation_category = $this->query->findRelation('post','category',$r);
$this->request->relation_theme = $this->query->findRelation('post','theme',$r);
$this->request->relation_term = $this->query->findRelation('post','term',$r);
$d'page_title'] = "Edition d'un article";
$d'current_page'] = 'post';
$this->set($d);
if(empty($this->request->data)) {
$this->error404();
}
}
Oui j'y ai pensé, ça réglerait mon problème seulement, je n'ai pas qu'une fonction dans ce cas là, mais beaucoup plus, toutes ces fonctions passent dans mon dispatcher, donc j'aurais voulu savoir si depuis ailleurs (depuis mon dispatcher), je peux savoir si une fonction dont je connais le nom requière des arguments, comme ça si il en manque j'appelle directement error404(); avant même d'appeler ma fonction.
Sa permettrait d'appliquer ce problème pour chaque méthode, et d'éviter des affichages d'erreur pour les personnes qui passe par là si j'ai oublié un $id = null quelque part, et également un petit gain de performance.
Dans son tutoriel Grafikart ne résout pas se problème il me semble ? Ce qui fait qu'en le suivant scrupuleusement, à la fin on se retrouve avec une erreur, si une personne s’amuse à retirer le paramètre passer dans un lien de la forme /Controller/Action/Param.
Je me dis donc que, peut être que Grafikart, qui n'as pas ce problème à une solution, autre que de mettre des null pour chaque arguments, de chaque fonctions =S pour éviter cette erreur ?
Tu peux toujours mettre une condition dans ta fonction, if(empty(argument)){$this->redirect(view vers laquelle redirigé);} et un $id = null dans les arguments devraient le faire. Sinon tu définis un $id de base comme ça si l'utilisateur ne rentre pas d'argument il sera redirigé vers l'article en question.
Merci, mais j'ai trouvé la réponse ;) je l'es validé au dessus (En dessous de mon premier post), mon but était de prédire avant d'appeler la méthode qu'il manquait un argument, pour éviter dans celle ci de faire des tests conditionnels et renvoyer sur la page d'erreur 404, du coup grâce à ma solution, avant même d'appeler la méthode si il manque des paramètres ont sera rediriger vers la page d'erreur 404 ;)