Récemment, dans le cadre de la maintenance d’un ancien projet développé sous le framework symfony en version 1.4, j’ai été amené à développer une tâche symfony personnalisée.
Qu’est ce qu’une tâche symfony ? Appelées « tasks », ce sont des scripts exécutables en ligne de commande et qui facilitent certains actions à effectuer pour un site. Si vous utilisez symfony, vous vous en servez tout le temps: ce sont les fameux php symfony cache:clear, php symfony doctrine:build --all, etc…
Et pour effectuer certaines actions, il est plus pratique de passer par celles-ci, notamment lorsque par exemple, vous devez effectuer une tâche récurrente à l’aide d’un CRON.
Dans mon exemple, j’ai développé un module d’enchère, et une fonctionnalité demandée était d’avoir un email envoyé automatiquement à tous les inscrits à l’enchère, une heure avant le début de celle ci. Alors évidemment, on aurait pu faire une action symfony qui, lorsque la bonne page est appelée (via un bouton dans l’administration du site par exemple), envoie ces mails, mais ce n’est pas très pratique (et cela requiert une action humaine avec le bon timing).
Une autre solution est donc de passer par les tâches CRON, qui permettent, une fois configurées sur un serveur, d’effectuer des tâches (comme lancer un script PHP) à des intervalles réguliers: tous les jours, toutes les heures, toutes les semaines, tous les mois, etc… L’idée ici est donc de créer une tâche CRON qui va, toutes les heures, lancer notre tâche symfony. Comme je n’ai pas trouvé de tutoriel clair et précis à ce sujet (et aussi pour me faire un petit mémo pour plus tard), je vais vous expliquer comment procéder pour créer une telle tâche. D’ailleurs, ceci peut vous servir de base / d’exemple pour créer vos propre tâches, quel que soit leur rôle. Je n’aborderai pas la création de tâches CRON, ceci étant un autre sujet.
Créons notre tâche symfony
Une tâche symfony est simplement un script de classe PHP avec une structure précise. Nous pourrions le créer à la main depuis zéro, mais comme symfony est bien fait, le framework nous propose … une tâche pour créer une tâche ! Grâce à la commande:
php symfony generate:task projet:tache
symfony va vous générer automatiquement un fichier projetTacheTask.class.php dans le dossier lib/task de votre projet, ce fichier contenant déjà toute la structure de base de votre tâche. Lorsque vous voudrez lancer la tâche, vous taperez dans la console donc:
[cc lang= »php » escaped= »true]
php symfony projet:tache
Ouvrez ce fichier, vous verrez deux méthodes appartenant à la classe. La première, configure(), comme son nom l’indique, permet de configurer votre tâche: son namespace et son nom (en d’autre termes, comment l’appeler en ligne de commande), lui ajouter une description (qui sera affichée si vous tapez « help » devant le nom de la commande lorsque vous l’appelez). Cette méthode peut appeler deux autres méthodes:
- [cci escaped= »true »]$this->addArguments() : Cette méthode, en lui passant un tableau d’argument en paramètre, permet de spécifier, à l’appel de la tâche, des arguments obligatoires, comme par exemple le nom de l’application, ou tout autre paramètres ui serait obligatoire au fonctionnement de la tâche
- [cci escaped= »true »]$this->addOptions() : cette méthode vous permet de spécifier des paramètres optionnels, qui peuvent servir à modifier le comportement de votre tâche mais qui ne sont pas obligatoires.
Le coeur de la tâche
La deuxième méthode de cette classe, execute(). C’est ici que vous devrez placer tout le code nécessaire au fonctionnement de votre script. Cette méthode contient par défaut les instructions suivantes:
[cc lang= »php » escaped= »true »]
<?php
protected function execute($arguments = array(), $options = array())
{
// initialisation de la connexion à la base de données
$databaseManager = new sfDatabaseManager($this->configuration);
$connection = $databaseManager->getDatabase($options[‘connection’])->getConnection();
cela vous permet d’avoir accès à la base de données et de la manipuler. Si vous souhaitez effectuer une requête SQL, vous pouvez, au choix, soit utiliser une méthode que vous avez crée dans une classe collection (les classes XXXXTable, générees d’après vos modèles), soit directement dans le script, avec une requête SQL pure, comme ceci:
[cc lang= »php » escaped= »true »]
<?php
$q = $connection;
$sql = « SELECT i.* FROM enchere_inscriptions i
LEFT JOIN encheres e ON e.id = i.enchere_id WHERE e.debut > ‘$now' »;
$req = $q->prepare($sql);
$req->execute();
$results = $req->fetchAll();
Ensuite, afin d’accéder aux différents services (notamment le helper « Partial« , qui va permettre de récupérer un template de votre projet pour la mise en forme de l’email), nous devons créer un contexte. En effet, une application symfony et sa logique se déroulent toujours dans un « contexte », un environnement, et par défaut, lorsqu’on lance une tâche, en ligne de commande, il n’y a aucun contexte. Pour le créer, donc, il faut placer le code suivant (toujours à l’intérieur de la fonction execute()):
[cc lang= »php » escaped= »true »]
<?php
// Création du contexte
$configuration = ProjectConfiguration::getApplicationConfiguration(‘frontend’, ‘prod’, false);
$context = sfContext::createInstance($configuration);
Les paramètres de la méthode getApplicationConfiguration() sont, vous l’aurez compris, le nom de l’application dans laquelle nous voulons récupérer le ou les templates, et l’environnement (le plus souvent « prod »). Le dernier paramètre est un booléen, vous permettant d’activer le mode debug ou non.
Enfin, pour récupérer le template/partial, il faut d’abord charger le helper puis utiliser la fonction get_partial:
[cc lang= »php » escaped= »true »]
<?php
$configuration->loadHelpers(‘Partial’);
$html = get_partial(‘module/template, array(‘variable’ => $variable));
Il ne vous reste plus qu’à envoyer le mail:
[cc lang= »php » escaped= »true »]
<?php
$message = $this->getMailer()->compose(‘no-reply@votresite.com’, ‘destinataire@email.com’, ‘Votre sujet’);
$message->setBody($html, ‘text/html’);
$this->getMailer()->send($message);
Si vous souhaitez afficher un message à la fin de (ou pendant) votre script dans la console, il suffit d’utiliser la méthode: