Tag Archives

3 Articles
Introduction au ZF – Partie 5 : Doctrine

Introduction au ZF – Partie 5 : Doctrine

Pour les Models, je pensais vous montrer l’exemple concret de l’usine à gaz présentée par Zend. Mais vu que le Zend Framework 2.0 va le changer pour doctrine, j’ai décidé de passer dessus. Doctrine a plusieurs points positifs :

  • Il utilise PDO donc il y a toujours une couche d’abstraction
  • Il génère automatiquement les models (si on utilise l’utilitaire)
  • Il est plus performant que Zend_Db
  • Tout est objet
  • Conforme au pattern MVC

Pour ces raisons, Doctrine semble être le choix le plus judicieux. Maintenant il ne reste plus qu’à l’intégrer à notre projet. Pour informations, j’utilise la version 1.2.2 de Doctrine qui est la dernière version stable en date. Vous pouvez la récupérer à cette adresse.

Je vous conseil aussi d’avoir la documentation officielle sous le bras pour bien comprendre tout ce qu’il va se dire ici. Avant de continuer, voici la base de donnée finale que nous allons utiliser tout au long de ce tutoriel. Je mets le contenu final ici pour que l’on génère les Models complets dès le début.

C’est avec une application bien pensée qu’on arrive à un bon résultat.

Et voici maintenant le script avec un utilisateur par défaut. Le mot de passe décrypté est azerty.

SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;

--
-- Base de données: `tutosite`
--
CREATE DATABASE `tutosite` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
USE `tutosite`;

-- --------------------------------------------------------
--
-- Structure de la table `article`
--

