Comment gérer une base de donnée avec le Zend Frameworkls

Alors la on va aborder un chapitre très important. Les bases de données sont bien sur très importantes pour un site web ou un service web. On va voir ensemble comment ajouter, modifier, supprimer des enregistrements (ou tuples) dans un table, dans une base de donnée. On va donc utiliser la gestion CRUD du Zend Framework 1.9.
Sommaire
- Sommaire
- Connexion a la base de donnée
- Schémas de la table
- Préparation de la classe métier
- Obtenir et récupérer des enregistrements
- Ajouter des enregistrements
- Modifier des enregistrements
- Supprimer des enregistrement
- Etendre la classe métier
- Conclusion
Connexion a la base de donnée.
La connexion à la base de donnée principale se fait toute seule. Je m’explique, c’est le bootstrap qui va initialiser notre connexion à la base de donnée. En fait le bootstrap va charger le fichier de configuration de l’application et c’est dans ce fichier que l’on va définir les paramètres de connexion a la BDD. Il faut donc éditer le fichier application/configs/application.ini
; DATABASE resources.db.adapter = "MYSQLI" resources.db.params.host = "localhost" resources.db.params.username = "budget" resources.db.params.password = "budget" resources.db.params.dbname = "budget" resources.db.params.date_format = "YYYY-MM-ddTHH:mm:ss" resources.db.isDefaultTableAdapter = true
Si on veut que notre connexion à la BDD soit géré automatiquement, le schémas (ci dessus) est très rigide. En effet zend va chercher automatiquement si dans le fichier de configuration il y a des constantes « ressources.db.* » de défini, et si oui il va essayé de se connecter à la base de donnée. Il est bien sur possible d’avoir plusieurs connexions à différente SGBD (mysql, orable, DB2 …).
Si vous utiliser mysql, il suffit de copier / coller le schémas ci dessus, et de bien remplacer les lignes : host, username, password et dbname qui signifie respectivement : hôte, nom d’utilisateur, mot de passe, nom de la BDD. Sinon l’adpater est le driver à utiliser pour se connecter (mysql, orable, DB2… ; se référer a la doc) ; date_format est le format de la date ; et isDefaultTableAdapter est pour savoir si cette connexion est la principale.
Schémas de la table
On va utiliser un exemple pour bien mettre en place ce tuto. On va utiliser une table d’utilisateur. Voilà le schémas :
CREATE TABLE IF NOT EXISTS `users` ( id int(50) NOT NULL auto_increment, `name` varchar(50) NOT NULL, firstname varchar(50) NOT NULL, email varchar(255) NOT NULL, `password` varchar(255) NOT NULL, phonenumber varchar(20) NOT NULL, `enable` int(1) NOT NULL, `level` int(1) NOT NULL, PRIMARY KEY (id), UNIQUE KEY email (email) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
On a donc :
- Un id en auto-increment
- Un nom
- Un prénom
- Une adresse email
- Un mot de passe
- Un numéro de téléphone
- Un booléen pour savoir si l’utilisateur est activé
- Un entier pour avoir le niveau d’administration
- Une clé primaire et un index sur l’id
- Une clé unique et un index sur l’email
Préparation de la classe métier.
Zend commence à gérer de façon assez autonome et automatique les BDD. Il y a maintenant un gestionnaire CRUD (Create, Read, Update, Delete => Ajouter, Lire, Mettre a jour, Supprimer des enregistrements). Pour se faire il faut créer une class php. On est assez libre pour le nom des class et pour leurs emplacements, mais je vous recommanderai d’être assez logique et rigoureux. En fait il va falloir faire une class par table de votre base de donnée. Pour ma part, je mets presque toujours un « s » a la fin du nom de mes tables, car elles contiennent plusieurs enregistrements. Par exemple la table users contient plusieurs utilisateurs. Il faut maintenant créer une class qui représente cette table. On peut organiser ses class comme on veut, mais en général sur le petits projets je mets toutes mes class dans le dossier application/models/DbTable/. De plus je nomme toujours ma class avec le même nom que la table. A quoi doit ressembler la class (Voir la convention de nommage des models) :
<?php
class Model_DbTable_Users extends Zend_Db_Table {
protected $_name = 'users';
}
Pour le nom de la class, il faut se référer au model dans le Zend Framework. Il faut étendre la class Zend_Db_Table. Enfin il faut ajouter l’attribut protected $_name qui a pour valeur le nom de la table dans la base de donnée. Et voilà, le plus dur est fait. On a maintenant une class qui possède un bon nombre de méthode CRUD.
Obtenir et récupérer des enregistrements
Comment obtenir tous les tuples d’une table ? Si il n’y a pas de close particulières, c’est super simple , on exécute le petit bout de code suivant :
private function getUsersAll() {
$dbUser = new Model_DbTable_Users();
return $dbUser->fetchAll()->toArray();
}
Donc on instancie un nouveau Model_DbTable_Users, et on lui demande la retourner tous les enregistrements grâce a la méthode fetchAll, et enfin on convertit le résultats en tableau. Voilà le tours est joué !
Comment obtenir que certains enregistrements ?
private function getUsersByName($name = '') {
$dbUser = new Model_DbTable_Users();
return $dbUser->fetchAll()->toArray(array('name = ?'=> $name));
}
Voilà, la méthode fetchAll possède 4 arguments: $where,$order,$count,$offset qui représente respectivement la clause where, le clause order by, et la clause limit (combien d’enregistrement et à partir de l’enregistrement numéro n ). Pour une utilisation plus poussé, je vous recommande de lire la doc du Zend Framework.
Ajouter un enregistrement
Comment ajouter un enregistrement dans la base de donnée ? Comme dans l’exemple précédant, on va ajouter un nouvel utilisateur.
$users = new Model_DbTable_Users();
$row = $users->createRow();
$row->name = 'Nom';
$row->firstname = 'Prenom';
$row->email = 'email';
$row->password = md5('password');
$row->phonenumber = '0102030405';
$row->enable = 1;
$row->level = 9;
$result = $row->save();
On commence par instanciée un nouveau Model_DbTable_Users. Ensuite on crée une ligne, puis on ajoute a cette ligne les différents attributs, et enfin on sauvegarde cette ligne en table.
On peut aussi faire la même chose en donnant a la méthode createRow un tableau en argument. :
$users = new Model_DbTable_Users();
$datas = array(
'name'=>'Nom',
'firstname'=>'Prenom',
'email'=>'email2',
'password'=>md5('password'),
'phonenumber'=>'0102030405',
'enable'=>1,
'level'=>9,
);
$row = $users->createRow($datas);
$row->save();
Enfin on peut faire beaucoup plus simple. Je ne connais pas bien la différence entre les deux méthodes (la précédente et la suivante), si quelqu’un peut m’éclairer, je suis preneur.
$users = new Model_DbTable_Users();
$datas = array(
'name'=>'Nom',
'firstname'=>'Prenom',
'email'=>'email3',
'password'=>md5('password'),
'phonenumber'=>'0102030405',
'enable'=>1,
'level'=>9,
);
$row = $users->insert($datas);
Bon, c’est assez simple d’ajouter un enregistrement en table ? On va un peu plus loin. Comment protéger ses enregistrements en table grâce a une transaction SQL :
$users = new Model_DbTable_Users();
$datas = array(
'name'=>'Nom',
'firstname'=>'Prenom',
'email'=>'email3',
'password'=>md5('password'),
'phonenumber'=>'0102030405',
'enable'=>1,
'level'=>9,
);
$defaultAdaptateur = Zend_Db_Table::getDefaultAdapter();
$defaultAdaptateur->beginTransaction();
try {
$defaultAdaptateur->insert('users', $datas);
$defaultAdaptateur->commit();
} catch (Exception $e) {
$defaultAdaptateur->rollBack();
echo $e->getMessage();
}
On commence de la même façon que pour la dernière méthode. Ensuite on récupère l’adaptateur de la base de donnée principale puis on commence une transaction. Il faut ensuite en-capsuler notre ajout à la base dans un bloque try-catch. On essaye d’insérer notre enregistrement puis si ça fonctionne on commit. Si ça ne fonctionne pas on fait un rollback et on affiche les messages. Bien sur il est possible de n’utiliser qu’un bloque try-catch.
Mettre a jour un enregistrement
La méthode ici est très similaire à l’ajout d’un enregistrement. On peut mettre a jour uniquement qu’une seule ligne ou tout un groupes de ligne. Dans cet exemple on remplace tous les enregistrements ou l’attribut name est « Nom » par « Nom2 ».
$users = new Model_DbTable_Users();
$datas = array('name'=>'Nom2');
$users->update($datas,array('name = ?'=>'Nom'));
$this->render('index');
Ici les $datas sont les données qu’on va mettre a jour. La méthode updates va tout faire. Le premier arguments est le tableau de donnée, le second argument correspond aux conditions de la clause where. Dans ce cas la on explicite que l’attribut name doit correspondre a Nom.
Supprimer un enregistrement
Cette dernier action est la plus simple, il suffit de bien formuler la clause where.
$users = new Model_DbTable_Users();
$users->delete(array('name = ?'=>'Nom2'));
Ici on supprimer tous les utilisateurs qui ont pour valeur d’attribut name : Nom2.
Extension de la class métier
Bien entendu, on peut ajouter des méthodes particulières a notre class métier. Comme par exemple pour avoir le nombre d’enregistrement :
public function getUserCount(){
$sql = 'select count(1) cnt from users';
$stmt = $this->_db->query($sql);
$results = $stmt->fetchAll();
if ((sizeof($results) > 0) && (isset($results[0]['cnt']))) {
return $results[0]['cnt'];
}
throw new Exception("Erreur : impossible d'obtenir le nombre d'utilisateur");
}
Conclusion
On peut bien sur en-capsuler un update, une suppression dans un block try-catch et de plus on est pas obligé d’utiliser les transaction sql qui sont quand même plus lourde. On verra dans un prochain tuto comme utiliser les clés étrangères.
[header]
Articles en rapport :
- Zend Framework, Formulaire et Base de donnée, partie 2
- Gerer l’authentification avec Zend_Auth du Zend Framework
- Zend Framework, Formulaire et Base de donnée, partie 1
- Application de site E-Commerce [Code-Source]
- Zend : Comment utiliser un model ?
Je crois que la différence entre la méthode createRow($data) et la méthode insert($data) est que la première fait un update quand les données qu’on veut insérer existe déjà et un insert quand ils n’existent pas
@ferdikam Ok, merci pour ta réponse, je teste ca dès que j’ai le temps (peut etre demain, soyons fou) lol
Salut Greg,
Tout d’abord, j’adore tes tutos qui sont pas d’une grande difficulté mais pour bien comprendre, faut justement pas faire trop compliquer…
Dans ce tutos, tu parles des BD, pourquoi, tu utilises « MYSQLI » et non « pdo_mysql » comme adapter? A ce que je sache, pdo est pousser en avant par zf non?
Merci
Michel
Alors en fait, avant j’utilisé PDO_MYSQL, mais la dernière fois que j’ai lancé un projet avec ZEND, j’ai choisis arbitrairement mysqli. Je ne sais pas du tout pourquoi, mais honnetement, je ne vois pas une grande différence. Peut etre sur les performances… Je pense qu’il faut se referer a la doc pour avoir une bonne définition.
Ceci étant dit, le reste du code reste pareil !!! 8-))
mysqli, ne serait pas ancien et en vois de disparition?
Michel !
oui le reste du code reste idéntique.
Sinon je ne sais pas du tout si mysqli est en train de disparaitre. A priori il reste encore très utilisé pour les applications critiques
bonjour je recherche un programme ou exemple existant d’une gestion de stock sous zend 7.1 merci
@benj > tu veux dire sous zend 1.7.1 ? mais sinon je n’ai pas d’exemple complet, mais a chaque fois c’est la meme chose …
Bonjour, j’ai quelques questions :
Quand tu définis les lignes de la connection à la base de données dans application.ini, tu le mets juste avant [production] ?
Ta fonction private getUsersAll() se trouve dans quel fichier?
Au moment de faire : new Model_DbTable_Users(); on me dit que la classe est introuvable. Zend Framework ne précharge pas la classe automatiquement? Ou doit-on le faire manuellement?
Et tes classes qui se trouvent dans models/DbTable, comment tu les nommes? Au pluriel?
Tuto sympathique sinon
Salut.
Perso le code de la database je le mets sous production : [development : production]
Tu peux le mettre ou tu veux ; après ca dépend de la configuration de ton serveur. En fait le fichier application.ini a un structure d’objet. Si tu ne vois pas de quoi je parle, je te recommande d’aller lire la doc de zend sur le fichier de configuration.
La fonction getUserAll se trouve dans un controller.
Par rapport au nom de classe et / ou au chargement de classe, je te conseil de lire : http://blog.lyrixx.info/zend/zend-comment-utiliser-un-model/
enfin, j’ai pour convention (perso) je toujours mettre aux pluriels les noms de classe qui représentent une table dans la BDD, car la table et elle aussi aux pluriel. Mais tu peux faire comme tu veux !
Merci
Salut Greg,
Tout d’abord merci pour tes tutos très intéressants
J’ai quelques question concernant ce tuto et la gestion CRUD de Zend 1.9.
J’ai suivi ton tuto, mais j’ai un message d’erreur:
« Fatal error: Class ‘Model_DbTable_Albums’ not found in /application/controllers/AlbumsController.php »
D’où mes questions:
situation:
ma structure de dossier : \models\DbTable\Albums.php
ma classe : class models_DbTable_Albums extends Zend_Db_Table {
protected $_name = ‘albums’; // nom de ma table => albums
dans mon fichier index.php je load les class (du moins je crois):
// Chargement des classes
require_once ‘Zend/Loader/Autoloader.php’;
Zend_Loader_Autoloader::getInstance();
Après tout ca, je mets dans mon controller AlbumController action index et je fais:
$albums = new Model_DbTable_Albums();
$this->view->albums = $albums->fetchAll()->toArray();
Pourrais-tu m’orienter sur mes erreurs? Je cherche depuis maintenant 2 jours et j’avoue être complétement bloqué…
Merci pour ton aide et vivement les prochains tutos Zend
Tout d’abord il ne trouve pas la classe. Vérifie au niveau de ton fichier /models/DbTable/Albums.php
que tu as bien nommé ta classe Model_DbTable_Albums au lieu de Models_DbTable_Albums comme je le vois dans ton commentaire.
Exactement
Hello,
Effectivement, mais j’ai essayé les 2 méthodes en vain.
Toutefois depuis j’ai trouvé une solution, mais je ne sais pas si c’est la bonne méthode.
J’ai rajouté dans mon Bootstrap.php le code suivant:
protected function _initAutoload() {
$autoloader = Zend_Loader_Autoloader::getInstance();
//$autoloader->registerNamespace(‘Model_DbTable_’);
$autoloader->setFallbackAutoloader(true);
$moduleLoader = new Zend_Application_Module_Autoloader(array(
‘namespace’ => »,
‘basePath’ => APPLICATION_PATH));
return $moduleLoader;
}
Pour info, APPLICATION_PATH pointe sur mon dossier « application ».
Quelqu’un saurait m’expliquer à quoi sert la ligne en commentaire? Car je n’ai pas su la comprendre et ‘exploiter.
Merci pour votre aide.
J’ai oublié de précisé que j’ai également renommé ma classe Albums en Model_DbTable_Album comme le suggérait ferdikam
En efet, j’ai cru comprendre en ouvrant le fichier \library\Zend\Application\Module\Autoloader.php que Model_DbTable pointait vers le dossier models/DbTable (source ligne 59):
‘dbtable’ => array(
‘namespace’ => ‘Model_DbTable’,
‘path’ => ‘models/DbTable’,
)
@keyros : la ligne en commentaire sert pour définir son propre namespace. Mais en fait on n’est pas obligé.
Je vous propose un lien vers un projet que je développe pour les cours. IL N’EST PAS FINIT !! cependant il y a déjà quelques notions et je pense que ce projet pourra vous aider. Il est disponible a cette adresse : http://blog.lyrixx.info/wp-content/uploads/2010/03/TP1-Ecommerce.tar.gz
Super!
Merci beaucoup, je vais pouvoir analyser un peu le code et comparer à mon code de débutant (3e jour de Zend :p)
Je repasserai sûrement très bientôt pour de futures questions
ok, pas de probleme
N’hesites pas à revenir si tu apprécies les tutos (ou même si tu ne les aimes pas lol
)
Slt,
g essayé ton projet Tp1Ecommerce mais une erreur du genre:
Parse error: parse error in C:\wamp\www\TP1-Ecommerce\application\layouts\scripts\layout.phtml on line 40
Et à la ligne 40 du code il n’y a rien.J’ai du mal à comprendre et j’ai aussi vérifier si il n’y a pas de crochets fermés ou pas.
je n’ai jamais eu de problème avec ce projet. C’était pour les cours et les profs n’ont pas eu de problème pour le lancer. Je pense que tu as du mal inclure la librairie ou je sais pas quoi …
Si tu trouves, fais moi signe
Merci