Navigation

Related Articles

Back to Latest Articles

Symfony et les tâches


Samuel Breton
Symfony et les tâches

Pour un projet récent j’ai du implémenter un script qui devait insérer des utilisateurs dans la base d’un projet symfony. Afin de conserver l’avantage des objets et de leur validator je n’ai pas effectué un script à base de ‘INSERT INTO’ mais j’ai bel et bien créé ma propre tâche.
Je ne vais pas dans cette article vous parler de la façon de créer les tâches pour cela je vous renvoie vers le cookbook aucune excuse pour ne pas le lire, il a été traduit en français mais je vais vous parler de la façon dont je l’ai implémenté dans mon application.

Il s’agit donc d’un projet très simple listant des profils d’utilisateur pour lesquels on spécifie des dates d’inscription à une option.

Voici donc le schéma que l’on obtient :

Utilisateur:
actAs:
Timestampable:  ~
columns:
civilite:         { type: string(5)}
nom:              { type: string(150)}
prenom:           { type: string(150)}
email:            { type: string(255), unique: true}
profession:       { type: string(255)}
adresse:          { type: string(255)}
code_postal:      { type: string(10)}
ville:            { type: string(100)}
pays:             { type: string(5)}
date_naissance:   { type: date}
telephone:        { type: string(30)}
site_inscription: { type: string(255)}
option1:         { type: Date}
option2:         { type: Date}
option3:         { type: Date}
option4:         { type: Date}

On a vu plus compliqué comme schéma. Le but de ma tâche est donc de récupérer des fichiers CSV et de les insérer dans ma base de données. On va commencer par créer notre tâche :

./symfony generate:task import:execute

On se retrouve donc avec notre class importExecuteTask dans le dossier : /lib/task
Dans la partie configure je vais d’abord définir l’option file qui va définir le fichier CSV que je veux importer :

new sfCommandOption('file', null, sfCommandOption::PARAMETER_REQUIRED, 'Nom du fichier a traiter', '')

Maintenant passons à la partir qui va se charger de l’import. Dans un premier temps création de ma boucle

$handle = fopen($options['file'], 'r');
while (($data = fgetcsv($handle, 5000, ";")) !== false)
{
 /* Mon code d'insertion */
}

Je veux que les utilisateurs déjà existant soit juste mis à jour pour les autres ils seront créé.

$user = Doctrine::getTable('Utilisateur')->createQuery('c')
->andWhere('c.email = ? ', $data[0])->fetchOne();
 
if (!$user)
{
  $user =new Utilisateur();
}
$user->setEmail($data[0]);
$user->setPrenom($data[1]);
 /* Etc pour chaque champs */

Je veux maintenant préciser les options et pouvoir en ajouter dans le futur assez facilement. Pour cela je vais mettre dans mon fichier apps/monApplication/modules/monModule/config/app.yml la liste de mes options :

all:
  option: [option1, option2, option3, option4]

Je vais ensuite définir un attribut dans ma tâche, n’oublions pas que c’est une classe et que symfony ou pas il n’en reste pas moins qu’on peut lui définir des attributs, j’insiste sur ce point car je pense que c’est une des difficultés quand on débute avec symfony, ne pas oublier que l’on est dans du PHP.

private static $app_yml = array();

