Hay momentos en el que una aplicación necesita ejecutar tareas periódicamente en el servidor. Si quieres enviar correos electrónicos a tus usuarios o limpiar tablas de la base de datos al final del día, necesitas de un mecanismo para programar tareas y gestionarlas cuando sea el momento. Un cron es un programador de tareas para sistemas tipo Unix, que ejecuta comandos de la shell en ciertos intervalos. Este artículo no pretende que sepas cómo funciona un cron, pero ya que es un concepto clave en este tutorial, vamos a describir los conceptos básicos de cómo funciona.
Fundamentos Cron
Un cron es un demonio programador de tareas que ejecuta tareas programadas en ciertos intervalos. Los crons utilizan unos archivos de configuración llamados crontab, para gestionar el proceso de programación de tareas. Cada crontab contiene cronjobs, cada uno relacionado con una tarea específica. Los cronjobs se componen de dos partes, la expresión cron y el comando de la shell que se debe ejecutar:
* * * * * command/to/run
Cada asterisco en la expresión anterior (* * * * *) es una opción para ajustar la fecha de cuando tiene que ejecutarse la tarea. Se compone de minuto, hora, día del mes, mes y día de la semana con el fin de asegurar una buena programación. Como sabéis, el símbolo del asterisco se refiere a todos los valores posibles para un campo especifico. Como resultado, el cron anterior se ejecutará a cada minuto del día.
Por ejemplo, el siguiente cronjob se ejecutará a las 12:30 todos los días:
30 12 * * * command/to/run
En aplicaciones desarrolladas en PHP, las tareas, fundamentalmente, son scripts de PHP independientes que se ejecutan en modo CLI. Estos scripts están implementados para realizar diferentes tareas en determinados momentos. Sin embargo, no podemos hacer mucho más sin el poder de otras librerías o frameworks PHP. En este artículo, aprenderás cómo utilizar el framework Laravel para crear scripts PHP robustos y programarlos directamente a través del código.
Creación de Comandos en Laravel
Crear un comando en PHP es tan simple como crear un script PHP, y luego ejecutarlo en la línea de comandos, utilizando el comando php. Aquí podéis ver un ejemplo:
php miarchivo.php
Como puedes ver, el archivo es pasado como argumento al comando php. Ya sea porque tu aplicación ha sido desarrollada en Laravel, o porque solo quieres utilizar sus fachadas y helpers para crear secuencias de comandos, tendrás que arrancar Laravel antes de usarlo. Sin embargo, hay una alternativa aún mejor para esto: la creación de un comando Laravel Artisan.
Al utilizar comandos Artisan, tendremos acceso a todas las funciones de Laravel, incluyendo a los helpers, fachadas y otros comandos Artisan, por nombrar unos pocos. No vamos a entrar en detalles sobre los comandos Artisan aquí, ya que están más allá del alcance de este artículo, pero vamos a discutir sus fundamento. Por cierto, para este tutorial vamos a utilizar la última versión del Laravel, la 5.1.
Utilizamos el comando Artisan make:console para generar un comando de la clase skeleton con el que trabajaremos. Como ejemplo, vamos a crear un comando que envíe un SMS de cumpleaños feliz a nuestros usuarios en el día de su cumpleaños.
$ php artisan make:console HappyBirthday --command=sms:birthday
El comando anterior creará una clase llamada HappyBirthday en un archivo con el mismo nombre en el directorio /app/Console/Commands. También tendremos un nombre para el comando a través de la opción command. Este es el nombre que utilizaremos para llamar al comando. Ahora vamos a abrir el archivo para ver lo que tenemos hasta ahora. Hay varias propiedades y métodos dentro de la clase que constituyen el backend del comando:
<?php namespace AppConsoleCommands; use IlluminateConsoleCommand; class HappyBirthday extends Command { /** * The name and signature of the console command. * * @var string */ protected $signature = 'sms:birthday'; /** * The console command description. * * @var string */ protected $description = 'Command description.'; /** * Create a new command instance. * * @return void */ public function __construct() { parent::__construct(); } /** * Execute the console command. * * @return mixed */ public function handle() { // } }
Dentro de la variable $description, podemos poner una simple descripción de lo que hace el comando cuando se ejecuta.
protected $description = 'Envia un mensaje de Cumpleaños Feliz a los usuarios por SMS';
En Laravel 5.1, cada vez que un comando se ejecuta en el terminal, se llama al método handle de la clase del comando. En nuestro caso, para enviar un mensaje a los usuarios en su cumpleaños, podemos modificar método handle de este modo:
<?php // ... public function handle() { User::whereBirthDate(date('m/d'))->get(); foreach( $users as $user ) { if($user->has('cellphone')) { SMS::to($user->cellphone) ->msg('Querido ' . $user->fname . ', te deseo un feliz cumpleaños') ->send(); } } $this->info('Los mensajes de felicitacion han sido enviados correctamente'); }
Una vez que el comando ha terminado, tenemos que registrarlo con Artisan, por lo que estará disponible en la terminal. Para ello, sólo tenemos que añadir el nombre de la clase al array de commands de la clase Kernel, que se encuentra en app/Console/Kernel.php:
<?php class Kernel extends ConsoleKernel { /** * The Artisan commands provided by your application. * * @var array */ protected $commands = [ // ... 'AppConsoleCommandHappyBirthday' ]; // ...
Si ejecutamos php artisan list en el terminal, veremos la descripción de nuestro comando:
$ php artisan list ... sms sms:birthday Envia un mensaje de Cumpleaños Feliz a los usuarios por SMS ...
Como resultado, cada vez que ejecutamos el comando en la terminal, un mensaje de cumpleaños feliz será enviado los usuarios que cumplan años, lógicamente:
$ php artisan sms:birthday Los mensajes de cumpleaños han sido enviados correctamente
Programación de comandos
Aquí viene la parte divertida. Vamos a programar una tarea para ejecutar el comando que acabamos de desarrollar. Para ello, vamos a utilizar una característica que sin duda os enamorará: el programador de tareas de Laravel. Las tareas se definen dentro del método schedule de la clase Kernel. Podemos añadir tantos comandos Artisan como necesitemos utilizando el método command.
Nuestra tarea, se supone que debe ejecutarse una vez al día. Así que, para ello, podemos utilizar el método daily(), de esta manera:
<?php // ... protected function schedule(Schedule $schedule) { $schedule->command('sms:birthday')->daily(); }
Podemos programar todos los comandos directamente desde el método schedule. Hay una variedad de frecuencias de horario para poder asignar a las tareas. Vamos a enumerar algunas de ellas aquí:
Para ejecutar una tarea cada hora todos los días:
<?php $schedule->command('myTask') ->hourly();
Para ejecutar una tarea de todos los días a medianoche:
<?php $schedule->command('myTask') ->daily();
Para ejecutar una tarea de todos los días a las 9:30:
<?php $schedule->command('myTask') ->dailyAt('09:30');
Para ejecutar una tarea una vez a la semana:
<?php $schedule->command('myTask') ->weekly();
Para ejecutar una tarea una vez al mes:
<?php $schedule->command('myTask') ->monthly();
También podemos utilizar un cron personalizado como si fuera una expresión cronjob:
$schedule->command('myTask') ->cron('* * * * *');
La tarea anterior se ejecutará a cada minuto.
Laravel también proporciona un conjunto de restricciones de horario, que se pueden combinar con los métodos anteriores. Por ejemplo, podemos programar una tarea que se ejecute una vez a la semana, pero limitarla a un determinado día y hora.
<?php $schedule->command('theTask') ->weekly() ->mondays() ->at(12:30);
o
<?php $schedule->command('theTask') ->weekly() ->sundays()
Podemos ir más allá y limitar la ejecución de tareas a una determinada condición, utilizando el método when que acepta condiciones. La tarea se ejecutará sólo si la condición es cierta.
<?php $schedule->command('table:clean') ->daily() ->when(function() { return SMS::isWorkingFine(); });
Iniciando el Laravel Scheduler
Para iniciar el propio scheduler, sólo tenemos que añadir una tarea cron en el servidor (con el comando crontab -e), que ejecute php/ruta/al/artisan schedule:run cada minuto en el día:
* * * * * php /path/to/artisan schedule:run 1>> /dev/null 2>&1
Y hasta aquí el artículo sobre cómo manejar cronjobs con Laravel. Espero que os haya gustado y, ya sabéis, si queréis que publiquemos más tutoriales similares, hacédnoslo saber a través de los comentarios.
Fuente: sitepoint