12. Controller

Notre premier contrôleur

Nous allons avoir besoin de deux contrôleurs pour notre blog : 
- un  FrontController  qui va gérer ce qui est accessible à tout le monde
- un  BackController  qui permettra de gérer les fonctionnalités de l'espace d'administration

Commençons par créer une classe  FrontController  dans le dossier  controller  dans  src  et ajoutons la méthode  home  :

<?php

namespace App\src\controller;

class FrontController
{
    public function home()
    {

    }
}

La méthode  home  va gérer l'affichage de la page d'accueil de notre site.

Oui c'est bien beau tout ça mais on en fait quoi de cette méthode ? 😅

Nous allons faire appel à notre contrôleur depuis notre... Routeur 😄 Et c'est justement l'appel à cette action qui va gérer le rendu de notre page d'accueil.

Mais qu'est-ce que tu racontes ? J'ai rien compris 😫

Ne vous en faites pas, voici la mise en pratique associée :

Router.php

<?php

namespace App\config;
use App\src\controller\FrontController;
use Exception;

class Router
{
    public function run()
    {
        try{
            if(isset($_GET['route']))
            {
                if($_GET['route'] === 'article'){
                    require '../templates/single.php';
                }
                else{
                    echo 'page inconnue';
                }
            }
            else{
                $frontController = new FrontController();
                $frontController->home();
            }
        }
        catch (Exception $e)
        {
            echo 'Erreur';
        }
    }
}

Ici, on instancie un objet $frontController et on fait appel à la méthode home.

Mais où est passé la 7ème compagnie ? euh, pardon, où est passé le  require  du fichier  home.php  ? 

Rassurez-vous, on l'a déplacé dans la méthode  home  du contrôleur que l'on vient de créer 😉 Voyez-par vous-mêmes

FrontController.php

<?php

namespace App\src\controller;

class FrontController
{
    public function home()
    {
        require '../templates/home.php';
    }
}

Si vous actualisez votre page d'accueil, ça fonctionne toujours 😊

On va aller un petit peu plus loin, en limitant au maximum le code php dans nos vues.

On va retirer les deux lignes suivantes dans  home.php  :

<?php
$article = new ArticleDAO();
$articles = $article->getArticles();

et les déplacer dans la méthode  home  du  FrontController . Pensez à récupérer le use en haut du fichier home.php et déplacez le dans le FrontController.php, comme ici :

FrontController.php

<?php

namespace App\src\controller;
use App\src\DAO\ArticleDAO;

class FrontController
{
    public function home()
    {
        $article = new ArticleDAO();
        $articles = $article->getArticles();
        require '../templates/home.php';
    }
}

Si vous actualisez votre page, on est toujours bon 😜

Allez, profitons-en pour en faire de même avec le rendu de la page single 😉

Voici nos fichiers actualisés : 
Router.php

<?php

namespace App\config;
use App\src\controller\FrontController;
use Exception;

class Router
{
    public function run()
    {
        try{
            if(isset($_GET['route']))
            {
                if($_GET['route'] === 'article'){
                    $frontController = new FrontController();
                    $frontController->article($_GET['articleId']);
                }
                else{
                    echo 'page inconnue';
                }
            }
            else{
                $frontController = new FrontController();
                $frontController->home();
            }
        }
        catch (Exception $e)
        {
            echo 'Erreur';
        }
    }
}

FrontController.php

<?php

namespace App\src\controller;
use App\src\DAO\ArticleDAO;
use App\src\DAO\CommentDAO;

class FrontController
{
    public function home()
    {
        $article = new ArticleDAO();
        $articles = $article->getArticles();
        require '../templates/home.php';
    }

    public function article($articleId)
    {
        $article = new ArticleDAO();
        $articles = $article->getArticle($articleId);
        $comment = new CommentDAO();
        $comments = $comment->getCommentsFromArticle($articleId);
        require '../templates/single.php';
    }
}

single.php

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="utf-8">
    <title>Mon blog</title>
</head>

<body>
<div>
    <h1>Mon blog</h1>
    <p>En construction</p>
    <?php
    $article = $articles->fetch()
    ?>
    <div>
        <h2><?= htmlspecialchars($article->title);?></h2>
        <p><?= htmlspecialchars($article->content);?></p>
        <p><?= htmlspecialchars($article->author);?></p>
        <p>Créé le : <?= htmlspecialchars($article->createdAt);?></p>
    </div>
    <br>
    <?php
    $articles->closeCursor();
    ?>
    <a href="../public/index.php">Retour à l'accueil</a>
    <div id="comments" class="text-left" style="margin-left: 50px">
        <h3>Commentaires</h3>
        <?php
        while($comment = $comments->fetch())
        {
            ?>
            <h4><?= htmlspecialchars($comment->pseudo);?></h4>
            <p><?= htmlspecialchars($comment->content);?></p>
            <p>Posté le <?= htmlspecialchars($comment->createdAt);?></p>
            <?php
        }
        $comments->closeCursor();
        ?>
    </div>
</div>
</body>
</html>