CREATE TABLE IF NOT EXISTS `article` (
  `idArticle` int(11) NOT NULL AUTO_INCREMENT,
  `idUtilisateur` int(11) NOT NULL,
  `idRubrique` int(11) NOT NULL,
  `titre` varchar(45) NOT NULL,
  `corps` text NOT NULL,
  `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`idArticle`),
  KEY `fk_Article_Utilisateurs` (`idUtilisateur`),
  KEY `fk_Article_Rubrique` (`idRubrique`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

--
-- Contenu de la table `article`
--
-- --------------------------------------------------------
--
-- Structure de la table `commentaire`
--

CREATE TABLE IF NOT EXISTS `commentaire` (
  `idCommentaire` int(11) NOT NULL AUTO_INCREMENT,
  `idArticle` int(11) NOT NULL,
  `pseudo` varchar(45) NOT NULL,
  `email` varchar(45) DEFAULT NULL,
  `message` text NOT NULL,
  `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`idCommentaire`),
  KEY `fk_Commentaire_Article` (`idArticle`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

--
-- Contenu de la table `commentaire`
--
-- --------------------------------------------------------
--
-- Structure de la table `rubrique`
--

CREATE TABLE IF NOT EXISTS `rubrique` (
  `idRubrique` int(11) NOT NULL,
  `Nom` varchar(45) NOT NULL,
  PRIMARY KEY (`idRubrique`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--
-- Contenu de la table `rubrique`
--
-- --------------------------------------------------------
--
-- Structure de la table `tag`
--

CREATE TABLE IF NOT EXISTS `tag` (
  `idTag` int(11) NOT NULL,
  `Nom` varchar(45) NOT NULL,
  `Couleur` varchar(7) NOT NULL DEFAULT '#000000',
  `Hicolor` varchar(7) NOT NULL DEFAULT '#000000',
  PRIMARY KEY (`idTag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--
-- Contenu de la table `tag`
--
-- --------------------------------------------------------
--
-- Structure de la table `tagarticle`
--

CREATE TABLE IF NOT EXISTS `tagarticle` (
  `idTag` int(11) NOT NULL,
  `idArticle` int(11) NOT NULL,
  PRIMARY KEY (`idTag`,`idArticle`),
  KEY `fk_Tag_has_Article_Tag` (`idTag`),
  KEY `fk_Tag_has_Article_Article` (`idArticle`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

--
-- Contenu de la table `tagarticle`
--
-- --------------------------------------------------------
--
-- Structure de la table `utilisateurs`
--

CREATE TABLE IF NOT EXISTS `utilisateurs` (
  `idutilisateur` int(11) NOT NULL AUTO_INCREMENT,
  `login` varchar(50) NOT NULL,
  `passwd` varchar(100) NOT NULL,
  PRIMARY KEY (`idutilisateur`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;

--
-- Contenu de la table `utilisateurs`
--

INSERT INTO `utilisateurs` (`idutilisateur`, `login`, `passwd`) VALUES
(1, 'admin', 'ab4f63f9ac65152575886860dde480a1 ');

--
-- Contraintes pour les tables exportées
--
--
-- Contraintes pour la table `article`
--
ALTER TABLE `article`
  ADD CONSTRAINT `fk_Article_Rubrique` FOREIGN KEY (`idRubrique`) REFERENCES `rubrique` (`idRubrique`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  ADD CONSTRAINT `fk_Article_Utilisateurs` FOREIGN KEY (`idUtilisateur`) REFERENCES `utilisateurs` (`idutilisateur`) ON DELETE NO ACTION ON UPDATE NO ACTION;
--
-- Contraintes pour la table `commentaire`
--
ALTER TABLE `commentaire`
  ADD CONSTRAINT `fk_Commentaire_Article` FOREIGN KEY (`idArticle`) REFERENCES `article` (`idArticle`) ON DELETE NO ACTION ON UPDATE NO ACTION;

Voilà pour la partie base de données SQL. Maintenant nous allons nous attaquer à la configuration. Nous allons tout d’abord créer les répertoires suivants :

  • Dossier contenant les données des tables en script YAML générés par Doctrine /application/configurations/data/fixtures
  • Dossier contenant les scripts SQL générés par Doctrine /application/configurations/data/sql
  • Dossier de migration de la base de données /application/configurations/migration
  • Dossier contenant le script de génération des cmodels /application/scripts
  • Dossier contenant nos models générés /library/App/Models

Quand la création des dossiers est faite, vous allez télécharger Doctrine 1.2.2. La version sandbox est inutile ici vu que les scripts donnés pour la génération doivent être complètement refait pour Zend.

Lorsque vous avez téléchargé Doctrine, vous allez extraire son contenu dans /library. Vous devriez alors avoir le dossier /library comme la capture sur votre droite. Le dossier vendor permet d’utiliser les scripts YAML quand au dossier Doctrine, il contient tout le cœur de Doctrine.

Maintenant que Doctrine a été correctement ajouté au dossier Library, Que la base de donnée a bien été ajoutée au SGBD, nous pouvons passer à la suite qui va consister à configurer proprement Zend.

Tout d’abord, nous allons rajouter les lignes suivantes au fichier /application/configurations/app.ini

; ---
; Doctrine
; ---

; configuration de base
; Le dsn correspond aux infos de connexion. Ici nous appelons une base mysql
; SGBD : MySqL
; Login : Root
; Password : azerty //si aucun password mettre juste root@localhost/bdd
; Serveur : localhost
; BDD : tutosite
doctrine.dsn                = "mysql://root:azerty@localhost/tutosite"
doctrine.data_fixtures_path = APPLICATION_PATH "/configurations/data/fixtures"
doctrine.sql_path           = APPLICATION_PATH "/configurations/data/sql"
doctrine.migrations_path    = APPLICATION_PATH "/configurations/migrations"
doctrine.yaml_schema_path   = APPLICATION_PATH "/configurations/schema.yml"
doctrine.models_path = APPLICATION_PATH "/../library/App/Models"

; règles lors de la génération des classes
; on utilise la convention de nommage PEAR
doctrine.generate_models_options.pearStyle  = true
; on génère les classes de table
doctrine.generate_models_options.generateTableClasses  = true
; on génère les classes de base. Ces classes contiennent les définitions de nos tables
doctrine.generate_models_options.generateBaseClasses  = true
; on définit un préfixe pour les classes de base
doctrine.generate_models_options.baseClassPrefix  = "Base_"
; on ne pet rien ici, avec la convention pear, ils seront ajoutés dans le sous dossier Base
doctrine.generate_models_options.baseClassesDirectory  =
; on ne met pas le préfixe au nom de fichier
doctrine.generate_models_options.classPrefixFiles  = false
; toutes les classes commenceront par ce préfixe
doctrine.generate_models_options.classPrefix = "App_Models_"

Ensuite, nous allons nous intéresser au /application/Bootstrap.php et nous allons ajouter la fonction d’initialisation de Doctrine :

protected function _initDoctrine() 
{
    //on met Doctrine en autoload
    $this->getApplication()
         ->getAutoloader()
         ->pushAutoloader ( array ('Doctrine', 'autoload' ) );
    spl_autoload_register(array('Doctrine', 'modelsAutoload'));

    //on récupère une instance de Doctrine
    $manager = Doctrine_Manager::getInstance ();

    //permet de valider automatiquement l'intégrité des données
    //ce qui veut dire que l'on ne peut pas mettre une variable de type string
    //dans une variable de type int.
    $manager->setAttribute (Doctrine::ATTR_VALIDATE, Doctrine::VALIDATE_ALL);
    //l’AUTO_ACCESSOR_OVERRIDE va nous permettre de personnaliser l’assignation de données.
    $manager->setAttribute ( Doctrine::ATTR_AUTO_ACCESSOR_OVERRIDE, true );
    //Doctrine permet de personnaliser également les classes de table en permettant 
    //de créer des méthodes propres à une table. 
    //Ce paramètre permet de charger le fichier contenant nos méthodes personnalisées.
    $manager->setAttribute (
     Doctrine::ATTR_MODEL_LOADING, 
     Doctrine::MODEL_LOADING_CONSERVATIVE
    );
    //on permet le chargement des classes table
    $manager->setAttribute ( Doctrine::ATTR_AUTOLOAD_TABLE_CLASSES, true );

    //on récupère toutes les options doctrine du fichier app.ini
    $doctrineConfig = $this->getOption('doctrine');

    //on récupère la variable doctrine.models_path du fichier app.ini
    //afin d'avoir le répertoire des models
    //pour que Doctrine les charge
    Doctrine::loadModels($doctrineConfig['models_path']);

    //on récupère la connexion à mysql et on la nomme doctrine
    $conn = Doctrine_Manager::connection($doctrineConfig['dsn'],'doctrine');
    //je sais plus ce que sa veut dire, mais il le faut
    $conn->setAttribute(Doctrine::ATTR_USE_NATIVE_ENUM,true);

    //on définit la sortie encodée en UTF-8
    $conn->setCharset('utf8');
    $conn->setCollate('utf8_general_ci');

    //on retourne la connexion
    return $conn;
}

Et pour que tout soit chargé directement, il suffit d’ajouter ces lignes dans la fonction _initNamSpaces() :

$autoloader->registerNamespace('Doctrine_');
$autoloader->registerNamespace('Doctrine');

Bien, maintenant Doctrine est correctement intégré à notre framework. Il ne reste plus qu’à générer les classes. Pour ce faire, il nous fait le fichier script suivant /application/scripts/Doctrine.php :

// Define path to application directory
defined('APPLICATION_PATH')
    || define('APPLICATION_PATH',
              realpath(dirname(__FILE__) . '/..'));

// Define application environment
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV',
              (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV')
                                         : 'production'));

// Typically, you will also want to add your library/ directory
// to the include_path, particularly if it contains your ZF install
set_include_path(implode(PATH_SEPARATOR, array(
    realpath(APPLICATION_PATH . '/../library'),
    get_include_path(),
)));

require_once 'Doctrine.php';

/** Zend_Application */
require_once 'Zend/Application.php';

// Create application, bootstrap, and run
$application = new Zend_Application(
    APPLICATION_ENV,
    APPLICATION_PATH . '/configurations/app.ini'
);

$application->getBootstrap()->bootstrap('doctrine');
$config = $application->getOption('doctrine');

$cli = new Doctrine_Cli($config);
$cli->run($_SERVER['argv']);

Vous l’aurez sans doute deviné, il s’agit du fichier /public/index.php avec à la fin l’instanciation de Doctrine. Cette instanciation nous permet d’utiliser, par le biais de la ligne de commande, Doctrine et, ainsi, générer nos classes.

Pour ce faire, allez dans votre invite de commande et rendez vous dans le dossier qui contient le script. Tapez juste la commande suivante :

php Doctrine.php

Elle devrait vous retourner le résultat suivant :

Il ne nous reste plus qu’à taper la commande :

php doctrine.php generate-models-db
php doctrine.php generate-yaml-db

Dans le dossier /application/configurations/ nous trouverons le dossier schema.yml contenant le script YAML de notre base de données. Et maintenant, si nous regardons dans le dossier /library/App/Models, nous avons pleins de classes de créées.

Prenons par exemple la table Utilisateurs. Elle aura 3 classes dédiées :

  • App_Models_Utilisateurs : permet de définir des fonction sur un objet utilisateur
  • App_Models_UtilisateursTable : permet de définir les différentes requêtes à faire sur notre table
  • App_Models_Base_Utilisateurs : contient la définition de la table Utilisateurs.

Justement, afin de tester et de bien comprendre ces classes, nous allons ajouter une fonction à la classe App_Models_UtilisateursTable. La fonction en question n’est rien d’autre qu’un fetchAll permettant de faire un Select de base.

/**
 * Select de base
 * 
 * @param string $where
 * @param string $order
 * @param int $limit
 * @param int $offset
 * @return Collection
 */
 public function fetchAll($where=null, $order=null, $limit=null, $offset=null)
 {
     $select = Doctrine_Query::create()->select('*')
         //dans le from on met le nom de la classe
         //Doctrine s'occupe du reste
         ->from('App_Models_Utilisateurs');

     if(isset($where)){ $select->where($where); }
     if(isset($order)){ $select->orderBy($order); }
     if(isset($limit)){ $select->limit($limit); }
     if(isset($offset)){ $select->offset($offset); }

     return $select->execute();
 }

Ensuite pour utiliser cette requête, nous allons éditier le controller Admin_AccueilController. Dans d’action d’index ajoutez les lignes suivantes :

//on récupère la classe table de App_Models_Utilisateurs
$table = Doctrine_Core::getTable('App_Models_Utilisateurs');
//on liste tout le monde
$liste = $table->fetchAll();
//on traite le résultat
foreach($liste as $unuser)
{
    print_r($unuser->login);
    print_r($unuser->passwd);
}

Normalement, si vous vous rendez sur la page concernée, vous devriez voir afficher le login et le mot de passe des utilisateurs. Voilà, maintenant vous pouvez utiliser Doctrine au sein du Framework Zend. La prochaine fois, nous verrons la création des premiers articles de notre Blog.

Introduction au Framework Zend – Partie 4

Chose promise, chose due, malgré une semaine de retard, je vous offre la suite du tutoriel Zend sur la création d’un blog. Aujourd’hui, il va s’agir de la partie authentification de l’administrateur.

Je vais donc commencer par vous montrer la création d’un nouveau module (module admin). Ensuite je vais vous montrer la création d’un formulaire avec Zend (il faut bien vous identifier quelque part non ?) et pour finir, nous allons entrer dans les détails de l’authentification par base de données.

Tout d’abord, reprenez le projet concernant cette suite de sujets et créez le module admin basée sur la structure montrée lors du précédent sujet (organisation des dossiers). Pour qu’un module autre que default marche, il faut lui créer un bootstrap de module permettant de charger ses models, ses formulaires et surtout ses contrôleurs.

Comme vous pouvez le voir, toutes les classes du module admin commencent par le Namespace Admin_, ceci est normal et permet à Zend de trouver facilement vos classes. Si vous oubliez cette information, Zend vous retournera une erreur comme quoi il ne trouve pas vos classes. Faites donc attention.
Dans le Bootstrap aussi vous devez renseigner le Namespace utilisé. Si il diffère de celui renseigné au début du nom de vos classes, vous aurez le droit à la même erreur.

/application/modules/admin/Bootstrap.php :

class Admin_Bootstrap extends Zend_Application_Module_Bootstrap
{  
    protected function _initAutoload()
    {
        $moduleLoader = new Zend_Application_Module_Autoloader(array(
            'namespace' => 'Admin_',
            'basePath'  => APPLICATION_PATH . '/modules/admin'));
        $moduleLoader->addResourceType('Models', 'models', 'Models');
        $moduleLoader->addResourceType('Forms', 'forms', 'Forms');
        return $moduleLoader;
    }
}

Afin de tester si notre module marche bien, nous allons ajouter l’IndexController et la vue associée à l’indexAction : /application/modules/admin/controllers/IndexController.php

class Admin_IndexController extends Zend_Controller_Action 
{
    public function indexAction() {
        $this->view->title="Authentification utilisateur";
    }
}

/application/modules/admin/views/scripts/index/index.phtml

<h3>Authentification</h3>

Normalement, si vous tapez http://localhost/tutosite.com/admin, vous devriez tomber sur La page suivante :

Je vous dis félicitation, vous venez de créer votre premier module pour le site. Maintenant, nous allons nous attaquer à quelque-chose de plus dur. La création du formulaire d’authentification.

Il faut savoir que dans la classe Zend_form, un élément comprend la légende et l’élément input. On peut aussi rajouter certains filtres et des validateurs pour automatiser des traitements rébarbatifs en PHP (combien ont fait des tests sur des $_POST).

Pour l’authentification, je prends les deux champs traditionnels : Login et Password. Le login ne sera pas une adresse E-Mail mais un pseudo. Je vous le dis pour le choix des validateurs. Si vous choisissez un e-mail, vous pouvez rajouter un validateur d’adresse e-mail qui accepte vos infos si et seulement si votre email a une structure valide (a@a.a). Vous pouvez aller plus loin en vérifiant que le nom de domaine existe bien (hotmail.com validé alors qu’azdfes.azdf est refusé).

Je vais donc vous montrer la classe formulaire que j’utilise sans trop rentrer dans les détails. La documentation explique beaucoup mieux que moi. Je vous expliquerais juste l’utilité des filtres et des validateurs que j’utilise.

/application/modules/admin/forms/Identification.php

class Admin_Forms_Identification extends Zend_Form 
{ 
    public function init()
    {
        $this ->setMethod('post')
              ->setName('identification'); 

        $login = new Zend_Form_Element_Text('login');
        $login ->setLabel('Identifiant')
               ->setRequired(TRUE)
               ->addFilters(array('StringTrim', 'StripTags'))
               ->addValidators(array( array('validator' => 'StringLength', 'options' => array(0, 20))))
               ->getDecorator('label')->setOption('tag', null);

        $passwd = new Zend_Form_Element_Password('password');
        $passwd ->setLabel('Mot de Passe')
                ->setRequired(TRUE)
                ->addFilters(array('StringTrim', 'StripTags'))
                ->addValidators(array( array('validator' => 'StringLength', 'options' => array(0, 20))))
                ->getDecorator('label')->setOption('tag', null);

        $submit = new Zend_Form_Element_Submit('submit');
        $submit ->setLabel('Connexion')
                ->setIgnore(true);

        $this->addElement($login);
        $this->addElement($passwd);
        $this->addElement($submit);

        $this->setDecorators(array(
            array('ViewScript', array('viewScript' => 'identification.phtml'))
        ));
    }
}

Tout d’abord, les filtres que j’utilise servent à limiter la casse et les injections de code (même si Zend ne permet pas ce genre de choses. Striptags permet d’enlever de notre variable toutes les balises de code afin d’éviter les injections JavaScript par exemple. Le filtre StringTrim quand à lui permet de supprimer les espaces en trop en début et en fin de notre variable afin de ne pas tricher sur le nombre de caractères requis. Ensuite le validateur StringLength quand à lui permet de définir le nombre min/max de caractères requis pour valider le formulaire.

Pour les décorateurs, j’ai décidé de passer par une vue externe afin de définir ma propre présentation. Cela permet une meilleure flexibilité de présentation e nos formulaires. Je trouve que les décorateurs sont trop complexes et limités mais en même temps, je suis nul avec. Pour pouvoir faire ce que je veux, j’ai donc désactivé les balises mises par défaut autour de notre élément.

Comme je vous l’ai expliqué, j’utilise un script de vue pour mettre en forme mon formulaire. Je vous le fournis bien entendu pour que vous puissiez voir comment cela marche.

/application/modules/admin/views/scripts/identification.phtml

<form action="<?php echo $this->escape($this->element->getAction()); ?>"         
      method="<?php echo $this->escape($this->element->getMethod()); ?>"         
      class="formident">         

    <p>Vous devez vous identifier pour accéder au backoffice.</p>        
    <div>        
        <span class="labelform"><?php echo $this->element->login->renderLabel(); ?></span>       
        <span><?php echo $this->element->login->renderViewHelper(); ?></span>        
    </div>       
    <div>        
        <span class="labelform"><?php echo $this->element->password->renderLabel(); ?></span>        
        <span><?php echo $this->element->password->renderViewHelper(); ?></span>         
    </div>       
    <?php echo $this->element->submit->renderViewHelper(); ?>                
</form>

Pour pouvoir afficher notre vue, nous ajoutons juste ces lignes pour le moment dans notre contrôleur :

$form = new Admin_Forms_Identification();
$this->view->form = $form;
$this->view->message = null;

Et dans notre vue, juste ces ligne :

<?php 
    if(!empty($this->message))
    {
?>
<div class="warning"><?php echo $this->message; ?></div>
<?php  
    }
    $this->form->setAction($this->url());
    echo $this->form;
    echo md5(azerty);

Voici le rendu final de notre vue :

En ajoutant le code css suivant à notre style, nous pouvons obtenir le résultat suivant :

/**
 * Formulaire authentification
 */
.formident{
    text-align: center;
}
.formident div{
    margin-top: 3px;
    margin-bottom: 3px;
    position: relative;
    width: 300px;
    margin-left: 330px;
} 
.formident div .labelform{
    width: 100px;
    display:block;
    float: left;
    text-align: left;
}

Alors ? Ce n’est pas sympa ce que l’on peut faire ? Nous pouvons aussi rajouter des images et des effets visuels sympas, mais ce n’est pas le but de cet article.

Bien, maintenant nous pouvons enfin attaquer le vif du sujet : L’authentification.

Comme je vous l’ai expliqué, nous allons authentifier notre utilisateur par une base de données. Je vais donc vous fournir le script de la base avec la table utilisateur. Je vais me baser dessus pour tous les autres articles du tutoriel.

CREATE DATABASE `tutosite` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci;
USE `tutosite`;
CREATE TABLE IF NOT EXISTS `utilisateurs` (
    `idutilisateur` int(11) NOT NULL AUTO_INCREMENT,
    `login` varchar(50) NOT NULL,
    `passwd` varchar(100) NOT NULL,
PRIMARY KEY (`idutilisateur`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

Bien évidemment, nous devons toucher les fichiers de configuration Zend pour pouvoir nous connecter à la base de donnée :

; Base de donnée
resources.db.adapter = PDO_MYSQL
resources.db.params.charset = UTF8
resources.db.params.host = localhost
resources.db.params.username = root
resources.db.params.password = passwd
resources.db.params.dbname = tutosite
resources.db.isDefaultTableAdapter = true

Voilà, maintenant que la connexion à la base de données fonctionne, voici les étapes à rajouter dans l’indexController->indexAction() pour s’identifier. J’ai commenté chaque ligne afin que vous ayez directement les explications :

if($this->_request->isPost())
{
    //on récupère le login
    $username = $this->_request->getPost('login');
    //on récupère le password  
    $password = $this->_request->getPost('password'); 

    if (empty($username)) 
    {
        $this->view->message = 'Veuillez saisir un identifiant';
    } 
    else
    {
        //on récupère la connexion à la base de donnée
        $dbAdapter = Zend_Db_Table::getDefaultAdapter();
        //récupération de l'adaptateur dbAdapter 
        $authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);
        //on indique le nom de la table 
        $authAdapter->setTableName('utilisateurs'); 
        //on indique la colonne du login 
        $authAdapter->setIdentityColumn('login');
        //on indique la colonne du mot de passe 
        $authAdapter->setCredentialColumn('passwd');
        //on dit que les mots de passes sont hashés en MD5
        $authAdapter->setCredentialTreatment('MD5(?)'); 

        //ajout des données du formulaire pour l'authentification
        $authAdapter->setIdentity($username);
        $authAdapter->setCredential($password);

        //lancement de l'authentification
        $auth = Zend_Auth::getInstance()->setStorage(new Zend_Auth_Storage_Session('admin'));
        $result = $auth->authenticate($authAdapter);

        if ($result->isValid()) 
        {
            //succès: on stoque dans un objet sessions toutes les infos de la ligne
            //de la table sauf le mot de passe pour des raisons de sécurité.
            $data = $authAdapter->getResultRowObject(null, 'password');
            $auth->getStorage()->write($data);
            //on redirige vers notre page admin
            $this->_redirect('/admin/accueil');
        } 
        else 
        {
            //failure: clear database row from session
            $this->view->message = "Echec de l'identification";
        } 
    }
}

Avant de tester ceci, sachez que nous allons être redirigés vers un nouveau contrôleur du module admin. Pour éviter à quelqu’un de non authentifié d’accéder à ce contrôleur, j’initialise la fonction preDispatch() qui permet d’effectuer des réglages avant la fin de l’initialisation du contrôleur.
/application/modules/admin/controllers/AccueilController.php :

class Admin_AccueilController extends Zend_Controller_Action 
{ 
    public function preDispatch()
    {
        $auth = Zend_Auth::getInstance()->setStorage(new Zend_Auth_Storage_Session('admin'));

        if (!$auth->hasIdentity()) {
            $this->_redirect('/admin/index');
        }
    }

    /**
     * The default action - show the home page
     */
    public function indexAction() 
    {
        $this->view->title = "Partie Administration - Accueil";
    }
}

/application/modules/admin/views/scripts/accueil/index.phtml

Partie Admin, vous êtes authentifiés.</code> Maintenant votre authentification est optionnelle. 

Pour vous déconnecter, il suffit de faire un lien vers l’action déconnexion de l’IndexController par exemple et qui serait comme ceci :

public function logoutAction()
{
    Zend_Auth::getInstance()->setStorage(new Zend_Auth_Storage_Session('admin'))->clearIdentity();
    $this->_redirect('/admin/index');
}

Pour éviter de tomber sur le formulaire d’identification, vous pouvez rajouter ceci autour de toutes les lignes de codes d’indexAction() afin d’arriver directement sur l’accueil admin :

$ident = Zend_Auth::getInstance()->setStorage(new Zend_Auth_Storage_Session('admin'))->getIdentity(); 
if($ident){
    $this->_redirect('/admin/accueil');
}else{
    //code authentification
}
Pour les mots de passe créez une page php de base avec juste un echo md5(‘motdepasse’) ; et après insérez votre nouvel utilisateur avec, comme mot de passe, celui qui vient d’être généré.

Voilà. Maintenant vous pouvez vous authentifier et rajouter d’autres utilisateurs à votre base de données. La prochaine fois, nous verrons les classes métiers et table_abstract pour ajouter nos premiers articles.

Validateur de dates

Certains d’entre vous ont voulu à plusieurs reprises faire un formulaire avec différents champs de Dates. L’une devant être inférieure à l’autre comme une date d’emménagement et de déménagement.

Bien évidement, le framework Zend a pensé à tout ceci avec le composant Zend_Date mais n’a pas pensé aux formulaires. Il n’y a pas de validateur connu (pour le moment) servant à ceci.

C’est pourquoi, dans le but d’en avoir un sous la main et aussi car j’en avais surtout besoin, je créai un validateur de dates. Il me permet de différencier deux champs contenant une date (de préférence des datepickers jQuery ou Dojo) et dire si oui ou non la date 1 est plus ancienne que la date 2.

Voici d’ailleurs le code du validateur:
/**
* App_Validate_Date
*
* Classe servant à faire la différene entre 2 dates
*
* Retournera True si valide
* False si faux
*
*/
class App_Validate_Date extends Zend_Validate_Abstract
{
const FALSEDATE = "falseDate";
const ILLEGALDIFF = "illegalDiff";

protected $_messageTemplates = array(
self::FALSEDATE =>
"False Date: L'une des dates est invalide",
self::ILLEGALDIFF =>
"ILLEGAL DIFF: La date d'emmenagement est plus récente que la date de déménagement"
);

/**
* la date de départ
*
* @var unknown_type
*/
protected $_date;

/**
* sert à instancier le validateur
*
* @param unknown_type $date
*/
public function __construct($date)
{
$this->setdate($date);
}

/**
* @return unknown_type
*/
public function getdate()
{
return $this->_date;
}

/**
* Setteur = initialiser la variable avec celle passée en paramètre
* @param unknown_type $_date
*/
public function setdate($_date)
{
$this->_date = $_date;
}

public function isValid($value)
{
$this->_setValue($value); //à laisser obligatoirement

if(Zend_Date::isDate($value, 'dd/mm/yy', 'fr_FR') && Zend_Date::isDate($this->_date, 'dd/mm/yy', 'fr_FR'))
{
$datevalue = new Zend_Date($value, 'fr_FR'); //on instancie une date de la valeur
$datedate = new Zend_Date($this->_date, 'fr_FR'); //on instancie la date

$testdate = $datedate->sub($datevalue);

if($testdate < 0) { return true; } else { $this->_error(self::ILLEGALDIFF);
return false;
}
}
else
{
$this->_error(self::FALSEDATE);
return false;
}

}

}
Pour l’utiliser, je n’ai pu le faire que du côté contrôleur. Il faut bien récupérer les deux valeurs après avoir posté le forum. Et voici donc les étapes à effectuer pour que cela marche.
if($this->_request->isPost())
{
$formdata = $this->_request->getPost();

$validator = new Zend_Validate(); //créer un validateur vide
$validator->addValidator(new Zend_Validate_Date('dd/mm/yy', 'fr_FR')); //ajout du validateur de verif date en 1°
$validator->addValidator(new App_Validate_Date($this->_request->getPost('date_debut'))); //ajoute le validateur de diff date en second

$form->date_fin->addValidator($validator); //ajoute la chaine de validateur afin de tous les verifier

if($form->isValid($formdata)) // ce isvalid appelle le isvalide du formulaire pour exécuter à la chaine tous les validateurs
{
//suite du traitement du formulaire
}
}

J’espère que ce validateur vous aidera dans vos projets. Si vous comptez l’améliorer, prévenez moi en m’envoyant les améliorations apportées.