Development

Documentation/fr_FR/book/trunk/populate

You must first sign up to be able to contribute.

Cette partie de la documentation est en cours de traduction. Cela signifie qu'elle est traduite de manière soit incomplète, soit inexacte. En attendant que cette traduction soit terminée, vous pouvez consulter la version en anglais pour des informations plus fiables.

Charger une base de données

En résumé

Au cours du développement d'applications, les développeurs sont souvent confrontés au problème de la saisie de données de test dans la base. Des solutions spécifiques à certaines bases existent, mais aucune ne peut s'utiliser de manière générique pour toute base de données relationelle. Symfony offre une solution permettant d'insérer via un script des données en base à partir d'un fichier YAML et de la classe sfPropelData.

Introduction

Imaginez un projets utilisant des utilisateurs stockés dans une table Userpossédant les colonnes suivantes:

User
id
name
login
hashed_password
email
created_at

La classe Propel User correspondante contient les méthodes d'accès standards aux propriétés de l'objet. Pour ce projet, on ajoute à la classe une méthode setPassword() qui met à jour la colonne hashed_password à partir d'un pot de passe en clair. Cette méthode est ajoutée dans le fichier myproject/lib/model/User.class.php:

[php]
class User extends BaseUser
{ 
  ...
  public function setPassword($password)
  {
    $this->setHashedPassword(md5(password));
  }
}

Cette méthode enregistre dans la colonne hashed_password un MD5 de la valeur passée en argument, pour ne pas stocker de mots de passe en clair dans la base.

La colonne ìd` est auto-incrémentée.

Symfony permet d'importer des données dans la base à partir d'un fichier texte, pour préparer des tests unitaires ou réinitialiser la base de développement par exemple.

Syntaxe du fichier

Symfony peut lire des fichiers utilisant la syntaxe YAML. Le fichier se compose d'un entête définissant la classe des enregistrements à insérer dans la base, suivi d'une liste d'enregistrements, chacun identifié par un label unique. Les valeurs de chaque enregistrement sont fixées au moyen de paires colonne: valeur. Par exemple:

User:
      bob_walter:
        name:       Bob Walter
        login:      bwalter
        password:   sarah34
        email:      bob.walter@foomail.com
        
      peter_clive:
        name:       Peter Clive
        login:      pclive
        password:   gurzikso
        email:      peter.clive@foomail.com

Les noms des colonnes seront transformés en CamelCase pour déterminer la correspondance avec les méthodes de la classe ( ici ->setName(), ->setLogin(), ->setPassword(), ->setEmail()). Cela signifie qu'il est possible de définir dans le fichier un champ password même si la table ne contient pas de colonne password. La classe User possède une méthode ->setPassword() qui sera utilisée.

La colonne id étant incrémentée automatiquement, il n'est pas nécessaire de la définir, la couche d'abstraction de base de données s'en chargera.

La colonne created_at n'a pas non plus besoin d'être définie, car Symfony renseigne automatiquement les champs created_at et updated_at respectivement avec les dates de création et de mise à jour de l'enregistrement.

Les données à charger sont enregistrées dans un fichier import_data.yml dans le répertoire myproject/data/fixtures/.

Traitement d'import d'import

Initialisations

L'import se fait au moyen d'un script PHP qui lit les données dans des fichiers YAML et les charge en base. Ce script utilise les classes Propel et les fichiers de configuration de Symfony, il doit donc contenir les même initialisations qu'un contrôleur:

    [php]
    <?php
    
    define('SF_ROOT_DIR',    realpath(dirname(__FILE__).'/..'));
    define('SF_APP',         'myapp');
    define('SF_ENVIRONMENT', 'dev');
    define('SF_DEBUG',       true);
    
    require_once(SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php');
    
    sfContext::getInstance();

La définition d'une application (myapp) et d'un environnement (dev) permettent à Symfony de déterminer la configuration à utiliser. Ce code rend accessible les classes Propel et les fonctions de chargement automatique des classes Symfony.

L'appel à sfPropelData

sfPropelData est une classe qui permet de lire des données dans un fichier YAML et de les insérer via Propel dans une base de données. Pour l'utiliser, il suffit d'appeler la méthode ->loadData(). Celle-ci prend pour argument soit le fichier à charger, soit un répertoire contenant plusieurs fichiers à charger.

Pour charger les données des fichiers contenus dans le répertoire fixtures, créez un fichier load_data.php dans le répertoire myproject/batch/. Ce fichier contient les initialisations précédentes et l'appel à sfPropelData:

    [php]
    $data = new sfPropelData();
    $data->loadData(sfConfig::get('sf_data_dir').DIRECTORY_SEPARATOR.'fixtures');

  ?>

Pour exécuter le script, il suffit de taper en ligne de commande:

    $ cd myproject/batch
    $ php load_data.php

Cel va charger les deux enregistrements libellés bob_walter et peter_clive dans la base (si les paramètres de connection fournis dans le fichier de configuration myproject/apps/myapp/config/databases.yml sont corrects).

Note: si vous avez ajouté une connection ou modifié le nom de la connection par défaut ('propel') dans le fichier databases.yml, vous devrez spécifier le nom de la connection à utiliser en le passant en paramètre à la méthode ->loadData(). Par exemple, pour utiliser la connection symfony, la syntaxe est:

         [php]
         $data->loadData(sfConfig::get('sf_data_dir').DIRECTORY_SEPARATOR.'fixtures', 'symfony');

Ajouter ou remplacer

Par défaut, la méthode ->loadData() supprime tous les enregistrements existant dans les tables chargées. Pour modifier ce comportement, avant d'appeler ->loadData() il faut positionner la propriété deleteCurrentData de sfPropelData à faux`:

    [php]
    $data->setDeleteCurrentData(false);

