web-dev-qa-db-fra.com

Un exemple de contrôleur MVC

J'ai beaucoup lu sur comment et pourquoi utiliser une approche MVC dans une application. J'ai vu et compris des exemples de modèle, j'ai vu et compris des exemples de View ... mais je suis TOUJOURS un peu confus sur le contrôleur. J'aimerais vraiment voir un exemple suffisamment complet de contrôleurs. (dans PHP si possible, mais tout langage pourra vous aider)

Je vous remercie.

PS: Ce serait également bien si je pouvais voir un exemple de page index.php, qui décide quel contrôleur utiliser et comment.

MODIFIER: Je sais ce que le contrôleur est travail, je ne comprends pas vraiment comment accomplir cela en POO.

38
BDuelz

Exemple de demande

Mettez quelque chose comme ceci dans votre index.php:

<?php

// Holds data like $baseUrl etc.
include 'config.php';

$requestUrl = 'http://'.$_SERVER['HTTP_Host'].$_SERVER['REQUEST_URI'];
$requestString = substr($requestUrl, strlen($baseUrl));

$urlParams = explode('/', $requestString);

// TODO: Consider security (see comments)
$controllerName = ucfirst(array_shift($urlParams)).'Controller';
$actionName = strtolower(array_shift($urlParams)).'Action';

// Here you should probably gather the rest as params

// Call the action
$controller = new $controllerName;
$controller->$actionName();

Vraiment basique, mais vous avez l’idée… (Je ne me suis pas non plus occupé du chargement de la classe de contrôleur, mais je suppose que cela peut être fait soit par chargement automatique, soit vous savez comment le faire.)

Exemple de contrôleur simple (controllers/login.php):

<?php    

class LoginController
{
    function loginAction()
    {
        $username = $this->request->get('username');
        $password = $this->request->get('password');

        $this->loadModel('users');
        if ($this->users->validate($username, $password))
        {
            $userData = $this->users->fetch($username);
            AuthStorage::save($username, $userData);
            $this->redirect('secret_area');
        }
        else
        {
            $this->view->message = 'Invalid login';
            $this->view->render('error');
        }
    }

    function logoutAction()
    {
        if (AuthStorage::logged())
        {
            AuthStorage::remove();
            $this->redirect('index');
        }
        else
        {
            $this->view->message = 'You are not logged in.';
            $this->view->render('error');
        }
    }
}

Comme vous le voyez, le contrôleur prend en charge le "flux" de l'application - la logique dite d'application. Il ne prend pas en charge le stockage et la présentation des données. Il rassemble plutôt toutes les données nécessaires (en fonction de la demande en cours) et les assigne à la vue ...

Notez que cela ne fonctionnerait avec aucun framework que je connaisse, mais je suis sûr que vous savez ce que les fonctions sont censées faire.

60
Franz

Imaginez-vous des écrans dans une interface utilisateur, un écran dans lequel un utilisateur entre certains critères de recherche, un écran dans lequel une liste de résumés des enregistrements correspondants est affichée et un écran dans lequel, lorsqu'un enregistrement est sélectionné, il est affiché pour édition. Il y aura une certaine logique relative à la recherche initiale sur les lignes de

if search criteria are matched by no records
    redisplay criteria screen, with message saying "none found"
else if search criteria are matched by exactly one record
    display edit screen with chosen record
else (we have lots of records)
    display list screen with matching records

Où doit aller cette logique? Pas dans la vue ou le modèle sûrement? C'est donc le travail du contrôleur. Le responsable du traitement serait également chargé de prendre les critères et d’appeler la méthode Model pour la recherche.

1
djna
<?php

class App {
    protected static $router;

    public static function getRouter() {
        return self::$router;
    }

    public static function run($uri) {
        self::$router = new Router($uri);

        //get controller class
        $controller_class = ucfirst(self::$router->getController()) . 'Controller';
        //get method
        $controller_method = strtolower((self::$router->getMethodPrefix() != "" ? self::$router->getMethodPrefix() . '_' : '') . self::$router->getAction());

        if(method_exists($controller_class, $controller_method)){
            $controller_obj = new $controller_class();
            $view_path = $controller_obj->$controller_method();

            $view_obj = new View($controller_obj->getData(), $view_path);
            $content = $view_obj->render();
        }else{
            throw new Exception("Called method does not exists!");
        }

        //layout
        $route_path = self::getRouter()->getRoute();
        $layout = ROOT . '/views/layout/' . $route_path . '.phtml';
        $layout_view_obj = new View(compact('content'), $layout);
        echo $layout_view_obj->render();
    }

