Zend framework : Utiliser Zend Framework et Doctrine (Auteur Ruben Vermeersch, Traduction Fred Blanc)

Dans: Tutoriel|Zend Framework

27 nov 2008

Utiliser Zend Framework et Doctrine

Cet article est une traduction du billet de Ruben Vermeersch.

Ce tutoriel vous permettra à l’aide de plusieurs étapes de mettre en place un projet utilisant à la fois Zend Framework et Doctrine. Pas à pas, nous allons réaliser une simple application permettant de poster des messages.

Avant de commencer

Bien que j’ai essayé de conserver cet article très simple, il ne s’agit pas d’une introduction aux deux technologies précitées. Je vous recommande de prendre en main ces deux technologies séparément, avant d’essayer de les combiner ensemble.

Les deux possèdent une bonne documentation vous permettant de débuter :

Le tutoriel d’Akra sur le Zend Framework permet également de bien débuter.

(Note du traducteur : pour la communauté française, vous pouvez trouver de nombreux tutoriels pour débuter sur le site de la communauté française du Zend Framework)

Le Zend framework propose une architecture à utiliser à la carte. Cela veut dire que vous êtes libre d’utiliser uniquement les composants qui vous sont nécessaires, alors que dans d’autres frameworks, la décision est plutôt du type tout ou rien. Cette utilisation ‘à la carte’ est une bonne chose : cela nous permet de développer de véritables applications Zend Framework, sans utiliser le composant Zend_Db (abstraction de base de données).

Bien que Zend_Db ne soit pas une mauvaise technologie, il est encore de bas niveau et trop proche de la couche de base de données. En utilisant Doctrine, vous pouvez manipuler vos données comme des objets, sans trop vous soucier de la base de données.

Le Zend Framework vous laisse une grande liberté dans la façon de construire vos applications. En d’autres termes : il ne vous oblige pas à avoir une structure figée pour votre projet. Dans cet article, j’ai essayé de suivre au plus près la structure recommandée par défaut. Cependant, tout cela n’est qu’une question de goût personnel.

Allons-y !

En premier, nous allons créer la structure par défaut du projet et installer les librairies. Ouvrez un gestionnaire de fichier et créez une structure de dossiers comme ci-dessous. J’expliquerai le rôle de ces dossiers dans un instant.

Structure basique des dossiers
Basic Folder Structure

Cela fait beaucoup de dossiers, mais la plupart d’entre eux vous sont familiers si vous avez déjà construit une application Zend Framework auparavant. Ce qui suit est différent :

  • application/doctrine/: Celui-ci contient tous les fichiers de données de Doctrine, comme les schéma sql et yaml, migrations, dump de données…
  • application/models/: Doctrine génèrera automatiquement les fichiers de modèles dans ce répertoire, qui seront facilement utilisables au sein de votre application Zend Framework.
  • library/: Normallement, vous n’installez que la librairie Zend Framework dans ce dossier library. Dans notre application, nous aurons besoin de deux librairies : le Zend Framework et Doctrine.
    Par conséquent, nous allons créer deux sous-répertoires et nous y installerons les bibliothèques.
  • scripts/: Doctrine est fournit avec un script en ligne de commande, nous le stockerons ici (comme indiqué dans la proposition mentionnée ci-dessus).

Notre prochaine étape sera d’installer le Zend Framework et Doctrine. Télécharger les dernières versions depuis les sites respectifs et décompresser le dossier library (pour Zend Framework) ou lib (pour Doctrine) dans les dossiers que nous venons juste de créer. Cela devrait ressemblait à quelque chose comme cela :

Zend Framework et Doctrine installés
Zend Framework and Doctrine installed

Il est temps de s’occuper du fichier de Bootstrap

Si vous vous souvenez correctement du Zend Framework Quick Start, nous avons besoin de créer un fichier bootstrap.php. Occupons nous de cela maintenant, avec les quelques modifications permettant d’utiliser Doctrine.

Tout d’abord, nous allons créer les fichiers public/index.php et public/.htaccess . Lancez votre éditeur préféré et récupérez les morceaux de code ci-dessous :

public/index.php

<?php
require '../application/bootstrap.php';

public/.htaccess
RewriteEngine on
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^(.*)$ index.php/$1

Comme vous pouvez le voir, ce sont les mêmes que dans n’importe quelle autre application Zend Framework. Le fichier application/bootstrap.php est légèrement différent.

