19
2010
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.
| SQL | | copy code | | ? |
| 001 | SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; |
| 002 | |
| 003 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; |
| 004 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; |
| 005 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; |
| 006 | /*!40101 SET NAMES utf8 */; |
| 007 | |
| 008 | -- |
| 009 | -- Base de données: `tutosite` |
| 010 | -- |
| 011 | CREATE DATABASE `tutosite` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; |
| 012 | USE `tutosite`; |
| 013 | |
| 014 | -- -------------------------------------------------------- |
| 015 | -- |
| 016 | -- Structure de la table `article` |
| 017 | -- |
| 018 | |
| 019 | CREATE TABLE IF NOT EXISTS `article` ( |
| 020 | `idArticle` INT(11) NOT NULL AUTO_INCREMENT, |
| 021 | `idUtilisateur` INT(11) NOT NULL, |
| 022 | `idRubrique` INT(11) NOT NULL, |
| 023 | `titre` VARCHAR(45) NOT NULL, |
| 024 | `corps` text NOT NULL, |
| 025 | `date` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, |
| 026 | PRIMARY KEY (`idArticle`), |
| 027 | KEY `fk_Article_Utilisateurs` (`idUtilisateur`), |
| 028 | KEY `fk_Article_Rubrique` (`idRubrique`) |
| 029 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; |
| 030 | |
| 031 | -- |
| 032 | -- Contenu de la table `article` |
| 033 | -- |
| 034 | -- -------------------------------------------------------- |
| 035 | -- |
| 036 | -- Structure de la table `commentaire` |
| 037 | -- |
| 038 | |
| 039 | CREATE TABLE IF NOT EXISTS `commentaire` ( |
| 040 | `idCommentaire` INT(11) NOT NULL AUTO_INCREMENT, |
| 041 | `idArticle` INT(11) NOT NULL, |
| 042 | `pseudo` VARCHAR(45) NOT NULL, |
| 043 | `email` VARCHAR(45) DEFAULT NULL, |
| 044 | `message` text NOT NULL, |
| 045 | `date` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, |
| 046 | PRIMARY KEY (`idCommentaire`), |
| 047 | KEY `fk_Commentaire_Article` (`idArticle`) |
| 048 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; |
| 049 | |
| 050 | -- |
| 051 | -- Contenu de la table `commentaire` |
| 052 | -- |
| 053 | -- -------------------------------------------------------- |
| 054 | -- |
| 055 | -- Structure de la table `rubrique` |
| 056 | -- |
| 057 | |
| 058 | CREATE TABLE IF NOT EXISTS `rubrique` ( |
| 059 | `idRubrique` INT(11) NOT NULL, |
| 060 | `Nom` VARCHAR(45) NOT NULL, |
| 061 | PRIMARY KEY (`idRubrique`) |
| 062 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
| 063 | |
| 064 | -- |
| 065 | -- Contenu de la table `rubrique` |
| 066 | -- |
| 067 | -- -------------------------------------------------------- |
| 068 | -- |
| 069 | -- Structure de la table `tag` |
| 070 | -- |
| 071 | |
| 072 | CREATE TABLE IF NOT EXISTS `tag` ( |
| 073 | `idTag` INT(11) NOT NULL, |
| 074 | `Nom` VARCHAR(45) NOT NULL, |
| 075 | `Couleur` VARCHAR(7) NOT NULL DEFAULT '#000000', |
| 076 | `Hicolor` VARCHAR(7) NOT NULL DEFAULT '#000000', |
| 077 | PRIMARY KEY (`idTag`) |
| 078 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
| 079 | |
| 080 | -- |
| 081 | -- Contenu de la table `tag` |
| 082 | -- |
| 083 | -- -------------------------------------------------------- |
| 084 | -- |
| 085 | -- Structure de la table `tagarticle` |
| 086 | -- |
| 087 | |
| 088 | CREATE TABLE IF NOT EXISTS `tagarticle` ( |
| 089 | `idTag` INT(11) NOT NULL, |
| 090 | `idArticle` INT(11) NOT NULL, |
| 091 | PRIMARY KEY (`idTag`,`idArticle`), |
| 092 | KEY `fk_Tag_has_Article_Tag` (`idTag`), |
| 093 | KEY `fk_Tag_has_Article_Article` (`idArticle`) |
| 094 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8; |
| 095 | |
| 096 | -- |
| 097 | -- Contenu de la table `tagarticle` |
| 098 | -- |
| 099 | -- -------------------------------------------------------- |
| 100 | -- |
| 101 | -- Structure de la table `utilisateurs` |
| 102 | -- |
| 103 | |
| 104 | CREATE TABLE IF NOT EXISTS `utilisateurs` ( |
| 105 | `idutilisateur` INT(11) NOT NULL AUTO_INCREMENT, |
| 106 | `login` VARCHAR(50) NOT NULL, |
| 107 | `passwd` VARCHAR(100) NOT NULL, |
| 108 | PRIMARY KEY (`idutilisateur`) |
| 109 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ; |
| 110 | |
| 111 | -- |
| 112 | -- Contenu de la table `utilisateurs` |
| 113 | -- |
| 114 | |
| 115 | INSERT INTO `utilisateurs` (`idutilisateur`, `login`, `passwd`) VALUES |
| 116 | (1, 'admin', 'ab4f63f9ac65152575886860dde480a1 '); |
| 117 | |
| 118 | -- |
| 119 | -- Contraintes pour les tables exportées |
| 120 | -- |
| 121 | -- |
| 122 | -- Contraintes pour la table `article` |
| 123 | -- |
| 124 | ALTER TABLE `article` |
| 125 | ADD CONSTRAINT `fk_Article_Rubrique` FOREIGN KEY (`idRubrique`) REFERENCES `rubrique` (`idRubrique`) ON DELETE NO ACTION ON UPDATE NO ACTION, |
| 126 | ADD CONSTRAINT `fk_Article_Utilisateurs` FOREIGN KEY (`idUtilisateur`) REFERENCES `utilisateurs` (`idutilisateur`) ON DELETE NO ACTION ON UPDATE NO ACTION; |
| 127 | -- |
| 128 | -- Contraintes pour la table `commentaire` |
| 129 | -- |
| 130 | ALTER TABLE `commentaire` |
| 131 | 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
| INI | | copy code | | ? |
| 01 | ; --- |
| 02 | ; Doctrine |
| 03 | ; --- |
| 04 | |
| 05 | ; configuration de base |
| 06 | ; Le dsn correspond aux infos de connexion. Ici nous appelons une base mysql |
| 07 | ; SGBD : MySqL |
| 08 | ; Login : Root |
| 09 | ; Password : azerty //si aucun password mettre juste root@localhost/bdd |
| 10 | ; Serveur : localhost |
| 11 | ; BDD : tutosite |
| 12 | doctrine.dsn = "mysql://root:azerty@localhost/tutosite" |
| 13 | doctrine.data_fixtures_path = APPLICATION_PATH "/configurations/data/fixtures" |
| 14 | doctrine.sql_path = APPLICATION_PATH "/configurations/data/sql" |
| 15 | doctrine.migrations_path = APPLICATION_PATH "/configurations/migrations" |
| 16 | doctrine.yaml_schema_path = APPLICATION_PATH "/configurations/schema.yml" |
| 17 | doctrine.models_path = APPLICATION_PATH "/../library/App/Models" |
| 18 | |
| 19 | ; règles lors de la génération des classes |
| 20 | ; on utilise la convention de nommage PEAR |
| 21 | doctrine.generate_models_options.pearStyle = true |
| 22 | ; on génère les classes de table |
| 23 | doctrine.generate_models_options.generateTableClasses = true |
| 24 | ; on génère les classes de base. Ces classes contiennent les définitions de nos tables |
| 25 | doctrine.generate_models_options.generateBaseClasses = true |
| 26 | ; on définit un préfixe pour les classes de base |
| 27 | doctrine.generate_models_options.baseClassPrefix = "Base_" |
| 28 | ; on ne pet rien ici, avec la convention pear, ils seront ajoutés dans le sous dossier Base |
| 29 | doctrine.generate_models_options.baseClassesDirectory = |
| 30 | ; on ne met pas le préfixe au nom de fichier |
| 31 | doctrine.generate_models_options.classPrefixFiles = false |
| 32 | ; toutes les classes commenceront par ce préfixe |
| 33 | 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 :
| PHP | | copy code | | ? |
| 01 | protected function _initDoctrine() |
| 02 | { |
| 03 | //on met Doctrine en autoload |
| 04 | $this->getApplication() |
| 05 | ->getAutoloader() |
| 06 | ->pushAutoloader ( array ('Doctrine', 'autoload' ) ); |
| 07 | spl_autoload_register(array('Doctrine', 'modelsAutoload')); |
| 08 | |
| 09 | //on récupère une instance de Doctrine |
| 10 | $manager = Doctrine_Manager::getInstance (); |
| 11 | |
| 12 | //permet de valider automatiquement l'intégrité des données |
| 13 | //ce qui veut dire que l'on ne peut pas mettre une variable de type string |
| 14 | //dans une variable de type int. |
| 15 | $manager->setAttribute (Doctrine::ATTR_VALIDATE, Doctrine::VALIDATE_ALL); |
| 16 | //l’AUTO_ACCESSOR_OVERRIDE va nous permettre de personnaliser l’assignation de données. |
| 17 | $manager->setAttribute ( Doctrine::ATTR_AUTO_ACCESSOR_OVERRIDE, true ); |
| 18 | //Doctrine permet de personnaliser également les classes de table en permettant |
| 19 | //de créer des méthodes propres à une table. |
| 20 | //Ce paramètre permet de charger le fichier contenant nos méthodes personnalisées. |
| 21 | $manager->setAttribute ( |
| 22 | Doctrine::ATTR_MODEL_LOADING, |
| 23 | Doctrine::MODEL_LOADING_CONSERVATIVE |
| 24 | ); |
| 25 | //on permet le chargement des classes table |
| 26 | $manager->setAttribute ( Doctrine::ATTR_AUTOLOAD_TABLE_CLASSES, true ); |
| 27 | |
| 28 | //on récupère toutes les options doctrine du fichier app.ini |
| 29 | $doctrineConfig = $this->getOption('doctrine'); |
| 30 | |
| 31 | //on récupère la variable doctrine.models_path du fichier app.ini |
| 32 | //afin d'avoir le répertoire des models |
| 33 | //pour que Doctrine les charge |
| 34 | Doctrine::loadModels($doctrineConfig['models_path']); |
| 35 | |
| 36 | //on récupère la connexion à mysql et on la nomme doctrine |
| 37 | $conn = Doctrine_Manager::connection($doctrineConfig['dsn'],'doctrine'); |
| 38 | //je sais plus ce que sa veut dire, mais il le faut |
| 39 | $conn->setAttribute(Doctrine::ATTR_USE_NATIVE_ENUM,true); |
| 40 | |
| 41 | //on définit la sortie encodée en UTF-8 |
| 42 | $conn->setCharset('utf8'); |
| 43 | $conn->setCollate('utf8_general_ci'); |
| 44 | |
| 45 | //on retourne la connexion |
| 46 | return $conn; |
| 47 | } |
Et pour que tout soit chargé directement, il suffit d’ajouter ces lignes dans la fonction _initNamSpaces() :
| PHP | | copy code | | ? |
| 1 | $autoloader->registerNamespace('Doctrine_'); |
| 2 | $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
| PHP | | copy code | | ? |
| 01 | // Define path to application directory |
| 02 | defined('APPLICATION_PATH') |
| 03 | || define('APPLICATION_PATH', |
| 04 | realpath(dirname(__FILE__) . '/..')); |
| 05 | |
| 06 | // Define application environment |
| 07 | defined('APPLICATION_ENV') |
| 08 | || define('APPLICATION_ENV', |
| 09 | (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') |
| 10 | : 'production')); |
| 11 | |
| 12 | // Typically, you will also want to add your library/ directory |
| 13 | // to the include_path, particularly if it contains your ZF install |
| 14 | set_include_path(implode(PATH_SEPARATOR, array( |
| 15 | realpath(APPLICATION_PATH . '/../library'), |
| 16 | get_include_path(), |
| 17 | ))); |
| 18 | |
| 19 | require_once 'Doctrine.php'; |
| 20 | |
| 21 | /** Zend_Application */ |
| 22 | require_once 'Zend/Application.php'; |
| 23 | |
| 24 | // Create application, bootstrap, and run |
| 25 | $application = new Zend_Application( |
| 26 | APPLICATION_ENV, |
| 27 | APPLICATION_PATH . '/configurations/app.ini' |
| 28 | ); |
| 29 | |
| 30 | $application->getBootstrap()->bootstrap('doctrine'); |
| 31 | $config = $application->getOption('doctrine'); |
| 32 | |
| 33 | $cli = new Doctrine_Cli($config); |
| 34 | $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 se faire, allez dans votre invite de commande et rendez vous dans le dossier qui contient le script.
Tapez juste la commande suivante :
| Bash | | copy code | | ? |
| 1 | php Doctrine.php |
Elle devrait vous retourner le résultat suivant :

Il ne nous reste plus qu’à taper la commande :
| Bash | | copy code | | ? |
| 1 | php doctrine.php generate-models-db |
| 2 | 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.
| PHP | | copy code | | ? |
| 01 | /** |
| 02 | * Select de base |
| 03 | * |
| 04 | * @param string $where |
| 05 | * @param string $order |
| 06 | * @param int $limit |
| 07 | * @param int $offset |
| 08 | * @return Collection |
| 09 | */ |
| 10 | public function fetchAll($where=null, $order=null, $limit=null, $offset=null) |
| 11 | { |
| 12 | $select = Doctrine_Query::create() |
| 13 | ->select('*') |
| 14 | //dans le from on met le nom de la classe |
| 15 | //Doctrine s'occupe du reste |
| 16 | ->from('App_Models_Utilisateurs'); |
| 17 | |
| 18 | if(isset($where)){ $select->where($where); } |
| 19 | if(isset($order)){ $select->orderBy($order); } |
| 20 | if(isset($limit)){ $select->limit($limit); } |
| 21 | if(isset($offset)){ $select->offset($offset); } |
| 22 | |
| 23 | return $select->execute(); |
| 24 | } |
Ensuite pour utiliser cette requête, nous allons éditier le controller Admin_AccueilController. Dans d’action d’index ajoutez les lignes suivantes :
| PHP | | copy code | | ? |
| 01 | //on récupère la classe table de App_Models_Utilisateurs |
| 02 | $table = Doctrine_Core::getTable('App_Models_Utilisateurs'); |
| 03 | //on liste tout le monde |
| 04 | $liste = $table->fetchAll(); |
| 05 | //on traite le résultat |
| 06 | foreach($liste as $unuser) |
| 07 | { |
| 08 | print_r($unuser->login); |
| 09 | print_r($unuser->passwd); |
| 10 | } |
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.
Articles Connexes
7 Commentaires Donnez votre avis
Laisser un commentaire
Catégories
- Actualités (11)
- Android (5)
- Bases de Données (4)
- Développement (1)
- PasteQR (2)
- PHP (8)
- Systèmes et Réseau (5)
- Technologies Web (5)
- Tests (2)
- Zend Framework (30)
Commentaires récents
- (@Fritte7) (@Fritte7) dans PasteQR passe en 1.1.0
- roux dans ZendX Jquery Dialog
- Fritte7 dans Gérer des évènements dans une listview.
- Fierfeu dans Introduction à Zend Framework 2.0
- Christophe B. dans Gérer des évènements dans une listview.
Mots-Clefs
Active Directory AJAX Android Apache2 APC Bootstrap Chrome Configuration CSS Eclipse Firefox Google html HTTP Installation Internet Internet Exporer Java Javascript JQuery JQuery UI Linux Mémoire Mac MySQL Navigateur Opera PDO Pear Phing PHP Safari SGBD SMTP SQL Ubuntu View Helper Windows Server XML Zend Cache Zend DB Zend Form Zend Framework ZendX ZF 2.0
WP Cumulus Flash tag cloud by Roy Tanck requires Flash Player 9 or better.

Publié par Throrïn





J’ai un problème lorsque j’utilise php Doctrine.php :
Fatal error: Uncaught exception ‘Zend_Config_Exception’ with message ‘Section ‘p
roduction’ cannot be found in C:\xampp\htdocs\zftest\application/configurations/
app.ini’ in C:\xampp\htdocs\zftest\library\Zend\Config\Ini.php:151
Stack trace:
#0 C:\xampp\htdocs\zftest\library\Zend\Application.php(386): Zend_Config_Ini->__
construct(‘C:\xampp\htdocs…’, ‘production’)
#1 C:\xampp\htdocs\zftest\library\Zend\Application.php(85): Zend_Application->_l
oadConfig(‘C:\xampp\htdocs…’)
#2 C:\xampp\htdocs\zftest\application\scripts\Doctrine.php(36): Zend_Application
->__construct(‘production’, ‘C:\xampp\htdocs…’)
#3 {main}
thrown in C:\xampp\htdocs\zftest\library\Zend\Config\Ini.php on line 151
Bonjour,
L’erreur est pas trop dur à corriger. En fait tu utilise ton site en mode production APP_ENV = production, hors, dans ton fichier de config, tu ne déclare pas production. Rajoute en fin de ton config.ini [production : development] et le tour est joué.
Attention tout de même. En faisant comme ça, tu remet les configs de développement pour la production ce qui n’est pas très recommandé.
Bonjour;
JE sais pas pourquoi le PhpMyAdmin me retourne cette erreur apres avoir recopier la requete SQL:
Erreur
Requête SQL:
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
MySQL a répondu:
#1064 – You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */’ at line 1
http://t.co/FXXV8EM7
Bonjour,
Lors de l’exécution du script Doctrine.php, j’obtiens l’erreur suivante : « unexpected T_STRING »
, qui correspond dans le script à la ligne » defined(‘APPLICATION_ENV’).
php Doctrine.php > PHP Parse error: syntax error, unexpected T_STRING in Doctrine.php on line 9.
Mon fichier est identique à votre Doctrine.php pourtant.
Je précise que j’utilise un Xampp pour faire tourner mon Zend.
Merci d’avance
Ok je viens de corriger.
En fait ton fichier contient plein d’espaces dans les inter-lignes, d’où le problème de syntaxe détecté. (à moins que ça soit le copier/collier avec ton widget pour afficher le code PHP qui foire)
Effectivement cela provient bien du module affichant le code source. As tu essayé via le bouton copy si ça remédie au problème ?