Appeler une tâche symfony depuis une autre tâche

Pour faciliter l'administration de votre site que vous avez bien entendu réalisé avec symfony vous faîtes des tâches. Un exemple de tâche est par exemple la suppression régulière des personnes qui se sont inscrites sur un site mais n'ont jamais confirmé leur email en cliquant sur un lien de validation. Pour rester dans l'esprit DRY, on ne duplique aucune partie de code et on peut être améné à vouloir appeler une tâche depuis une autre...

Pour être concret, nous allons créer une tâche pour insérer des utilisateurs dans un groupe. La tâche va utiliser la tâche create-user du plugin sfDoctrineGuard, ainsi que la tâche add-group. Comme son nom l'indique (même si c'est en grand breton), la première tâche permet de créer un utilisateur tandis que la deuxième permet d'associer un utilisateur à un groupe. Ce que nous voulons faire peut en réalité être fait en deux commandes :

# ./symfony guard:create-user jean@dupond.org jean dupond
# ./symfony guard:add-group jean members

Cela fonctionne à la condition que le groupe members existe. La tâche en question va appeler la tâche create-user. Puis elle va créer le groupe passé en argument si besoin est et finalement va appeler la tâche add-group.

Le constructeur d'une tâche symfony a comme paramètre d'appel un objet sfEventDispatcher et un objet sfFormatter. Pour appeler d'autres tâches il suffira de leur passer les objets que l'on aura reçu à l'appel. Par exemple pour sfGuardCreateUser, ce sera:

$task = new sfGuardCreateUserTask($this->dispatcher, $this->formatter);

J'ai eu un peu de mal à trouver cette information dans la documentation officielle même si je suis sûr qu'elle existe quelque part ! Il faut ensuite invoquer la tâche avec les paramètres et les options qui vont bien. On passe les paramètres que la tâche create-user attend, à savoir email, nom d'utilisateur et mot de passe dans cet ordre. Pour les options (environnement et application), on se contente de passer ceux qu'on a reçu ! Cela donne cela :

$task_arguments = array();
$task_arguments['username'] = $arguments['username'];
$task_arguments['password'] = $arguments['password'];
$task_arguments['email'] = $arguments['email'];
$task->run($task_arguments, $options);

Après le reste du code est des plus classique dans une tâche. Comme on va travailler sur la base on charge les différentes classes Doctrine :

$databaseManager = new sfDatabaseManager($this->configuration);

Il faudra appeler de la même manière la tâche add-group mais comme elle n'a que deux paramètres ce sera bien plus simple :

$task_arguments = array();
$task_arguments['username'] = $arguments['username'];
$task_arguments['group'] = $arguments['group'];
$task = new sfGuardAddGroupTask($this->dispatcher, $this->formatter);
$task->run($task_arguments, $options);

L'ensemble du code ressemble alors à ça. Par parenthèses, si vous connaissez un moyen de mettre du code facilement dans dotclear et de le colorer et surtout de pouvoir après continuer à éditer son billet, je suis preneur. Yash c'est une plaie.

class guardAddUserToGroupTask extends sfBaseTask
{
    protected function configure() {
        $this->addArguments(array(new sfCommandArgument('username', sfCommandArgument::REQUIRED, 'Username'),
                                  new sfCommandArgument('password', sfCommandArgument::REQUIRED, 'Password'),
                                  new sfCommandArgument('email', sfCommandArgument::REQUIRED, 'Email address'),
                                  new sfCommandArgument('group', sfCommandArgument::REQUIRED, 'Group name')
        ));
        $this->addOptions(array(new sfCommandOption('application', null, sfCommandOption::PARAMETER_OPTIONAL, 'Application name', 'frontend'),
                                new sfCommandOption('env', null, sfCommandOption::PARAMETER_REQUIRED, 'Environment', 'dev'),
        ));
        $this->namespace = 'guard';
        $this->name = 'adduser2group';
        $this->briefDescription = 'Create a user and add it to a group';
        $this->etailedDescription = <<configuration);
        $task_arguments = array();
        $task_arguments['username'] = $arguments['username'];
        $task_arguments['password'] = $arguments['password'];
        $task_arguments['email'] = $arguments['email'];

        $task = new sfGuardCreateUserTask($this->dispatcher, $this->formatter);
        $task->run($task_arguments, $options);
        $group = Doctrine_Core::getTable('sfGuardGroup')->findOneByName($arguments['group']);

        if (!$group) {
            $this->logSection('guard', sprintf('Group "%s" does not exist. It will be created', $arguments['group']));
            $group = new sfGuardGroup();
            $group->setName($arguments['group']);
            $group->save();
            $this->logSection('guard', sprintf('Create group "%s"', $arguments['group']));
        }

        $task_arguments = array();
        $task_arguments['username'] = $arguments['username'];
        $task_arguments['group'] = $arguments['group'];
        $task = new sfGuardAddGroupTask($this->dispatcher, $this->formatter);
        $task->run($task_arguments, $options);
    }
}

On aurait pu faire de manière plus simple ou au moins différente. On aurait pu par exemple créer l'utilisateur de la même manière que l'on a créer le groupe. Une autre manière de faire aurait été de dériver la classe sfGuardAddGroupTask pour lui faire créer le groupe en cas de besoin.

Haut de page