    public static function redirect($uri){
        print("<script>window.location.href='{$uri}'</script>");
        exit();
    }
}
0
David
<?php
class Router {

    protected $uri;

    protected $controller;

    protected $action;

    protected $params;

    protected $route;

    protected $method_prefix;

    /**
     * 
     * @return mixed
     */
    function getUri() {
        return $this->uri;
    }

    /**
     * 
     * @return mixed
     */
    function getController() {
        return $this->controller;
    }

    /**
     * 
     * @return mixed
     */
    function getAction() {
        return $this->action;
    }

    /**
     * 
     * @return mixed
     */
    function getParams() {
        return $this->params;
    }

    function getRoute() {
        return $this->route;
    }

    function getMethodPrefix() {
        return $this->method_prefix;
    }

        public function __construct($uri) {
            $this->uri = urldecode(trim($uri, "/"));
            //defaults
            $routes = Config::get("routes");
            $this->route = Config::get("default_route");
            $this->controller = Config::get("default_controller");
            $this->action = Config::get("default_action");
            $this->method_prefix= isset($routes[$this->route]) ? $routes[$this->route] : '';


            //get uri params
            $uri_parts = explode("?", $this->uri);
            $path = $uri_parts[0];
            $path_parts = explode("/", $path);

            if(count($path_parts)){
                //get route
                if(in_array(strtolower(current($path_parts)), array_keys($routes))){
                    $this->route = strtolower(current($path_parts));
                    $this->method_prefix = isset($routes[$this->route]) ? $routes[$this->route] : '';
                    array_shift($path_parts);
                }

                //get controller
                if(current($path_parts)){
                    $this->controller = strtolower(current($path_parts));
                    array_shift($path_parts);
                }

                //get action
                if(current($path_parts)){
                    $this->action = strtolower(current($path_parts));
                    array_shift($path_parts);
                }

                //reset is for parameters
                //$this->params = $path_parts;
                //processing params from url to array
                $aParams = array();
                if(current($path_parts)){ 
                    for($i=0; $i<count($path_parts); $i++){
                        $aParams[$path_parts[$i]] = isset($path_parts[$i+1]) ? $path_parts[$i+1] : null;
                        $i++;
                    }
                }

                $this->params = (object)$aParams;
            }

    }
}
0
David
  1. Créer une structure de dossier
  2. Configuration .htaccess & hôtes virtuels
  3. Créer une classe de configuration pour construire un tableau de configuration

Manette

  1. Créer une classe de routeur avec une protection non statique, avec des accesseurs
  2. Créer init.php avec config include & autoload et les chemins d'inclusion (lib, controlelrs, models)
  3. Créer un fichier de configuration avec routes, valeurs par défaut (route, contrôleurs, action)
  4. Définir les valeurs dans le routeur - valeurs par défaut
  5. Définir les chemins URI, exploser l'URI et définir la route, le contrôleur, l'action, les paramètres, les paramètres de processus.
  6. Créez une classe d'application pour exécuter l'application en passant uri - (routeur protégé obj, exécutez func)
  7. Créez une classe parente de contrôleur qui héritera de tous les autres contrôleurs (données protégées, modèle, paramètres non statiques) Set data, paramètres dans le constructeur.
  8. Créer un contrôleur et étendre avec la classe parent ci-dessus et ajouter une méthode par défaut.
  9. Appelez la classe et la méthode du contrôleur dans la fonction d'exécution. méthode doit être avec préfixe.
  10. Appelez la méthode si elle existe

Des vues

  1. Créez une classe de vue parent pour générer des vues. (data, path) avec le chemin par défaut, set controller, render funcs en renvoie le chemin complet tempalte (non statique)
  2. Créez une fonction de rendu avec ob_start (), ob_get_clean pour renvoyer et envoyer le contenu au navigateur.
  3. Modifiez la classe d'application pour analyser les données afin d'afficher la classe. si chemin est renvoyé, passe également à la classe.
  4. Layouts..layout dépend du routeur. re-analyser la mise en page HTML pour afficher et rendre 
0
David