I. Installation de Doctrine Data Fixtures▲
Dans l'édition Standard de Symfony2, l'appel du script bin/vendors.php lance la mise à jour et le téléchargement d'une série de dépôts Git, précisés dans un fichier de dépendances. Par défaut, ce fichier est rempli avec le framework Symfony2 et les paquets nécessaires pour former l'édition standard. On peut cependant y ajouter de nouveaux dépôts à télécharger. C'est la méthode qui sera utilisée ici.
Tout d'abord, dans le fichier de dépendances deps, il faut ajouter ces quelques lignes :
[doctrine-fixtures]
git=http://github.com/doctrine/data-fixtures.git
[DoctrineFixturesBundle]
git=http://github.com/symfony/DoctrineFixturesBundle.git
target=/bundles/Symfony/Bundle/DoctrineFixturesBundle
Elles indiquent qu'il y a deux nouvelles dépendances à télécharger. Il faut ensuite lancer la mise à jour des vendors afin de les installer effectivement et, le cas échéant, de mettre à jour votre installation de Symfony2 :
bin/vendors install
Le bundle est maintenant installé, il faut que l'application l'inclue dans son noyau (kernel) et autoloading.
Il faut ajouter le nouvel espace de noms dans ceux connus de Symfony2 ; cependant, on ne peut pas ajouter cette entrée n'importe où : si on met le nouvel espace (Doctrine\Common\DataFixtures) après l'actuel de Doctrine (Doctrine\Common), toute requête sur cet espace finira en erreur, Symfony2 ira d'abord chercher dans l'espace commun de Doctrine.
Dans le fichier app/autoload.php :
$loader
->
registerNamespaces(array(
// ...
'
Doctrine\\Common\\DataFixtures
'
=>
__DIR__.
'
/../vendor/doctrine-fixtures/lib
'
,
'
Doctrine\\Common
'
=>
__DIR__.
'
/../vendor/doctrine-common/lib
'
,
// ...
));
Ensuite, il faut charger ce bundle. Pour ce faire, dans le fichier app/AppKernel.php :
II. Première fixture▲
Les fixtures sont simplement des classes dont la méthode load() est exécutée. Ces classes doivent se trouver dans le dossier DataFixtures/ORM de votre bundle si vous utilisez l'ORM, DataFixtures/ODM pour l'ODM (MongoDB, CouchDB ou autres).
Pour le nommage, il est préférable d'utiliser la convention suivante : LoadEntityData, où Entity est le nom de l'entité.
On met dans le fichier un contenu similaire à ce qui suit :
<?php
namespace
...
\...
\DataFixtures\ORM;
use
Doctrine\Common\DataFixtures\FixtureInterface;
use
...
\...
\Entity\En;
class
LoadEnData implements
FixtureInterface
{
public
function
load($manager
)
{
$en
=
new
En();
// Quelques modifications sur l'entité pour qu'elle serve à quelque chose
$manager
->
persist($en
);
$manager
->
flush();
}
}
Une fois ce fichier créé, rempli et adapté, il faut importer ces fixtures en lançant la commande suivante :
app/console doctrine:fixtures:load
En fonction de la base de données sous-jacente, il faudra possiblement adapter la commande :
app/console doctrine:mongodb:fixtures:load
Remarquons la flexibilité que ce système offre par rapport à son équivalent pour Doctrine dans sa première version : on peut générer très facilement des fixtures dynamiquement, en fonction des résultats d'une requête Google, par exemple.
III. Ordre de chargement▲
Il n'est pas possible en l'état de se baser sur l'existence ou non d'entités en base, alors que la définition de nouvelles entités requiert l'existence d'autres (on ne peut pas créer un article sans catégorie associée sur un blog, notamment).
On utilise alors un ordre de chargement : les fixtures seront chargées selon l'ordre de chargement indiqué. On le spécifie en définissant une méthode publique getOrder() dans le fichier de fixtures. Il renverra un entier : le fichier de fixtures ayant l'entier le plus bas sera chargé en premier, suivi des autres dans l'ordre croissant.
<?php
namespace
...
\...
\DataFixtures\ORM;
use
Doctrine\Common\DataFixtures\FixtureInterface;
use
...
\...
\Entity\En;
class
LoadEnData implements
FixtureInterface
{
public
function
load($manager
)
{
$en
=
new
En();
// Quelques modifications sur l'entité pour qu'elle serve à quelque chose
$manager
->
persist($en
);
$manager
->
flush();
}
public
function
getOrder()
{
return
1
;
}
}
IV. Pour insérer plusieurs entités à la fois▲
Il n'est pas rare de devoir insérer plusieurs entités à la fois, parfois même de créer les entités en fonction d'un résultat externe. Dans ces cas, il est probablement plus pratique d'externaliser la création de l'entité et sa persistance comme ceci :
<?php
namespace
...
\...
\DataFixtures\ORM;
use
Doctrine\Common\DataFixtures\FixtureInterface;
use
...
\...
\Entity\En;
class
LoadEnData implements
FixtureInterface
{
private
$manager
;
public
function
load($manager
)
{
$this
->
manager =
$manager
;
$this
->
generateEntities();
$this
->
manager->
flush();
}
public
function
getOrder()
{
return
1
;
}
private
function
generateEntities()
{
$vars
=
array
('cats'
,
'dogs'
);
foreach
($vars
as
$v
)
{
$this
->
newEntity($v
);
}
}
private
function
newEntity($param
)
{
$en
=
new
En();
$en
->
setParam($param
);
$this
->
manager->
persist($en
);
}
}
À noter que la fonction generateEntities() n'est pas requise, elle permet simplement d'avoir des fonctions courtes et qui n'ont qu'une seule utilité : load() initialise et lance la génération des entités et valide leur entrée en base de données ; generateEntities() génère les données nécessaires à la création de ces entités ; newEntity() crée l'entité.
V. Remerciements▲
Merci à Claude Leloup pour sa relecture orthographique !