13. Model

Notre premier model : Article.php

 Occupons-nous maintenant de créer un model pour nos articles : une classe  Article.php

Très bien, mais ça va nous servir à quoi exactement ?

À travailler avec des... objets 😄

Mais c'est déjà ce qu'on fait non ?

Pas tout à fait, on travaille effectivement avec des "objets", mais ce sont sont pas des "objets" conformes. Vous n'avez rien compris ? Ok, je vous explique 😉

Ouvrez votre fichier home.php et faites un var_dump de $article ...

<?php
while($article = $articles->fetch())
{
    var_dump($article);
    ?>
    <div>
        <h2><a href="../public/index.php?route=article&articleId=<?= htmlspecialchars($article->id);?>"><?= htmlspecialchars($article->title);?></a></h2>
        <p><?= htmlspecialchars($article->content);?></p>
        <p><?= htmlspecialchars($article->author);?></p>
        <p>Créé le : <?= htmlspecialchars($article->createdAt);?></p>
    </div>
    <br>
    <?php
}
$articles->closeCursor();
?>

Actualisez la page http://localhost/blog/public/index.php

Rien ne vous "choque" ?  


 

On a bien ici des objets, de la classe ... ArticleDAO 😱

Oui et alors ? Ça fonctionne c'est le principal non ?

Oui je vous l'accorde, mais ce n'est pas suffisant. Dans ce qu'on a mis en place dans notre application, les classes DAO ne doivent gérer QUE les requêtes SQL entre notre application et la base de données. Si vous regardez de plus près, on a aussi un attribut $connection qui appartient à la classe parents, la classe DAO.

Le mieux c'est d'avoir une classe Article, qui ne contienne que les propriétés et méthodes lui appartenant, qui nous crée ces objets, et non pas ArticleDAO.

Mais comment va-t-on faire pour transformer ça en objet ?

C'est justement l'objet de ce chapitre 😊

 Commençons par créer une classe  Article.php  (dans  src/model  ) :  

<?php

namespace App\src\model;

class Article
{
    
}
On y met quoi à l'intérieur ? 

Eh bien, ses propriétés et ses méthodes :

<?php

namespace App\src\model;

class Article
{
    /**
     * @var int
     */
    private $id;

    /**
     * @var string
     */
    private $title;

    /**
     * @var string
     */
    private $content;

    /**
     * @var string
     */
    private $author;

    /**
     * @var \DateTime
     */
    private $createdAt;

    /**
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @param int $id
     */
    public function setId($id)
    {
        $this->id = $id;
    }

    /**
     * @return string
     */
    public function getTitle()
    {
        return $this->title;
    }

    /**
     * @param string $title
     */
    public function setTitle($title)
    {
        $this->title = $title;
    }

    /**
     * @return string
     */
    public function getContent()
    {
        return $this->content;
    }

    /**
     * @param string $content
     */
    public function setContent($content)
    {
        $this->content = $content;
    }

    /**
     * @return string
     */
    public function getAuthor()
    {
        return $this->author;
    }

    /**
     * @param string $author
     */
    public function setAuthor($author)
    {
        $this->author = $author;
    }

    /**
     * @return \DateTime
     */
    public function getCreatedAt()
    {
        return $this->createdAt;
    }

    /**
     * @param \DateTime $createdAt
     */
    public function setCreatedAt($createdAt)
    {
        $this->createdAt = $createdAt;
    }
}

La PHPDoc a été générée avec PHPStorm 😅

Faisons maintenant le lien entre notre classe  Article  et ArticleDAO.

Pour cela, nous allons avoir besoin de plusieurs fichiers :

ArticleDAO.php en récupérant le résultat de la requête et en "transformant" celle-ci en objets, basé sur la classe Article

- DAO.php, en supprimant l'appel à SetFetchMode, qui ne va plus nous servir

- en adaptant le fichier home.php, notre vue

<?php

namespace App\src\DAO;

use App\src\model\Article;

class ArticleDAO extends DAO
{
    private function buildObject($row)
    {
        $article = new Article();
        $article->setId($row['id']);
        $article->setTitle($row['title']);
        $article->setContent($row['content']);
        $article->setAuthor($row['author']);
        $article->setCreatedAt($row['createdAt']);
        return $article;
    }

    public function getArticles()
    {
        $sql = 'SELECT id, title, content, author, createdAt FROM article ORDER BY id DESC';
        $result = $this->createQuery($sql);
        $articles = [];
        foreach ($result as $row){
            $articleId = $row['id'];
            $articles[$articleId] = $this->buildObject($row);
        }
        $result->closeCursor();
        return $articles;
    }

    public function getArticle($articleId)
    {
        $sql = 'SELECT id, title, content, author, createdAt FROM article WHERE id = ?';
        return $this->createQuery($sql, [$articleId]);
    }
}

On a créé une méthode privée  buildObject  qui nous permet de convertir chaque champ de la table en propriété de notre objet  Article  .
Cette méthode est appelée dans notre méthode getArticles pour renvoyer maintenant des objets de la classe Article 😁

Dans le fichier DAO.php, pensez à supprimer les lignes avec SetFetchMode 😉

On peut maintenant modifier notre vue home.php en conséquence

home.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
    foreach ($articles as $article)
    {
        ?>
        <div>
            <h2><a href="../public/index.php?route=article&articleId=<?= htmlspecialchars($article->getId());?>"><?= htmlspecialchars($article->getTitle());?></a></h2>
            <p><?= htmlspecialchars($article->getContent());?></p>
            <p><?= htmlspecialchars($article->getAuthor());?></p>
            <p>Créé le : <?= htmlspecialchars($article->getCreatedAt());?></p>
        </div>
        <br>
        <?php
    }
    ?>
</div>
</body>
</html>

Dans notre vue home.php, on a ici : 

- remplacé notre boucle while par une boucle foreach

- fais appel à nos getters de la classe Article

- supprimer l'appel à closeCursor (qui est maintenant fait dans ArticleDAO.php)

 

À vous de jouer pour faire la même chose pour ce qui est de la méthode getArticle (attention, vous aurez plusieurs fichiers à mettre à jour).

 

Je vous mets à jour les fichiers en conséquence juste en-dessous.

ArticleDAO.php :

<?php

namespace App\src\DAO;

use App\src\model\Article;

class ArticleDAO extends DAO
{
    private function buildObject($row)
    {
        $article = new Article();
        $article->setId($row['id']);
        $article->setTitle($row['title']);
        $article->setContent($row['content']);
        $article->setAuthor($row['author']);
        $article->setCreatedAt($row['createdAt']);
        return $article;
    }

    public function getArticles()
    {
        $sql = 'SELECT id, title, content, author, createdAt FROM article ORDER BY id DESC';
        $result = $this->createQuery($sql);
        $articles = [];
        foreach ($result as $row){
            $articleId = $row['id'];
            $articles[$articleId] = $this->buildObject($row);
        }
        $result->closeCursor();
        return $articles;
    }

    public function getArticle($articleId)
    {
        $sql = 'SELECT id, title, content, author, createdAt FROM article WHERE id = ?';
        $result = $this->createQuery($sql, [$articleId]);
        $article = $result->fetch();
        $result->closeCursor();
        return $this->buildObject($article);
    }
}

J'ai aussi mis à jour FrontController.php en renommant $articles en $article dans la méthode article étant donné qu'on ne renvoit qu'un seul article, cet objet étant utilisé dans la vue single.php.

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)
    {
        $article = $this->articleDAO->getArticle($articleId);
        $comments = $this->commentDAO->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>
    <div>
        <h2><?= htmlspecialchars($article->getTitle());?></h2>
        <p><?= htmlspecialchars($article->getContent());?></p>
        <p><?= htmlspecialchars($article->getAuthor());?></p>
        <p>Créé le : <?= htmlspecialchars($article->getCreatedAt());?></p>
    </div>
    <br>
    <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>

À ce stade, l'afffichage des articles doit fonctionner correctement 

Il nous reste à en faire de même avec notre classe Comment 😉

 

Notre deuxième model : Comment.php

 Commençons par créer notre classe  Comment.php  dans le dossier src/model

<?php

namespace App\src\model;

class Comment
{
    
}

Ajoutons maintenant ses caractéristiques :

<?php

namespace App\src\model;

class Comment
{
    /**
     * @var int
     */
    private $id;

    /**
     * @var string
     */
    private $pseudo;

    /**
     * @var string
     */
    private $content;

    /**
     * @var \DateTime
     */
    private $createdAt;

    /**
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @param int $id
     */
    public function setId($id)
    {
        $this->id = $id;
    }

    /**
     * @return string
     */
    public function getPseudo()
    {
        return $this->pseudo;
    }

    /**
     * @param string $pseudo
     */
    public function setPseudo($pseudo)
    {
        $this->pseudo = $pseudo;
    }

    /**
     * @return string
     */
    public function getContent()
    {
        return $this->content;
    }

    /**
     * @param string $content
     */
    public function setContent($content)
    {
        $this->content = $content;
    }

    /**
     * @return \DateTime
     */
    public function getCreatedAt()
    {
        return $this->createdAt;
    }

    /**
     * @param \DateTime $createdAt
     */
    public function setCreatedAt($createdAt)
    {
        $this->createdAt = $createdAt;
    }
}

Il ne nous reste plus qu'à modifier le fichier  CommentDAO.php

<?php

namespace App\src\DAO;

use App\src\model\Comment;

class CommentDAO extends DAO
{
    private function buildObject($row)
    {
        $comment = new Comment();
        $comment->setId($row['id']);
        $comment->setPseudo($row['pseudo']);
        $comment->setContent($row['content']);
        $comment->setCreatedAt($row['createdAt']);
        return $comment;
    }

    public function getCommentsFromArticle($articleId)
    {
        $sql = 'SELECT id, pseudo, content, createdAt FROM comment WHERE article_id = ? ORDER BY createdAt DESC';
        $result = $this->createQuery($sql, [$articleId]);
        $comments = [];
        foreach ($result as $row) {
            $commentId = $row['id'];
            $comments[$commentId] = $this->buildObject($row);
        }
        $result->closeCursor();
        return $comments;
    }
}

et la vue  single.php  qui affiche nos commentaires :

<!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>
    <div>
        <h2><?= htmlspecialchars($article->getTitle());?></h2>
        <p><?= htmlspecialchars($article->getContent());?></p>
        <p><?= htmlspecialchars($article->getAuthor());?></p>
        <p>Créé le : <?= htmlspecialchars($article->getCreatedAt());?></p>
    </div>
    <br>
    <a href="../public/index.php">Retour à l'accueil</a>
    <div id="comments" class="text-left" style="margin-left: 50px">
        <h3>Commentaires</h3>
        <?php
        foreach ($comments as $comment)
        {
            ?>
            <h4><?= htmlspecialchars($comment->getPseudo());?></h4>
            <p><?= htmlspecialchars($comment->getContent());?></p>
            <p>Posté le <?= htmlspecialchars($comment->getCreatedAt());?></p>
            <?php
        }
        ?>
    </div>
</div>
</body>
</html>

Et voilà le travail 😅

 On travaille maintenant avec des objets dans nos vues 😏

En parlant des vues, à leur tour d'être adaptées en objet.

 

Bilan

Dans ce chapitre, nous avons mis en place nos objets pour utiliser un maximum la programmation orientée objet.

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