Aprende a crear comandos personalizados en Laravel con Artisan para automatizar tareas críticas. Partimos de un caso práctico: un comando que envía una newsletter por correo a usuarios verificados, usando notificaciones, argumentos opcionales y barra de progreso. Verás cómo estructurar la firma, la descripción, el constructor y el método handle, además de configurar SMTP con Mailtrap para pruebas confiables.
¿Cómo crear un comando personalizado en Laravel con Artisan?
Crear un comando es directo. Laravel ofrece la base y tú defines la lógica. Además de los que trae Artisan, puedes añadir los tuyos con argumentos, opciones y preguntas.
// Firma y descripcióna protected$signature='send newsletter';a protected$description='Envía un correo electrónico';// Prueba rápida en handledd('hola');
¿Qué define la firma y la descripción?
La firma es el nombre con el que invocas el comando: por ejemplo, send newsletter. La descripción funciona como ayuda para el usuario: "Envía un correo electrónico".
¿Dónde colocar la lógica con handle?
En handle va la lógica de negocio. Puedes inyectar dependencias con el constructor si lo necesitas.
¿Cómo enviar una newsletter con notificaciones y verificación de correo?
Para enviar correos de forma expresiva usaremos notificaciones. Crearemos una notification y filtraremos usuarios que hayan verificado su email. Luego activaremos las rutas de verificación y configuraremos SMTP con Mailtrap.
Genera la notificación desde la terminal.
Implementa la interfaz de verificación en el modelo usuario: MustVerifyEmail.
Filtra por email_verified_at no nulo y recorre la colección de Eloquent con each.
Envía con notify(new *NewsletterNotification*).
Habilita verificación de rutas pasando ['verified' => true].
Configura Mailtrap: integra con Laravel, copia valores y pégalos en tu .env.
php artisan make notification newsletter notification
// Consulta base: usuarios con email verificado$builder=User::whereNotNull('email_verified_at');// Envío de notificación$user->notify(newNewsletterNotification);// Rutas con verificación habilitada['verified'=>true];
Nota: si la barra de progreso marca error de inicialización, reemplaza "create progress bar" por progress start antes de ejecutar de nuevo.
¿Cómo añadir argumentos, filtros y barra de progreso al comando?
Para más control, agrega un argumento opcional tipo array llamado email. Si lo pasas, el comando enviará solo a esos correos. También usaremos un query builder para componer la consulta, un whereIn para filtrar y una barra de progreso para feedback claro.
Argumento opcional tipo array en la firma: email?*.
Recupera el argumento con $this->arguments('email').
Usa una variable builder para la consulta y aplica whereIn si hay correos.
Calcula count para iniciar la barra de progreso.
Avanza la barra con progressAdvance en cada envío y ciérrala con progressFinish.
Mensajes informativos: "Se enviaron X correos" o "No se envió ningún correo".
// Firma con argumento opcional tipo arrayprotected$signature='send newsletter {email?*}';// Recuperar argumento y construir la query$email=$this->arguments('email');$builder=User::whereNotNull('email_verified_at');if($email){$builder->whereIn('email',$email);}$count=$builder->count();$this->output->progressStart($count);// Envío + barra de progreso$builder->each(function($user){$user->notify(newNewsletterNotification);$this->output->progressAdvance();});$this->output->progressFinish();// Mensajes$this->info("Se enviaron {$count} correos");// O, si no hay usuarios:$this->info('No se envió ningún correo');
¿Te animas al reto final? Crea un comando que notifique a los usuarios no verificados registrados hace más de una semana. Cuéntame en comentarios cómo lo resolverías y qué filtros agregarías.
<?php
namespace App\Console\Commands;use Illuminate\Console\Command;use App\Models\User;use Carbon\Carbon;classRequestEmailVerificationextendsCommand{/**
* The name and signature of the console command.
*
* @var string
*/protected $signature ='request:emailverification';/**
* The console command description.
*
* @var string
*/protected $description ='Send an email to all the users that have not verify their email';/**
* Create a new command instance.
*
* @return void
*/publicfunction__construct(){parent::__construct();}/**
* Execute the console command.
*
* @return int
*/publicfunctionhandle(){ $builder =User::query()->whereNull('email_verified_at')->whereDate('created_at','<=',Carbon::now()->subDays(7)->format('Y-m-d'));if($count = $builder->count()){ $this->info("{$count} email will be sent"); $this->output->progressStart($count); $builder->each(function(User $user){ $user->sendEmailVerificationNotification(); $this->output->progressAdvance();}); $this->output->progressFinish(); $this->info('emails sent');}else{ $this->info('No email sent');}return0;}}
Si tienen este error: Cannot send message without a sender address
ejecuten esto: php artisan config:clear
Me dice que se envian demaciadosmensajes por segundo, alguien lo ha solucionado ?
Expected response code 354 but got code "550", with message "550 5.7.0 Requested action not taken: too many emails per second
este profe explica muy bien para quienes ya tenemos esos conceptos avanzados, pues si he hecho varios comandos en mis aplicaciones, pero aca aprendi algunas cosas como pasar param al comando
Buenas, tengo el siguiente error al correr el comando:
mi enviarCorreCoamndo.php
<?php
namespace App\Console\Commands;use App\Notifications\nuevaInformacionNotificacion;use App\User;use Illuminate\Console\Command;classEnviarCorreoComandoextendsCommand{protected $signature ='enviar:usuarioNoAutenticado {emails?*}';protected $description ='Envia un correo electronico a los usuarios que no se autenticaron';publicfunctionhandle(){ $emails = $this->argument('emails'); $builder =User::query();if($emails){ $builder->whereIn('email', $emails);} $cuantos = $builder->count();if($cuantos){ $builder->whereNull('email_verified_at')->each(function(User $user){ $user->notify(newnuevaInformacionNotificacion());}); $this->info("Se enviarion {$cuantos} correos");return;} $this->info('No se enviaron ningun correo');return;}}
nuevaInformacionNotificacion.php:
<?php
namespace App\Notifications;use Illuminate\Bus\Queueable;use Illuminate\Notifications\Notification;use Illuminate\Contracts\Queue\ShouldQueue;use Illuminate\Notifications\Messages\MailMessage;classnuevaInformacionNotificacionextendsNotification{ use Queueable;publicfunctionvia($notifiable){return['mail'];}publicfunctiontoMail($notifiable){return(newMailMessage)->line('The introduction to the notification.')->action('Notification Action',url('/'))->line('Thank you for using our application!');}publicfunctiontoArray($notifiable){return[//];}}
Si alguien tiene alguna sugerencia de cual es el problema, le agradecería su ayuda!
Saludos
Alejandro.
Bueno me contesto a mi mismo, el problema para por el lado de Ubuntu, instale lo siguiente:
sudo apt-get install php-xml
Saludos.
Sería interesante un curso especializado en Eloquent a profundidad ¿Han pensado en ello?
Compañero!
Toda sugerencia de realización de cursos será muy bien recibido si envía el feedback a team@platzi.com para que puedan evaluarlo.
Saludos!
Con la cuenta gratuita de mailtrap se genera un error al tratar de enviar correos masivamente:
Expected response code "354" but got code "550", with message "550 5.7.0 Too many emails per second. Please upgrade your plan https://mailtrap.io/billing/plans/testing".
para superar esto, una solucion muy simple, demorar la ejecucion del codigo un par de segundos:
// Se envia notificacion a cada usuario $builder->whereNotNull("email_verified_at") ->each(function (User $user) { sleep(5); $user->notify(new NewsletterNotification()); $this->output->progressAdvance(); });
Reto cumplido. Usé la librería Carbon para manejar las fechas:
<?php
namespace App\Console\Commands;use Illuminate\Console\Command;use App\Models\User;use App\Notifications\NewsletterNotification;use Illuminate\Support\Carbon;classSendReminderCommandextendsCommand{/**
* The name and signature of the console command.
*
* @var string
*/protected $signature ='send:reminder {emails?*}';/**
* The console command description.
*
* @var string
*/protected $description ='Envía un recordatorio a los usuarios que no han confirmado su correo electrónico.';/**
* Execute the console command.
*/publicfunctionhandle(){ $emails = $this->argument('emails'); $builder =User::query();if($emails){ $builder->whereIn('email', $emails);} $count = $builder->count();if($count){ $this->output->progressStart(); $builder->whereNull('email_verified_at')->whereDate('created_at','<',Carbon::now()->subWeek())->each(function(User $user){ $user->notify(newNewsletterNotification); $this->output->progressAdvance();}); $count = $builder->count(); $this->output->progressFinish();} $this->info($count ?"Se enviaron {$count} correos.":"No se envió ningún correo.");}}
Yo estoy trabajando en Laravel 10. A mi me pareció más estético el resultado con el siguiente código en el handler del archivo SendNewsletterCommand:
Pasa por alto conceptos que nunca se explicaron, ni aquí ni en los cursos requeridos, cada vez peor la calidad de los cursos
Espero que hagan otro curso de laravel avanzado donde se puedan explicar correctamente los distintos conceptos. Y ya que estoy expresando expectativas, que sea version 10.
En el momento 2:48 creo que se equivoca, no es una migración, es nuestro comando
Para que no se sobre escriba el texto info durante la ejecucion de la barra puedes usar un return y cambiar el orden que primero termine la barra y despues escriba el mensaje: