Navigation

Versions

- 8 avril 2008 : Adaptation au ZF 1.5.1 (ajout loadClass)
- 7 août 2007 : correction du display.phtml sur la page qui ne correspond pas au fichier zip...
- 3 juil 2007 : adaptation ZF 1.0.0 stable
- 15 juin 2007 : adaptation ZF 1.0RC2 + refonte pour ViewRenderer
- 2 juin 2007 : adaptation rapide ZF 1.0RC1
- 11 mai 2007 : adaptation ZF:0.9.3
- 5 avril 2007 : correction du zip et utilisation PATH_SEPARATOR
- Mars 2007 : adaptation au ZF 0.9.x
- 23 fev 2007 : adaptation ZF 0.8.0 : Zend_Filter, Zend_Validate et RewriteRouter modifiés
- 12 fev 2007 : traitement exception par controller
- 19 jan 2007 : adaptation ZF 0.7.0 (pas d'évolution)
- 2 jan 2007 : adaptation au ZF 0.6.0
- 2 nov 2006 : adaptation au ZF 0.2.0
- 18 juillet 2006 : ajout d'un paragraphe sur le lancement de l'appli
- 13 juillet 2006 : création

Contactez-nous

Kitpages
17 rue de la Frise
38000 Grenoble
tel : 04 58 00 33 81

Par Philippe Le Van (@plv) Dernière mise à jour : 08 April 2008

Kitpages : Tutorial Zend Framework avancé 1.5.x

Introduction

Ce tutorial se présente comme la 2e partie de l'initiation au Zend Framework.

Nous avons décidé de présenter un exemple de réalisation très simple (un système d'ajouts de commentaires).

Ce tutorial est nettement plus complexe que le précédent. Il demande d'avoir des notions dans les domaines suivant :

Il aborde des notions fondamentales du Zend Framework pour celui qui veut créer un site web dynamique :

  • Le routeur
  • Le contrôleurLe viewer
  • Les bases de données
  • Le loggeur
  • Les filtres (input filter)

 

N'hésitez pas à m'envoyer vos commentaires.

(Restez informés de l'actualité du Zend Framework en vous rendant sur la communauté française du Zend Framework http://www.z-f.fr )

Le mini projet : Un système de commentaires

Nous allons réaliser un système de commentaires. Cela comprend 2 pages :

  • Une page d'ajout d'un commentaire
  • Une page d'affichage de l'ensemble des commentaires

Quand on ajoute un commentaire, on revient sur la liste des commentaires et quand on clique sur "ajouter un commentaire", on va sur le formulaire d'ajout de commentaires.

Pour réaliser cette appli, nous aurons besoin des fichiers suivants :

  • index.php (avec des éléments supplémentaires par rapport à l'initiation)
  • CommentController.php (le controller de l'application)
  • Les vues
    • comment/display.phtml (la page qui affiche les messages)
    • comment/edit.phtml (la page qui affiche le formulaire)
  • Kitpages_Tutoriaux_Facade : le modèle de l'application

Organisation des fichiers

L'organisation des fichiers suit l'arborescence définie à droite.

Notons qu'on peut interdire à un internaute l'accès à l'ensemble du répertoire PHP-INF. C'est même conseillé pour des raisons de sécurité. On sait ainsi que son seul point d'entrée est le fichier index.php. C'est l'objet du fichier .htaccess contenu dans le répertoire PHP-INF/.htaccess . Il contient uniquement "Deny from all".

Vous pouvez télécharger cette archive.

Base de données

Pour que l'exemple fonctionne, il faut créer une table dans la base de données :

CREATE TABLE `comment` (
  `id` int(32) unsigned NOT NULL auto_increment,
  `email` varchar(200) default NULL,
  `subject` varchar(200) NOT NULL,
  `content` text NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB ;

fichier index.php

Le fichier index.php est central. Vous l'avez déjà vu dans l'"initiation au Zend Framework". Voyons ce qui a changé :

  • des constantes en plus pour :
    • L'emplacement du fichier de logs
    • La connexion à la base de données
  • L'initialisation du logger
    • On voit l'initialisation du logger avec notamment le Zend_Log_Writer_Stream
    • On voit comment utiliser le logger
    • Note : dans la vraie vie, il faudra mettre en place un système plus malin que le logger dans la registry, parce que ça serait infernal de taper une ligne aussi longue pour envoyer un log...
  • L'ajout d'une route dans le routeur
    • La route ajoutée sert à orienter les requêtes du genre http://localhost/Tutoriaux/comment/xxx/yyy vers le controller comment, l'action xxx et envoie la valeur yyy dans le paramètre comment.
    • c'est le RewriteRouteur qui permet de faire ces tours de magie.

 

<?php
// mettre vos constantes ici...
define("WEBAPP_DIR","C:/users/levan/_boulot/eclipse/Tutoriaux");
define("MODEL_DIR",WEBAPP_DIR."/PHP-INF/model");
define("ROOT_URL","http://localhost/Tutoriaux");
define("BASE_URL","/Tutoriaux/");
define("ZEND_FRAMEWORK_DIR","C:/phplib/ZendFramework/library");
define("LOG_FILE","C:/tutoriaux.log");
 
define("DB_SERVER","localhost");
define("DB_PORT","3306");
define("DB_NAME","tutoriaux");
define("DB_USER","root");
define("DB_PASSWORD","");
define("DB_TYPE","PDO_MYSQL");
 
 
set_include_path(
  ".".PATH_SEPARATOR.
  MODEL_DIR.PATH_SEPARATOR.
  ZEND_FRAMEWORK_DIR.PATH_SEPARATOR.
  get_include_path()
);
 
require_once 'Zend/Loader.php';
 
// Registry init
Zend_Loader::loadClass("Zend_Registry");
 
// Logger init
Zend_Loader::loadClass('Zend_Log');
Zend_Loader::loadClass('Zend_Log_Writer_Stream');
$logger = new Zend_Log();
$logger->addWriter(new Zend_Log_Writer_Stream(LOG_FILE));
Zend_Registry::set("logger",$logger);
Zend_Registry::get("logger")
    ->debug("** URI=".$_SERVER["REQUEST_URI"]);
 
// Controller init
Zend_Loader::loadClass('Zend_Controller_Front');
Zend_Loader::loadClass('Zend_Controller_Router_Rewrite');
$controller = Zend_Controller_Front::getInstance();
 
$router = new Zend_Controller_Router_Rewrite();
 
$cmtRoute = new Zend_Controller_Router_Route(
    "comment/:action/:comment",
    array(  "comment"=>null,
            "controller"=>"comment",
            "action"=>"display"
    )
);
$router->addRoute("comment",$cmtRoute);
$controller->setBaseUrl(BASE_URL);
 
$controller->setRouter($router);
$controller->setControllerDirectory('PHP-INF/ctrl');
$controller->throwExceptions(true);
 
// init viewRenderer
Zend_Loader::loadClass("Zend_View");
$view = new Zend_View();
$viewRenderer = Zend_Controller_Action_HelperBroker::
    getStaticHelper('viewRenderer');
$viewRenderer->setView($view)
             ->setViewSuffix('phtml');
 
// call dispatcher
$controller->dispatch();
?>

Le fichier CommentController

Ce fichier contient 2 actions importantes :

  • displayAction : action qui redirige vers l'affichage des commentaires
  • editAction : action qui
    • Affiche le formulaire si aucune donnée POST n'est envoyée
    • Enregistre le commentaire en base de donnée si une donnée POST est envoyée (puis affiche la liste des commentaires)

Etudions ces actions dans le détail :

  • displayAction
    • Cette action ne fait aucun traitement. Elle se contente d'appeler le fichier (la vue) d'affichage des commentaires (comment/display.phtml)
  • editAction
    • Si aucun formulaire n'a été validé (pas de donnée $_POST envoyée)
      • on affiche simplement la vue du formulaire (comment/edit.phtml)
    • Si un formulaire a été validé
      • On valide les champs du formulaire
        • On valide l'adresse email avec la classe Zend_Validate_EmailAddress
        • On filtre les champs subject et content pour éviter les codes javascript ou autres faille de sécurité. Pour ça on utilise Zend_Filter_StripTags
      • On charge la le modèle de l'application (Kitpages_Tutoriaux_Facade) qui s'occupe des sauvegardes en base de données. Nous y reviendrons plus tard.
      • On fait une redirection vers la page d'affichage des commentaires.
        • Notons que faire une redirection au lieu d'afficher directement la vue permet de pouvoir ensuire faire un "back" sans que le navigateur ne nous demande si on veut renvoyer le POST...

 

<?php
Zend_Loader::loadClass("Zend_Controller_Action");
Zend_Loader::loadClass("Zend_Validate_EmailAddress");
Zend_Loader::loadClass("Zend_Filter_StripTags");
 
class CommentController extends Zend_Controller_Action {
 
    public function displayAction() {
        Zend_Loader::loadClass("Kitpages_Tutoriaux_Facade");
        $commentList = Kitpages_Tutoriaux_Facade::
            getInstance()->getAllComments();
        $this->view->commentList = $commentList;
        $this->view->rootUrl = ROOT_URL;
    }
 
    public function editAction() {
        // vérifie l'existence d'un post :
        if (count($_POST) > 0) {
            // validation de l'email
            $email = $_POST["email"];
            $validator = new Zend_Validate_EmailAddress();
            if (!$validator->isValid($email)) {
                $this->_redirect(
                    "comment/edit?error=email+invalide"
                );
            }
            // filtre du sujet et du contenu
            $filter = new Zend_Filter_StripTags(array("b","em"));
            $subject = $filter->filter($_POST["subject"]);
            $content = $filter->filter($_POST["content"]);
            // sauvegarde
            Zend_Loader::loadClass('Kitpages_Tutoriaux_Facade');
            $facade = Kitpages_Tutoriaux_Facade::getInstance();
            $facade->saveComment($email,
                                 $subject,
                                 $content);
            // redirection
            $url = ROOT_URL."/comment";
            Zend_Registry::get("logger")
                ->debug("before redirection, url=$url");
            $this->_redirect($url);
        }
    }
}
?>

Vue 1 : le formulaire

C'est une vue on ne peut plus simple..., juste de l'html...

Fichier : comment/edit.phtml

<html>
<head>
    <title>Tutoriaux Kitpages</title>
</head>
<body>
<p><?php if (isset($_GET["error"])) {echo $_GET["error"];} ?></p>
Saisir son commentaire<br/>
<form action="<?php echo ROOT_URL ?>/comment/edit" method="POST">
    Email : <input type="text" name="email"/><br>
    Sujet : <input type="text" name="subject"/><br>
    Contenu : <textarea name="content"></textarea><br>
    <input type="submit" value="valider"/>
</form>
</body>
</html>

Vue 2 : l'affichage des commentaires

Fichier permettant d'afficher les commentaires. Cette vue utilise le modèle (classe Kitpages_Tutoriaux_Facade) pour aller chercher en base de données la liste des commentaires. Nous y reviendrons plus tard.

Fichier : comment/display.phtml

<html>
<head>
    <title>Tutoriaux Kitpages</title>
</head>
<body>
commentaires :<br>
<a href="<?php echo $this->rootUrl;?>/comment/edit">
Ajouter un commentaire
</a>
<hr/>
<?php foreach ($this->commentList as $comment) { ?>
<b><?php echo $comment["subject"]; ?> </b>-
<?php echo $comment["email"]; ?><br/>
<?php echo $comment["content"]; ?>
<hr/>
<?php } ?>
</body>
</html>

Modèle : Kitpages_Tutoriaux_Facade

Ce paragraphe est intéressant à 2 niveaux :

  • Il montre comment se servir des bases de données avec le Zend Framework
  • Il montre comment organiser ses classes pour qu'elles soient accesibles de la même façon que les classes du Zend Framework

Le code est donnée ci dessous, nous allons le commenter plus ou moins dans l'ordre.

  • On inclu les classes de bases de données du zend Framework
  • Le include_path de l'application va jusqu'à PHP-INF/model . Nous avons ensuite créé les répertoire Kitpages/Tutoriaux/ et nous avons mis le fichier Facade.php dedans. Nous avons ensuite appelé la classe Kitpages_Tutoriaux_Facade. Tout celà permet de charger la classe dans un autre fichier avec la fonction Zend_Loader::loadClass("Kitpages_Tutoriaux_Facade"); (ça remplace un include_once...)
  • La classe en question est un singleton. C'est à dire qu'on impose le fait qu'il y ait une et une seule instance de la classe en même temps. Cette instance unique se récupère en appelant Kitpages_Tutoriaux_Facade::getInstance()
  • la méthode getZendDb crée une connexion vers la base de données et la renvoie (Création d'une connexion)
  • saveComment(xxx) enregistre un commentaire dans la base de données (Insertion en base)
  • getAllComments() renvoie la liste des commentaires dans l'ordre chronologique (Selection de lignes)

Les liens vers la doc du Zend Framework vont vous aider à comprendre le code, mais surtout ont pour objectif de vous habituer à la consulter...

<?php
/*
 * Created on 13 juil. 06
 *
 * @author Philippe Le Van (http://www.kitpages.fr)
 * @copyright 2005-2006
 */
include_once "Zend/Db.php";
 
class Kitpages_Tutoriaux_Facade {
    ////
    // singleton management
    ////
    static private $_instance = null;
    private function __construct() {
    }
    static public function getInstance() {
        if (!self::$_instance instanceof self) {
           self::$_instance = new self();
        }
        return self::$_instance;
    }
    
    ////
    // connexion management
    ////
    private $db = null;
    public function getZendDb() {
        if ($this->db == null) {
            $params = array(
                'host'     => DB_SERVER ,
                'username' => DB_USER ,
                'password' => DB_PASSWORD ,
                'dbname'   => DB_NAME
            );
            $this->db = Zend_Db::factory(DB_TYPE,$params);
        }
        return $this->db;
    }
    
    /**
     * save comments
     * Note : pas besoin de s'occuper 
des echapements, c'est pris en charge
     */
    public function saveComment($email,$subject,$content) {
        $db = $this->getZendDb();
        $valueArray = array("email"=>$email,
                            "subject"=>$subject,
                            "content"=>$content);
        $rows_affected = $db->insert("comment", $valueArray);
        return $db->lastInsertId();
    }
    
    /**
     * get all comments
     */
    public function getAllComments() {
        $db = $this->getZendDb();
        $select = $db->select();
        $select->from("comment", array(
                "id","email","subject","content"));
        $select->order("id DESC");
        return $db->fetchAll($select);
    }
}
?>

Comment lancer tout ça ?

Une fois que tout est installé, les URL à aller voir sont les suivantes :

http://localhost/Tutoriaux/comment/display : pour voir la liste des messages

http://localhost/Tutoriaux/comment/edit : pour ajouter un message

(ces URL sont définies dans index.php quand j'ajoute une route au routeur).

Conclusion

L'esprit du controlleur a pas mal changé avec la version 1.0.0-RC1. Ce tutorial a été remis à jour le 15 juin pour refléter ces évolutions. Nous utilisons effectivement le ViewRenderer et l'arborescence standard du Zend Framework.

C'est un peu indigeste tout ça me direz-vous... Je ne peux pas vous contredire, mais quand on a codé des dizaines de sites, on se rend compte que c'est utile....

En attendant, vous pouvez télécharger les sources ici

Encore une fois, n'hésitez pas à m'envoyer vos commentaires.

Pour aller plus loin, la documentation du Zend Framework est bien faite et traduite en français (en grande majorité du moins...). Vous pourrez regarder notamment comment générer un PDF, créer des flux RSS, envoyer des mails...

Commentaires

Ajouter un commentaire
recherche tuto pour la version 2
J'ai réalisé ceci, pour mon projet réel je voudrais démarrer avec zendframework 2.x si possible?
Je parcours les tutos ZF de temps en temps et je suis souvent tombé sur celui-ci. Dommage qu'il ne soit vraiment plus à jour, même si certaines bases restent les mêmes. Une mise à jour est-elle prévue ?
Si ça intéresse, je parle de ZF1.11 sur www.alcides-notes.ijintek.fr.