Salut à tous, je tennais à remercier énormément GrafikArt pour cette formation qui m'a énormément aidée !

Il me reste cependant une question.
Dans le chapitre sur le MVC, on construit une sorte de routeur dans le fichier index.php qui sert à rediriger sur les bons controlleurs ainsi que sur la bonne action, en fonction de l'url saisie.

Exemple: index.php?p=posts.index

Nous redirige sur le controlleur PostsController et utilise l'action index.

Or lorsque l'on saisis une action qui n'existe pas
Example: index.php?p=posts.actioninexistante

On obtient une erreur du style:
Fatal error: Call to undefined method App\Controller\PostsController::actioninexistante() in /MonSite/public/index.php on line 21

L'erreur est encore un peut plus importante lorsque le controleur appelé n'existe pas..

J'aimerais donc simplement vous demander si vous conaissez un moyen de contourner l'erreur, ou si vous conaissez une fonction qui fasse en sorte que si l'url saisie redirige bien vers une action fonctionnelle, elle l'affiche.
Sinon, si ce qui est saisis dans l'url n'est pas valable, on redirige vers index.php

Je vous met le code du système de routing pour ceux qui n'aurais pas fait la formation:

if(isset($_GET['p'])){
    $page = $_GET['p'];
} else {
    $page = 'posts.index';
}

$page = explode('.', $page);
if($page[0] == 'admin'){
    $controller = '\App\Controller\Admin\\' . ucfirst($page[1]) . 'Controller';
    $action = $page[2];
} else {
    $controller = '\App\Controller\\' . ucfirst($page[0]) . 'Controller';
    $action = $page[1];
}
$controller = new $controller();
$controller->$action();

En tout cas, je vous remercie beaucoup d'avoir juste pris le temps de me lire.

15 réponses


Lqncer
Réponse acceptée

Salut

fait simplement un test avec get_class_methods tu regarde si la méthod existe si oui tu laisse passé si non tu redirige

hugopb82
Réponse acceptée

Bonjour, regarde du côté de file_exists pour les controllers et du côté de method_exists pour les méthodes.
Essaye de trouver la solution par toi-même car la création d'un router est un excellent entraînement! ;)
Hugo

Bon ben c'est génial, je te remercie beaucoup Lqncer !
Je viens de modifier un peut le code, et si une action inexistante est saisie, on redirige vers accueil !

$controller = new $controller();
$methodes = get_class_methods($controller);
if(in_array($action, $methodes)){
    $controller->$action();
}else{
    header('Location: index.php');
}

Par contre pour le controlleur, je viens de réfléchir à une solution d'après ce que tu me conseille hugopb82 (d'ailleur merci beaucoup pour votre réactivitée les mecs !)
Hummm.... Au Boulot !

A mon goût la fonction method_exists est plus simple que de récuperer toutes les méthodes et de faire un in_array. Ton code sera peut-être plus lisible mais après chacun code différemment :)

Oui c'est pas faux sinon pour tester

if(!class_exists('Nom de ta classe', false)){
    header('Location: index.php');
}

if(!method_exists('Nom de ta classe', 'Ta_method')){
    header('Location: index.php');
}

Salut!

J'ai un router dont je vais faire la liste des vérifications, mais juste un truc à savoir : je prends tout dans une variable, avec le .htaccess. Par exemple, si on appelle site.com/controller/action/param1/param2/parametc, du côté du PHP, je vais récupérer controller/action/param1/param2/parametc. Je divise le tout en array, ce qui me donne $arr[0] le controller et $arr[1] l'action, et le reste sont des paramètres.

Maintenant, la liste des vérifications:

<?php

if () {
    // request empty and default is not callable = error 404
} elseif () {
    // request empty and default is callable = call default
} elseif () {
    // controller doesn't exist = error 404
} elseif () {
    // no specific method called and default action exists = call default action from controller
} elseif () {
    // no specific method called and default method doesn't exist = error 404
} elseif () {
    // method doesn't exist in controller = error 404
} else {
    // everything is fine = call method in controller
}