Maitenant que l’attribut est crée on va lui attribuer la valeur contenu dans le fichier app.yml graĉe à la classe sfYaml()

    protected function configure()
    {
       self::$app_yml = sfYaml::load(sfConfig::get('sf_root_dir').'/apps/backend/config/app.yml');
// suite du code ...

Mais à quoi cela peut-il servir ? Et bien par exemple à créer des options à la volée :

protected function configure()
    {
       // Début du code
        foreach (self::$app_yml['all']['option'] as $option)
        {
            $this->addOption($option,null,sfCommandOption::PARAMETER_OPTIONAL, 'Valeur pour '.$option, false);
        }
 
     // Suite du code

Je me retrouve maintenant avec 4 options supplémentaires que l’on peut vérifier en tapant la commande

./symfony help import:execute

Maintenant que nous avons créé ces options autant les utiliser mais il faut que cela soit dynamique pour cela on va utiliser les méthodes magiques dans ma boucle qui insère les utilisateurs :

// debut du code
 foreach (self::$app_yml['all']['option'] as $option)
{
  if ($options[option])
  {
    $user->__get($option, date('Y-m-d'));
  }
}
// fin du code

Maintenant lorsque que je vais appeler ma tâche je peux préciser les options auxquelles correspond mon fichier CSV.

./symfony import:execute --option1="true"

Pour terminer voilà un petit conseil pour le traitement de masse et la création multiple d’objet. En fin de boucle une fois que votre objet ne sera plus utiliser ajouté :

// debut du code
$user->free();
unset($user);
// fin de ma boucle

Ceci évitera certains problèmes de mémoire.

En conclusion :

Dans le futur si des options supplémentaires sont nécessaires je pourrais simplement rajouter une colonne dans ma base de données et compléter mon fichier app.YML. Il est bien évident que l’on pourrait faire cette gestion dans la base de données directement avec une table lié et une relation 1-1. Mais ici le but été de voir également la possibilité de charger un fichier YML depuis un autre module voir même d’ailleurs.

Show Comments (5)

Comments

  • Gilles

    Intéressant. Merci pour ces articles Symfony. Je dev principalement en Python / Django. Ca me fait penser aux commandes Django. Bref, très pratique. Simple et rapide à implémenter.

    • Article Author
  • pink90

    j’ai essayer le code voici mon fichier c’est bizarre je ne trouve pas d’erreur svp aidez moi merci
    //début de mon code

    class importExecuteTask extends sfBaseTask
    {
    private static $app_yml = array ();
    protected function configure()
    {
    // // add your own arguments here
    // $this->addArguments(array(
    // new sfCommandArgument(‘my_arg’, sfCommandArgument::REQUIRED, ‘My argument’),
    // ));
    self::$app_yml = sfYaml::load(sfConfig::get(‘sf_root_dir’).’/apps/backend/config/app.yml’);
    foreach (self::$app_yml[‘all’][‘option’] as $option)
    {
    $this->addOption($option,null,sfCommandOption::PARAMETER_OPTIONAL, ‘Valeur pour ‘.$option, false);
    }

    $this->addOptions(array(
    new sfCommandOption(‘application’, null, sfCommandOption::PARAMETER_REQUIRED, ‘The application name’),
    new sfCommandOption(‘env’, null, sfCommandOption::PARAMETER_REQUIRED, ‘The environment’, ‘dev’),
    new sfCommandOption(‘connection’, null, sfCommandOption::PARAMETER_REQUIRED, ‘The connection name’, ‘doctrine’),
    new sfCommandOption(‘file’, null, sfCommandOption::PARAMETER_REQUIRED, ‘C:/Program Files/EasyPHP-5.3.3.1/www/test/pdimodif_oceane.csv’,  »),
    ));

    $this->namespace = ‘import’;
    $this->name = ‘execute’;
    $this->briefDescription =  »;
    $this->detailedDescription = <<configuration);
    $connection = $databaseManager->getDatabase($options[‘connection’])->getConnection();

    // add your code here
    $handle = fopen ($options[‘file’], ‘r’);
    while (( $data = fgetcsv ($handle, int $ length = 0, »; »)) !== false)
    {
    /* Mon code d’insertion */
    $ticketmodif_oceane = Doctrine::getTable(‘pdimodif_oceane’)->createQuery(‘c’)
    ->andWhere(‘c.Titre = ? ‘, $data[0])->fetchOne();

    if (!$ticketmodif_oceane)
    {
    $ticketmodif_oceane =new pdimodif_oceane();
    }
    $ticketmodif_oceane->setId($data[0]);
    $ticketmodif_oceane->setIs_active($data[1]);
    $ticketmodif_oceane->setIs_published($data[2]);
    $ticketmodif_oceane->setNumero_ticket($data[3]);
    $ticketmodif_oceane->setTitre($data[4]);
    $ticketmodif_oceane->setDescription($data[5]);
    $ticketmodif_oceane->setDescrip_commer($data[6]);
    $ticketmodif_oceane->setInitiateur($data[7]);
    $ticketmodif_oceane->setCause($data[8]);
    $ticketmodif_oceane->setAction_effectuee($data[9]);
    $ticketmodif_oceane->setClasse_Tick($data[10]);
    $ticketmodif_oceane->setNiveau_critique($data[11]);
    $ticketmodif_oceane->setEtat_Tick($data[12]);
    $ticketmodif_oceane->setNature($data[13]);
    $ticketmodif_oceane->setDate_debut($data[14]);
    $ticketmodif_oceane->setDate_ret($data[15]);
    $ticketmodif_oceane->setDate_fin($data[16]);
    $ticketmodif_oceane->setTypeequip($data[17]);
    $ticketmodif_oceane->setEquip($data[18]);
    $ticketmodif_oceane->setChaines_impact($data[19]);
    $ticketmodif_oceane->setType_ticket($data[20]);
    $ticketmodif_oceane->setDomaine($data[21]);
    $ticketmodif_oceane->setDroits_tick($data[22]);
    $ticketmodif_oceane->setOuverture_id($data[23]);
    $ticketmodif_oceane->setCreated_by_id($data[24]);
    $ticketmodif_oceane->setUpdated_by_id($data[25]);
    /* Etc pour chaque champs */
    }
    }
    }

    //fin de mon code
    j’ai l’erreur PHP Parse error: syntax error, unexpected ‘$’ in C:\APPS\smc_portail_infobon\li
    b\task\importExecuteTask.class.php on line 46

    Parse error: syntax error on line 46, unexpected ‘$’ in C:\APPS\smc_portail_infobon\lib\tas
    k\importExecuteTask.class.php

    • Article Author
  • pink90

    quelle est la partie du code me permettant de spécifier ma base mysql à laquelle je veux me connecter?

    • Article Author
  • pink90

    je travaille avec synfony 1.4 et j\’ai vraiment besoin d\’implémenter cette tache svp
    voici mon code il a des erreurs spécifiées en bas de page svp c\’est urgent et j\’ai besoin d\’assistance
    je veux insérer des données dans les tables ma base mysql à partir des fichiers csv situés dans ma machine en local et je ne sais comment m\’y prendre avec symfony
    <?php

    class importExecuteTask extends sfBaseTask
    {
    private static $app_yml = array ();
    protected function configure()
    {
    // // add your own arguments here
    // $this->addArguments(array(
    // new sfCommandArgument(\’my_arg\’, sfCommandArgument::REQUIRED, \’My argument\’),
    // ));

    $this->addOptions(array(
    new sfCommandOption(\’application\’, null, sfCommandOption::PARAMETER_REQUIRED, \’The application name\’),
    new sfCommandOption(\’env\’, null, sfCommandOption::PARAMETER_REQUIRED, \’The environment\’, \’dev\’),
    new sfCommandOption(\’connection\’, null, sfCommandOption::PARAMETER_REQUIRED, \’The connection name\’, \’doctrine\’),
    new sfCommandOption(\’file\’, null, sfCommandOption::PARAMETER_REQUIRED, \’C:/Program Files/EasyPHP-5.3.3.1/www/test/pdimodif_oceane.csv\’, \’\’),
    ));
    $this->namespace = \’import\’;
    $this->name = \’execute\’;
    $this->briefDescription = \’\’;
    $this->detailedDescription = <<<EOF
    The [import:execute|INFO] task does things.
    Call it with:

    [php symfony import:execute|INFO]
    EOF;
    self::$app_yml = sfYaml::load(sfConfig::get(\’sf_root_dir\’).\’/apps/backend/config/app.yml\’);
    foreach (self::$app_yml[\’all\’][\’option\’] as $option)
    {
    $this->addOption($option,null,sfCommandOption::PARAMETER_OPTIONAL, \’Valeur pour \’.$option, false);
    }
    }

    protected function execute($arguments = array(), $options = array())
    {
    // initialize the database connection
    $databaseManager = new sfDatabaseManager($this->configuration);
    $connection = $databaseManager->getDatabase($options[\’connection\’])->getConnection();

    // add your code here
    $handle = fopen($options[\’file\’], \’r\’);
    $data =fgetcsv($handle,0,\";\");

    while(fgetcsv($handle,0,\";\")!== false)
    {
    /* Mon code d\’insertion */
    // testons le contenu de la colonne id de notre table pdimodif_oceane
    $ticketmodif_oceane = Doctrine::getTable(\’pdimodif_oceane\’)->createQuery(\’c\’)
    ->andWhere(\’c.id = ? \’, $data[0])->fetchOne();

    if (!$ticketmodif_oceane)
    {
    $ticketmodif_oceane =new pdimodif_oceane();

    $ticketmodif_oceane->setId($data[0]);
    $ticketmodif_oceane->setIs_active($data[1]);
    $ticketmodif_oceane->setIs_published($data[2]);
    $ticketmodif_oceane->setNumero_ticket($data[3]);
    $ticketmodif_oceane->setTitre($data[4]);
    $ticketmodif_oceane->setDescription($data[5]);
    $ticketmodif_oceane->setDescrip_commer($data[6]);
    $ticketmodif_oceane->setInitiateur($data[7]);
    $ticketmodif_oceane->setCause($data[8]);
    $ticketmodif_oceane->setAction_effectuee($data[9]);
    $ticketmodif_oceane->setClasse_Tick($data[10]);
    $ticketmodif_oceane->setNiveau_critique($data[11]);
    $ticketmodif_oceane->setEtat_Tick($data[12]);
    $ticketmodif_oceane->setNature($data[13]);
    $ticketmodif_oceane->setDate_debut($data[14]);
    $ticketmodif_oceane->setDate_ret($data[15]);
    $ticketmodif_oceane->setDate_fin($data[16]);
    $ticketmodif_oceane->setTypeequip($data[17]);
    $ticketmodif_oceane->setEquip($data[18]);
    $ticketmodif_oceane->setChaines_impact($data[19]);
    $ticketmodif_oceane->setType_ticket($data[20]);
    $ticketmodif_oceane->setDomaine($data[21]);
    $ticketmodif_oceane->setDroits_tick($data[22]);
    $ticketmodif_oceane->setOuverture_id($data[23]);
    $ticketmodif_oceane->setCreated_by_id($data[24]);
    $ticketmodif_oceane->setUpdated_by_id($data[25]);
    /* Etc pour chaque champs */
    }
    }
    }

    ?>

    les erreurs sont les suivantes et il y en a d\’autres svp aidez moi à le débugger merci d\’avance :
    C:\\APPS\\smc_portail_infobon>php symfony help import:execute
    PHP Parse error: syntax error, unexpected \’,\’ in C:\\APPS\\smc_portail_infobon\\li
    b\\task\\importExecuteTask.class.php on line 45

    Parse error: syntax error, unexpected \’,\’ in C:\\APPS\\smc_portail_infobon\\lib\\tas
    k\\importExecuteTask.class.php on line 45

    C:\\APPS\\smc_portail_infobon>php symfony help import:execute
    PHP Parse error: syntax error, unexpected T_VARIABLE in C:\\APPS\\smc_portail_inf
    obon\\lib\\task\\importExecuteTask.class.php on line 67

    Parse error: syntax error, unexpected T_VARIABLE in C:\\APPS\\smc_portail_infobon\\
    lib\\task\\importExecuteTask.class.php on line 67

    C:\\APPS\\smc_portail_infobon>php symfony help import:execute
    PHP Parse error: syntax error, unexpected \’$\’ in C:\\APPS\\smc_portail_infobon\\li
    b\\task\\importExecuteTask.class.php on line 46

    Parse error: syntax error, unexpected \’$\’ in C:\\APPS\\smc_portail_infobon\\lib\\tas
    k\\importExecuteTask.class.php on line 46

    • Article Author
  • thomas

    @pink90, n’hésites pas à nous envoyer ton fichier pa rmail sur contact at lexik.fr
    Et commence par vérifier les lignes qui sont remontées dans tes erreurs.

    • Article Author

Recevez nos articles