Dans le router, on a utilisé le même principe que tout à l'heure, mais on a fait appel à une autre méthode,  article  , qui a besoin de l'identifiant passé en paramètre.
Le contrôleur instancie un objet  ArticleDAO  et  CommentDAO  et fait appel aux méthodes dont on a besoin, la vue associée se contente de faire une boucle et d'afficher les informations. On a aussi remplacé dans notre Contrôleur $_GET['articleId'] par $articleId.  

 

Un peu de refactorisation

 Encore ? Tu te fiches de nous ? 😠 

Je vous l'avais dis, ça arrivera régulièrement dans le développement de vos projets.
Je vais ici refactoriser le fichier  Router.php  et  FrontController.php

Je vous invite à essayer par vous-même (vous avez dû remarquer qu'un peu de code était répété), et voir la solution si vous bloquez.

Router.php  

<?php

namespace App\config;
use App\src\controller\FrontController;
use Exception;

class Router
{
    private $frontController;

    public function __construct()
    {
        $this->frontController = new FrontController();
    }

    public function run()
    {
        try{
            if(isset($_GET['route']))
            {
                if($_GET['route'] === 'article'){
                    $this->frontController->article($_GET['articleId']);
                }
                else{
                    echo 'page inconnue';
                }
            }
            else{
                $this->frontController->home();
            }
        }
        catch (Exception $e)
        {
            echo 'Erreur';
        }
    }
}

FrontController.php

<?php

namespace App\src\controller;
use App\src\DAO\ArticleDAO;
use App\src\DAO\CommentDAO;

class FrontController
{
    private $articleDAO;
    private $commentDAO;

    public function __construct()
    {
        $this->articleDAO = new ArticleDAO();
        $this->commentDAO = new CommentDAO();
    }

    public function home()
    {
        $articles = $this->articleDAO->getArticles();
        require '../templates/home.php';
    }

    public function article($articleId)
    {
        $articles = $this->articleDAO->getArticle($articleId);
        $comments = $this->commentDAO->getCommentsFromArticle($articleId);
        require '../templates/single.php';
    }
}

Et voilà le travail, c'était simple hein ? 😝

On commence maintenant à respecter le modèle MVC, même si nous ne travaillons pas encore tout à fait avec des objets. Je reviens là-dessus bientôt.

Pour le moment, occupons-nous de notre backController

 

Ajoutons un nouveau contrôleur, BackController

Voici notre fichier créé  BackController.php  (dans  src/controller  )

<?php

namespace App\src\controller;

class BackController
{

}
Qu'est-ce qu'on y met à l'intérieur ? 😅

Rien... du moins pour le moment.

Pourquoi le créer maintenant alors ? 😑

Pour vous habituer à créer des contrôleurs pardi 😉

D'ailleurs, connaissez-vous l'adage ? Jamais deux sans trois 😃

 

ErrorController, pour gérer les erreurs

Vous avez dû remarquer (ou pas 😝 ) que dans notre  Router  les erreurs n'étaient pas gérées par des contrôleurs. Pour une application optimale, il faut que tout soit géré de la même manière pour éviter de s'y perdre.

Je vous laisse essayer de mettre en place cette fonctionnalité, sachant que :
- le Router doit faire appel à une méthode du ErrorController
- chaque méthode de ce contrôleur doit renvoyer une vue
- la vue peut contenir uniquement un echo en php, ou en HTML, peu importe
À vous de jouer. 😉

Vous avez réussi ? Vous avez bloqué sur un point ? 

Pas de panique, je vous donne une solution ici :

Notre fichier Router.php actualisé

<?php

namespace App\config;
use App\src\controller\FrontController;
use App\src\controller\ErrorController;
use Exception;

class Router
{
    private $frontController;
    private $errorController;

    public function __construct()
    {
        $this->frontController = new FrontController();
        $this->errorController = new ErrorController();
    }

    public function run()
    {
        try{
            if(isset($_GET['route']))
            {
                if($_GET['route'] === 'article'){
                    $this->frontController->article($_GET['articleId']);
                }
                else{
                    $this->errorController->errorNotFound();
                }
            }
            else{
                $this->frontController->home();
            }
        }
        catch (Exception $e)
        {
            $this->errorController->errorServer();
        }
    }
}

Voici donc le ErrorController.php

<?php

namespace App\src\controller;

class ErrorController
{
    public function errorNotFound()
    {
        require '../templates/error_404.php';
    }

    public function errorServer()
    {
        require '../templates/error_500.php';
    }
}

Je ne mets pas le code des fichiers  error_404.php  et  error_500.php  , ce sont de simples messages affichant 'page non trouvée' et 'problème serveur'.

Vous vous rappelez de ce que je vous ai dis tout à l'heure ? Qu'on ne travaillait pas totalement avec des objets ? 

On s'en occupe maintenant 😉

 

Bilan

Dans ce chapitre, nous avons mis en place nos contrôleurs pour respecter le modèle MVC. Nous allons maintenant nous occuper de la partie model de notre MVC.

Vous pouvez retrouver le code associé à ce chapitre sur GitHub.