Je l’ai divisé en deux fichiers: application/bootstrap.php et application/global.php. Le premier prend en charge les requêtes client, le second inclut tous les fichiers nécessaires.
J’ai divisé ainsi car le code de global.php est également nécessaire dans le script en ligne de commande de Doctrine (que nous allons voir dans une minute).

application/global.php
<?php
error_reporting
(E_ALL | E_STRICT);
ini_set('display_startup_errors', 1);
ini_set('display_errors', 1);
date_default_timezone_set('Europe/Brussels');

/*
* Setup libraries & autoloaders
*/
set_include_path(dirname(__FILE__).‘/../library/zendframework’
. PATH_SEPARATOR . dirname(__FILE__).‘/../library/doctrine’
. PATH_SEPARATOR . dirname(__FILE__).‘/models’
. PATH_SEPARATOR . dirname(__FILE__).‘/models/generated’
. PATH_SEPARATOR . get_include_path());
require
‘Zend/Loader.php’;
Zend_Loader::registerAutoload(‘Zend_Loader’);

/*
* Set super-global data
*/
Doctrine_Manager::connection(« mysql://user:pass@localhost/database »);

/*
* Configure Doctrine
*/
Zend_Registry::set(‘doctrine_config’, array(
‘data_fixtures_path’ => dirname(__FILE__).‘/doctrine/data/fixtures’,
‘models_path’ => dirname(__FILE__).‘/models’,
‘migrations_path’ => dirname(__FILE__).‘/doctrine/migrations’,
‘sql_path’ => dirname(__FILE__).‘/doctrine/data/sql’,
‘yaml_schema_path’ => dirname(__FILE__).‘/doctrine/schema’
));

application/bootstrap.php

<?php
require dirname(__FILE__).'/global.php';

Zend_Controller_Front::run(dirname(__FILE__).‘/controllers’);
?>
Regardons cela pas à pas :


<?php
error_reporting
(E_ALL | E_STRICT);
ini_set('display_startup_errors', 1);
ini_set('display_errors', 1);
date_default_timezone_set('Europe/Brussels');
?>

C’est toujours une bonne idée de configurer à minima la gestion des erreurs et un fuseau horaire. Rien de spécial ici.


<?php
/*
* Setup libraries & autoloaders
*/
set_include_path(dirname(__FILE__).'/../library/zendframework'
. PATH_SEPARATOR . dirname(__FILE__).'/../library/doctrine'
. PATH_SEPARATOR . dirname(__FILE__).'/models'
. PATH_SEPARATOR . dirname(__FILE__).'/models/generated'
. PATH_SEPARATOR . get_include_path());
require
'Zend/Loader.php';
Zend_Loader::registerAutoload('Zend_Loader');
?>

C’est là que nous intégrons Doctrine. Comme vous pouvez le voir, nous avons mis dans notre include path le Zend Framework et Doctrine. Nous incluons également les dossiers dans lesquels Doctrine, va générer des fichiers de modèle. Notez que nous n’avons pas défini le Doctrine autoloader. Le Zend Loader fonctionne tout aussi bien, aussi longtemps que l’include_path sera correctement défini.
Attention: avec la version actuelle de ZF (1.5.1), il y a un bug qui oblige ZF à imprimer (sans danger) des avertissements lorsque vous utilisez la classe Doctrine Templates. Il devrait être fixé dans les futures versions.


<?php
/*
* Set super-global data
*/
Doctrine_Manager::connection("mysql://user:pass@localhost/database");

/*
* Configure Doctrine
*/
Zend_Registry::set(‘doctrine_config’, array(
‘data_fixtures_path’ => dirname(__FILE__).‘/doctrine/data/fixtures’,
‘models_path’ => dirname(__FILE__).‘/models’,
‘migrations_path’ => dirname(__FILE__).‘/doctrine/migrations’,
‘sql_path’ => dirname(__FILE__).‘/doctrine/data/sql’,
‘yaml_schema_path’ => dirname(__FILE__).‘/doctrine/schema’
));
?>

Cette portion de code accompli deux tâches. Tout d’abord, nous avons mis en place la connexion de base de données. Pour rester simple, j’ai placé en dur les données de connexion dans une chaîne de caractères. Dans un système réel, vous souhaiteriez utiliser quelque chose comme Zend_Config. Je vous laisse réaliser cela en guise d’exercice. Deuxièmement, ce morceau de code définit les chemins l’outil en ligne de commande de Doctrine (qui génère tout le code et les schémas de la base de données). Je stocke ce tableau dans le Zend_Registry, qui est un objet générique de stockage, un endroit où vous pouvez stocker des objets et les récupérer plus tard à un point de l’exécution.
Modifiez la ligne qui définit la connexion Doctrine pour répondre aux caractéristiques de votre système. Vous devez pointer sur une base de données vide. Nous allons alimenter cette base de données plus tard.

Le fichier application/bootstrap.php ne contient rien de surprenant. Encore une fois, j’essaie de garder cet exemple le plus simple possible.

Enfin, nous allons définir l’interface de ligne de commande Doctrine :

scripts/doctrine-cli
#!/usr/bin/env php
<?php
require dirname(__FILE__).'/../application/global.php';

$cli = new Doctrine_Cli(Zend_Registry::get(‘doctrine_config’));
$cli->run($_SERVER['argv']);

Rendez ce script exécutable :

chmod +x scripts/doctrine-cli

et vous êtes prêt à commencer.

Contruire une application

A présent que nous avons les scripts de base en place, nous allons construire une application simple utilisant le Zend Framework et Doctrine. Nous allons construire un mur de message très simple, un endroit où les utilisateurs pourront poster un message et voir les autres messages.

Nous ferons cela très simplement : seulement un contrôleur et un script de vue. Recopier les fichiers suivants :

application/views/scripts/index/index.phtml
<html>
<head
<title>ZF & Doctrine example</title>
</head>

<body>
<h1>Submit a message:</h1>
<?=$this->form?>

<hr />
<h1>Messages posted:</h1>
<!– TODO: Show messages here –>
</body>
</html>

application/controllers/IndexController.php

<?php
class IndexController extends Zend_Controller_Action
{
public function
indexAction(
{
$form = $this->getForm();
$req = $this->getRequest();
if (
$req->getPost() && $form->isValid($req->getPost())) {
// TODO: Insert message into database
}
$this->view->form = $form;

// TODO: Retrieve all messages.
}

private function getForm()
{
$form = new Zend_Form();
$form->addElement(‘text’, ‘name’, array(
‘label’ => ‘Your name’,
‘required’ => true
));
$form->addElement(‘textarea’, ‘message’, array(
‘label’ => ‘Message’,
‘required’ => true,
‘rows’ => 4
));
$form->addElement(‘submit’, ‘send’);
return
$form;
}
}
?>

Comme vous pouvez le voir, il y a trois grands points TODO : l’un dans le script de vue et deux dans le contrôleur. Ce sont les endroits où nous devrons raccorder Doctrine. Mais pour ce faire, nous avons besoin tout d’abord de définir des objets de données. Nous allons revenir sur le contrôleur et le script de vue plus tard, mais à présent, il est temps de créer un schéma de base de données.

Définir le schéma de base de données

Doctrine vous permet de spécifier votre schéma de base de données dans des fichiers YAML, une représentation textuelle très simple. Nous utiliserons cela et laisserons Doctrine générer les fichiers PHP automatiquement. J’ai défini le schéma suivant:

application/doctrine/schema/schema.yml (attention à l’indentation, YAML y est très sensible)
---
Message:
columns:
id:
primary: true
autoincrement: true
type: integer(4)
posted:
type: timestamp
name:
type: string(255)
message:
type: string

Dans cette application, nous n’avons besoin que d’un objet très simple: Message, avec quatre colonnes: l’identifiant unique obligatoire, la date et l’heure lorsque le message a été envoyé, le nom de l’utilisateur et le message lui-même.

Nous pouvons à présent utiliser la ligne de commande de Doctrine afin de générer les fichiers de modèles et les tables de la base de données. Depuis le shell, exécutez ceci :

$ ./scripts/doctrine-cli generate-models-yaml
generate-models-yaml - Generated models successfully from YAML schema
$ ./scripts/doctrine-cli generate-sql
generate-sql - Generated SQL successfully for models
$ ./scripts/doctrine-cli create-tables
create-tables - Created tables successfully

Si tout se passe bien, aucune erreur ne doit s’afficher. Si c’est le cas, assurez-vous que vos informations de connexion sont correctement définies.

Connectons le ensemble

Maintenant, attaquons-nous à la partie finale des TODO. Nous allons les remplacer étape par étape. Le code source intégral des fichiers complets est disponible à la fin de l’article. Tout d’abord, nous allons ajouter le code pour stocker un message. Remplacer le texte suivant:

<?php
// TODO: Insert message into database
?>

Par celui là (ne tenez pas compte des balises <?php et ?> ) :

<?php
$message
= new Message();
$message->fromArray($form->getValues(true));
$message->posted = new Doctrine_Expression('NOW()');
$message->save();
?>

Comme vous pouvez le voir, nous utilisons un objet de la classe Message. Cette classe a été générée automatiquement par Doctrine. Vous pouvez le trouver dans  application/models/. L’autoloader prend en charge tous les besoins de chargement.

Nous avons également besoin de pouvoir récupérer les messages afin de les afficher.Tout d’abord, le contrôleur.

Remplacez :


<?php
// TODO: Retrieve all messages.
?>

Par :


<?php
$messages
= Doctrine_Query::create()
->
from('Message m')
->
orderBy('m.posted DESC')
->
execute();
$this->view->messages = $messages;
?>

Encore une fois, très simple. J’ai utilisé une requête DQL (Doctrine Query Language) pour trier par ordre anti-chronologique.

Maintenant, tout ce qu’il reste à faire est l’affichage de ces messages dans notre script de vue. Encore une fois, remplacer:

<!-- TODO: Show messages here -->

Par :


<?php foreach ($this->messages as $message): ?>
<h2><?=$message->name?> (<?=$message->posted?>)</h2>
<?=$message->message?>
<?php
endforeach; ?>

Et voilà, nous avons fini, le résultat devrait ressembler à quelquechose comme cela :

L’application terminée
Finished application

Toutefois, n’utilisez pas cette application dans la vie réelle. Afin de me concentrer sur les parties importantes, je me suis permis des choses comme ne pas filtrer les entrées. Vous pouvez réaliser cela en tant qu’exercice.

Conclusion

Donc vous l’avez, une application claire et simple utilisant à la fois le Zend Framework et Doctrine. Comme les deux suivent un peu la même philosophie, il est possible d’intégrer ces derniers d’une manière très propre, de prendre un réel plaisir à la construction d’une application.

Si vous avez une remarque, un commentaire ou des questions, n’hésitez pas à m’envoyer un mail (ruben@savanne.be), ou un commentaire sur mon blog.

Note du traducteur : Si vous avez une remarque, un commentaire ou des questions sur cette traduction, n’hésitez pas à m’envoyer un mail (fred [point] blanc [arobase] gmail [point] com, ou à poster un commentaire ci-dessous.

Appendice: Listing complet des fichiers

application/controllers/IndexController.php

<?php
class IndexController extends Zend_Controller_Action
{
public function
indexAction()
{
$form = $this->getForm();
$req = $this->getRequest();
if (
$req->getPost() && $form->isValid($req->getPost())) {
$message = new Message();
$message->fromArray($form->getValues(true));
$message->posted = new Doctrine_Expression('NOW()');
$message->save();
}
$this->view->form = $form;

$messages = Doctrine_Query::create()
->
from(‘Message m’)
->
orderBy(‘m.posted DESC’)
->
execute();
$this->view->messages = $messages;
}

private function getForm()
{
$form = new Zend_Form();
$form->addElement(‘text’, ‘name’, array(
‘label’ => ‘Your name’,
‘required’ => true
));
$form->addElement(‘textarea’, ‘message’, array(
‘label’ => ‘Message’,
‘required’ => true,
‘rows’ => 4
));
$form->addElement(‘submit’, ‘send’);
return
$form;
}
}
?>

application/views/scripts/index/index.phtml

<html>
<head>
<title>ZF & Doctrine example</title>
</head>

<body>
<h1>Submit a message:</h1>
<?=$this->form?>

<hr />
<h1>Messages posted:</h1>
<?php foreach ($this->messages as $message): ?>
<h2><?=$message->name?> (<?=$message->posted?>)</h2>
<?=$message->message?>
<?php
endforeach; ?>
</body>
</html>

Blogged with the Flock Browser

9 réponse to Zend framework : Utiliser Zend Framework et Doctrine (Auteur Ruben Vermeersch, Traduction Fred Blanc)

Avatar

miboo

novembre 27th, 2008 at 14 h 04 min

Beau travail !

Juste pour savoir, quel logiciel tu utilises pour afficher ton arborescence ?

Avatar

Frédéric Blanc

novembre 27th, 2008 at 15 h 49 min

Merci Miboo… même si je n’ai que très peu de mérite vu que je n’ai fait que traduire l’article de Ruben.

Pour l’arborescence, je pense que ce sont des captures réalisées sous Mac.

Personnellement, pour mes captures d’images ou vidéo, j’utilise Jing qui répond très bien à mes besoins.

Cordialement,
Fred

Avatar

RubenV

novembre 30th, 2008 at 17 h 38 min

Non non, c’est absolutement pas un Mac!

J’utilise Linux, Ubuntu 8.10 et l’arborescence, c’est Nautilus (qui fait partie de GNOME).

Ruben

Avatar

Frédéric Blanc

décembre 1st, 2008 at 1 h 00 min

Oui Ruben, je te prie de m’excuser. Je me suis laissé berner par le fait que l’affichage des dossiers était proche de ce que j’ai sous Mac.
1000 excuses à toi et à Nautilus ;)

Avatar

Stéphan Claveirolle

novembre 12th, 2009 at 11 h 52 min

Bonjour,

Toute d’abord merci Ruben pour cet article et merci Fred pour la traduction française.

L’ensemble est relativement clair et agréable à lire.
Cela donne la motivation nécessaire pour se lancer dans un projet ZF/Doctrine sans plus attendre. :-)

Toutefois, depuis l’édition de cet article, le 30 novembre 2008, il y a eu pas mal d’évolution sur le ZF (et j’imagine aussi en ce qui concernent Doctrine). Ces modifications ne rendent-elles pas caduque certains aspects du code proposé ?

La dernière annonce de « fusion » Zend Framework / Doctrine laisse également penser que l’intégration sera plus simple et intuitive dans le futur (proche ?).

Qu’en est-il de l’utilisation du ZF sous Zend Studio (Eclipse), au niveau des « wizards » de création des classes/fichiers ?

Cordialement,

S.C.

Avatar

Stéphan Claveirolle

novembre 12th, 2009 at 14 h 58 min

Apparemment d’autres se sont penchés sur la question :

http://www.danceric.net/2009/06/06/doctrine-orm-and-zend-framework/

Cordialement,

S.C.

Avatar

abdellah

décembre 14th, 2009 at 14 h 36 min

salut tout le monde et merci rubenV et Frédéric Blanc de l’explication que vous avez fait
je veut seulement connaitre commet je fait pour supprimer ou modifier un enregistrement avec doctrine et zend
merci d’avance

Avatar

Stéphan Claveirolle

janvier 7th, 2010 at 18 h 54 min

Bonjour,

Je viens de mettre en place un début de projet PHP utilisant à la fois Zend Framework et Doctrine

Je travaille actuellement avec l’IDE Zend Studio et parfois je n’ai pas l’auto-complétion du code concernant les objets du modèle Doctrine.

Est-ce que quelqu’un ici a déjà eu ce genre de problème ?

Exemple :

$user = new User();
$user->name = ‘stephan’;
// La complétion de code fonctionne bien et lorsque je fais un + après $user, Zend Studio me propose bien les propriétés de mon objet $user (donc entre autre $user->name).

Si je récupère un Doctrine_Record via une requête DQL de sélection de mes utilisateurs et que je fais un foreach dessus pour traiter chaque utilisateur, je ne peux plus accéder à leurs propriétés via l’auto-complétion.

En même temps, il y a une différence entre l’objet métier lui même et un objet Doctrine_Record.

Mais peut-on s’arranger afin de conserver tout de même l’auto-complétion à votre avis ?

Cordialement,

S.C.

Avatar

Ludovic

mai 26th, 2010 at 14 h 30 min

Un grand merci pour ce super tutoriel qui m’a permis d’intégrer sans difficultés Doctrine à Zend Framework.

Cependant, une question persiste, j’ai vu que les clés étrangères des tables de la base de données n’étaient pas générées avec le script de Doctrine_Cli dans les modèles ou le fichier YAML.

Savez-vous s’il est possible de les générer automatiquement ? Ou faut-il que je le fasse manuellement sur mes 90 classes modèles et le fichier YAML :( ?

Merci d’avance.

Commentez ce billet

Nota : Tous les commentaires sont modérés à posteriori.

A propos

Un blog technologique, sur le développement, sur le Zend Framework, sur PHP et aussi une petite touche d'entreprenariat.

ElePHPants

    Elefant train like meOn guardEuroscope
  • LucSens: "Lost in Japan" and "Lost in China" offer support for Japanese and Chinese - you just take a photo w [...]
  • Ludovic: Un grand merci pour ce super tutoriel qui m'a permis d'intégrer sans difficultés Doctrine à Zend [...]
  • crazyball: Bonjour, merci pour ce super tuto, par contre est il possible de faire une auto-completion de type " [...]
  • Elio DUFOUR: Hello, j'ai trouvé votre site sympa via Google et je tenais à vous le dire. [...]
  • Prestanux: Bonjour, Les plateformes de mise en relation commerciales sont nombreuses sur la toiles et il est [...]

En ce moment...

Posting tweet...

Partenaires