Si tu veux, je peux te montrer les conditions, si ça aide.

Franchement je vous remercie beaucoup car grâce à vos indications j'ai réussis en vraiment peut de temps !!
Je pensais que j'allais galérer car je suis encore un peut débutant mais en fait, suivre cette formation m'à vraiment fait aquérir pas mal de connaissances !

Je met le code du controlleur au cas ou ça puisse servir à quelqu'un un jour ^^

if(isset($_GET['p'])){
    $page = $_GET['p'];
} else {
    $page = 'posts.index';
}

$page = explode('.', $page);
if($page[0] == 'admin'){
    $file = './../app/Controller/Admin/' .ucfirst($page[1]) . 'Controller.php';
    $controller = '\App\Controller\Admin\\' . ucfirst($page[1]) . 'Controller';
    $action = $page[2];
} else {
    $file = './../app/Controller/' .ucfirst($page[0]) . 'Controller.php';
    $controller = '\App\Controller\\' . ucfirst($page[0]) . 'Controller';
    $action = $page[1];
}

if (file_exists($file)) {
    $controller = new $controller();
    $methodes = get_class_methods($controller);
    if(in_array($action, $methodes)){
        $controller->$action();
    }else{
        header('Location: index.php');
    }
} else {
    header('Location: index.php');
}

Si jamais, dites moi ce que vous en pensez.
(Sinon par rapport aux dernières fonctions que vous m'aviez conseiller j'étais déja parti sur celles conseillées au début, les quelles sont les mieux dans mon cas ? Y a t il une optimisation possible ou tant que les cas d'utilisations succés/échecs fonctionnent et que le code n'est pas dégueulasse c'est valable ?)

Merci pour tout !

Salut Forever, merci beaucoup pour ta réponse mais en fait dans la formation PHP OO GrafikArt propose de transformer un routeur comme tu me propose, en un routeur "dynamique" qui en gros devine les chemins à utiliser en fonction de l'url soumise, on à donc plus à écrire chaque cas comme dans ce que tu me conseillais justement =D
Si tu ne connais pas je te conseille de te pencher dessus c'est vraiment top !
(Je ne conaissais pas il y a une semaine et maintenant que j'ai compris j'utiliserais toujours cette méthode !)

@QuentiPancakes: que signifie "un routeur dynamique" pour toi ? J'ai du mal à voir la différence. Les conditions que je t'ai proposait ne sont qu'une frame, le controlleur appellé dépend bien entendu du GET...

En gros ce que j'apelle un routeur dynamique (mais cela ne doit vraiment pas s'appeler comme ça) c'est le fait qu'on ai pas besoin d'écrire à la main les routes dans le fichier index.php, mais j'avais mal lu ce que tu me proposais et je m'en excuse, je veut bien en effet que tu me montre les conditions car cette methode à l'air encore mieux que ce que j'ai arrangé moi même, qui par exemple ne pointe pas vers une erreur 404 ou ce genre de choses !!
Excuse moi d'avoir lu trop vite, mais je bosse sur deux écrans à la fois et j'étais reflexion intensive ^^

<?php
if (empty($req) &&
    !is_callable(['App\\Controllers\\' .
                  $config('default_mvc_name') .
                  $config('controllers_ext'),
                  $config('default_controller_method')])) {
    // request empty and default is not callable = error 404

    $controller = $caller->controller('Errors\\Error404');
    $method = $config('default_controller_method');

} elseif (empty($req)) {
    // request empty and default is callable = call default

    $controller = $caller->controller('Main');
    $method = $config('default_controller_method');

} elseif (!class_exists('App\\Controllers\\' .
                        $arr_req[0] .
                        $config('controllers_ext'))) {
    // controller doesn't exist = error 404

    $controller = $caller
        ->controller('Errors\\Error404',
                     \App\Helpers\Php::array_diff_key_values($arr_req, []));
    $method = $config('default_controller_method');

} elseif (empty($arr_req[1]) &&
          is_callable(['App\\Controllers\\' .
                       $arr_req[0] .
                       $config('controllers_ext'),
                       $config('default_controller_method')])) {
    // no specific method called and index() exists = call index() from controller

    $controller = $caller->controller($arr_req[0]);
    $method = $config('default_controller_method');

} elseif (empty($arr_req[1])) {
    // no specific method called and default method doesn't exist = error 404

    $controller = $caller
        ->controller('Errors\\Error404',
                     \App\Helpers\Php::array_diff_key_values($arr_req, []));
    $method = $config('default_controller_method');

} elseif (!is_callable(['App\\Controllers\\' .
                       $arr_req[0] .
                       $config('controllers_ext'),
                       $arr_req[1]])) {
    // method doesn't exist in controller = error 404

    $controller = $caller
        ->controller('Errors\\Error404',
                     \App\Helpers\Php::array_diff_key_values($arr_req, []));
    $method = $config('default_controller_method');

} else {
    // everything is fine = call method in controller

    $controller = $caller
        ->controller($arr_req[0],
                     \App\Helpers\Php::array_diff_key_values($arr_req, [0, 1]));
    $method = $arr_req[1];

}

Où:

  • $req: string contenant la requête (GET);
  • $arr_req: explode('/', $req);, donc $arr[0] contient le nom du controlleur que l'on désire et $arr_req[1] le nom de l'action;
  • $config: classe de configuration où:
    • default_mvc_name: string contenant le nom des model-view-controller par défaut (Main dans mon cas);
    • controllers_ext: string contenant le suffixe qui est présent sur tout les controllers (Controller dans mon cas);
    • default_controller_method: l'action à utiliser pas défaut (index dans mon cas);
  • $caller: class qui me permet de générer un model/view/controller/twig facilement.

En suite, je fais simplement $controller->$method();.

C'est pour mon framework perso, tu peux voir le projet ici (que j'ai commencé hier...), mais là, j'arrive pas à envoyer les derniers changements, à cause du DDoS que Github subbit depuis un petit moment maintenant.

Ça défonce !! Tu penses que je peut participer au projet, ou tu bosse qu'avec des mecs que tu connais ? :)
En fait je suis en 2éme année de BTS SIO donc je suis pas vraiment débutant, et surtout avec cette formation que j'ai suivie genre 3 fois j'ai apris vraiment pas mal de choses. En ce moment je me fais un site et j'ai toujours eut envie de participer a un projet comme ça !
Dit moi si t'es chaud :)

En faite, je fais sa tout seul. J'avais pas pensé que sa pourrait intéresser quelqu'un, avec tout les frameworks déjà existant. :p

Après, je comptais faire un framework assez basique, avec le strict minimum (MVC, config, logger, template engine), donc je dois t'avouer que je vois le projet comme presque fini pour une première release. Ce qui reste à faire, selon moi:

  • transformer le pâté qu'est le routeur en joli code OO;
  • README file;
  • ajouter/créer une ORM;
  • faire pleins de tests pour vérifier le tout.

Je dis pas que c'est fini, et parfait, donc si tu veux contribuer, j'accepte volontié! Comment pourrait-on discuter ? En PV sur irc, pour se passer un lien tlk.io par exemple ?

Je suis chaud pour contribuer !
Même si il existe beaucoup de framework j'ai déja pensé en faire un simple, ne serait ce que pour apprendre, et pouvoir l'utiliser pour des petits projets perso, la ou des gros framework ne seraient que suprflux !
J'aimerais bien te donner une adresse email ou mon skype mais je vais me faire détruire la boite mail si je dépose une adresse ici ^^
Tu veux créer une salle sur tlk.io ?

Viens sur irc, on pourra parler.