Ejecutar acciones cuando un modelo se crea, se edita o se elimina en Laravel

Muchas veces, en nuestros back-end, tenemos que realizar varias acciones una vez un registro se inserta / edita. Para esto, podemos usar los eventos de Eloquent.

Ejecutar acciones cuando un modelo se crea, se edita o se elimina en Laravel
Photo by Dell / Unsplash

Muchas veces, en nuestros back-end, tenemos que realizar varias acciones una vez un registro se inserta / edita. Por ejemplo:

  • Enviar un e-mail cuando se crea un pedido o cambia de estado
  • Comprimir una imagen o un vídeo al subirla a la web
  • Ejecutar un job de importación de datos, etc.

Por ejemplo, para realizar un pedido nuestro código podría ser así:

<?php

namespace App\Http\Controllers;

use App\Models\Order;
use App\Mail\NewOrderEmail;
use Illuminate\Http\Request;
use Mail;

class OrderController extends Controller
{
    public function executeOrder(Request $request)
    {
    	// validation...
        // $request->validate([...]);
        
        $order = new Order();
        // ...
        $order->save();
        
        Mail::to($order->user->email)->send(new NewOrderEmail($order));
        Mail::to(config('platform.admin.email'))->send(new NewOrderEmail($order));
    }
}

Aunque este código no esté mal, aún se puede abstraer esta lógica de "¿qué tiene que pasar cuando se cree un pedido en nuestra plataforma?" a un lugar más "reutilizable". Esta lógica de negocio debería ser la misma y ejecutarse de manera automática independientemente de si el pedido se crea desde la web, a través de la app, a través de la API o a través de un panel de administración interno. Además, ¡idealmente sin repetir el código!

Para ello, Eloquent nos provee con varios eventos a los que podemos escuchar:

Evento Descripción
retrieved Un modelo se descarga de la base de datos
creating Cuando un modelo se está guardando por primera vez, pero antes de guardarse
created Cuando un modelo se guarda por primera vez
updating Justo antes de ejecutar el UPDATE del modelo en base de datos
updated Cuando un modelo se actualiza
saving Cuando un modelo se está guardando (sea para crear o editar)
saved Cuando un modelo se ha guardado
deleting Justo antes de eliminar un modelo
deleted Cuando un modelo es eliminado
trashed Cuando un modelo es marcado como deleted_at en la base de datos
forceDeleted Cuando un modelo se elimina permanentemente de la base de datos
restoring Cuando se está restaurando un modelo de la base de datos
restored Cuando se restaura un modelo de la base de datos
replicating Cuando se duplica un modelo

Desde Eloquent podemos escuchar a estos eventos y ejecutar acciones:

<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;
 
class Order extends Model
{
    /**
     * The "booted" method of the model.
     *
     * @return void
     */
    protected static function booted()
    {
        static::created(function (Order $order) {
            Mail::to($order->user->email)->send(new NewOrderEmail($order));
        	Mail::to(config('platform.admin.email'))->send(new NewOrderEmail($order));
        });
    }
}

Además, puedes definir directamente que la función se ejecute en el sistema de colas:

<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;
 
class Order extends Model
{
    /**
     * The "booted" method of the model.
     *
     * @return void
     */
    protected static function booted()
    {
        static::created(queueable(function (Order $order) {
            Mail::to($order->user->email)->send(new NewOrderEmail($order));
        	Mail::to(config('platform.admin.email'))->send(new NewOrderEmail($order));
        }));
    }
}

De esta forma, da igual desde donde se haya creado el pedido, siempre se enviará un email al usuario y al administrador de la plataforma sin tener que reutilizar código.