Pour obtenir la valeur actuelle de la propriété, utilisez son accesseur:

    [php]
    $status = $data->getDeleteCurrentData(false);

Tables liées

Ajouter des enregistrements dans une table est aisé, cela peut se compliquer lorsque des tables sont liées entre elles. Imaginez que les utilisateurs de votre site postent des billets via une interface de blog. Votre modèle de données contient donc également une table billet comportant ces champs:

Post
id
user_id
title
body
created_at
updated_at

Comment définir la valeur du champ user_id alors que la colonne id de la table User est renseignée automatiquement ?

C'est ici que la notion de label devient vraiment utile: pour ajouter un billet écrit par Bob Walter, il suffit d'ajouter les lignes suivantes au fichier myproject/data/fixtures/import_data.yml:

    Post:
      post01:
        user_id:      bob_walter
        title:        Today is the first day of the rest of my life
        body:         I have plenty to say, but I prefer to stay short. Enjoy.

La classe sfPropelData va reconnaître le label que vous avez attribué plus haut à un utilisateur, et le remplacer par la clé primaire de l'enregistrement correspondant de la table User. Vous liez les objets par leur label, sans vous soucier de leur identifiant.

La seule contrainte est que l'objet référencé dans une clé étrangère doit avoir été défini plus haut dans le fichier, Vous devez insérer les objets dans le fichier dans l'ordre où vous les inséreriez manuellement. Le fichier est lu de la première à la dernière ligne, et l'ordre dans lequel vous saisissez les données est important.

Un seul fichier ou plusieurs ?

Un fichier peu contenir les données pour charger plusieurs tables. Par exemple, le fichier suivant:

    User:
      bob_walter:
        name:         Bob Walter
        login:        bwalter
        password:     sarah34
        email:        bob.walter@foomail.com
        
      peter_clive:
        name:         Peter Clive
        login:        pclive
        password:     gurzikso
        email:        peter.clive@foomail.com

    Post:
      test_post:
        user_id:      bob_walter
        title:        Today is the first day of the rest of my life
        body:         I have plenty to say, but I prefer to stay short. Enjoy.

      another_test_post:
        user_id:      bob_walter
        title:        I don't know what to say today
        body:         As my previous post was so briliant, I find myself a little dry.
       
    Comment:
      enthusiast_comment:
        user_id:      peter_clive
        post_id:      test_post
        body:         Hey Bob, I'm so glad you finally found something interesting to say.
          
      disappointed_comment:
        user_id:      peter_clive
        post_id:      another_test_post
        body:         Mate, you really disappoint me. I expected much more or your great potential.

Ce fichier est long. Symfony vous autorise à le découper. Tous les fichiers d'un répertoire sont traités les uns après les autres, par ordre alphabétique. Vous pouvez par exemple découper le fichier précédent en 3, un pour chaque classe. Pour vous assurer qu'ils seront traités dans le bon ordre, préfixez les noms de fichiers d'un nombre:

    100_user_import_data.yml
    200_post_import_data.yml
    300_comment_import_data.yml

Comme on l'a appelée avec un répertoire en paramètre, la méthode->loadData() du script de chargement fonctionnera toujours.

    [php]
    $data->loadData(sfConfig::get('sf_data_dir').DIRECTORY_SEPARATOR.'fixtures');

Si vous ne voulez charger qu'un seul de ces fichiers:

    [php]
    $data->loadData(sfConfig::get('sf_data_dir').DIRECTORY_SEPARATOR.'fixtures'.DIRECTORY_SEPARATOR.'100_user_import_data.yml');

Syntaxe YAML alternative

YAML propose une syntaxe alternative pour les tableaux associatifs. Avec cette syntaxe, vos fichiers de données seront plus lisibles, surtout pour les tables qui contiennent de nombreuses clés étrangères. Par exemple, le fichier

Comments:
      c123:
        user_id:    u65
        post_id:    p23
        body:       first blabla
      
      c456:
        user_id:    u97
        post_id:    p64
        body:       second blabla

Peut être écrit plus simplement

    Comments:
      c123: { user_id: u65, post_id: p23, body: first blabla }
      c456: { user_id: u97, post_id: p64, body: second blabla }

Pour plus d'information sur la syntaxe YAML, reportez-vous au site de YAML