Excepciones personalizadas

Clase 19 de 33Curso Avanzado de Laravel

Resumen

Crear excepciones personalizadas en Laravel te permite validar entradas de forma clara, mantener lógica desacoplada y ofrecer respuestas JSON consistentes. Aquí verás cómo limitar la calificación de productos con un rango configurable, lanzar una excepción específica e internacionalizar el mensaje para el usuario.

¿Cómo limitar el rating con configuración en Laravel?

Configurar el rango de calificación en un archivo dedicado facilita el mantenimiento y la reutilización. El objetivo: aceptar solo valores entre 1 y 5 y rechazar el resto con una excepción.

¿Qué define rating.php en config?

  • Archivo en config/rating.php con claves from y to.
  • Rango inicial: 1 a 5 para la calificación.
  • Sección models para asociar el modelo de rating a la clase creada previamente.

Ejemplo:

// config/rating.php
return [
    'from' => 1,
    'to' => 5,
    'models' => [
        'rating' => App\Models\Rating::class,
    ],
];

¿Cómo valida el trait can rate el score?

  • Usar el trait CanRate para centralizar la validación.
  • Leer configuración: config('rating.from') y config('rating.to').
  • Condición: si $score < $from o $score > $to, lanzar excepción.
$from = config('rating.from');
$to = config('rating.to');

if ($score < $from || $score > $to) {
    throw new InvalidScore($from, $to);
}

¿Cuándo se lanza la excepción personalizada?

  • Al recibir un score fuera del rango configurado.
  • Se ejecuta dentro del trait antes de persistir la calificación.
  • Beneficio: reglas de negocio consistentes en todo el dominio.

¿Cómo crear y capturar la excepción InvalidScore?

La excepción personalizada InvalidScore permite responder con un mensaje claro en JSON y evita mezclar reglas de negocio dentro del handler global.

¿Cómo generar la clase con PHP Artisan make:exception?

  • Comando: php artisan make:exception InvalidScore.
  • Ubicación por defecto: carpeta Exceptions.
  • Lanzamiento: throw new InvalidScore($from, $to).
// En el *trait* CanRate
throw new InvalidScore($from, $to);

¿Cómo responder en JSON desde Handler::render?

  • Opción inicial: verificar instanceof InvalidScore en render del handler y retornar JSON.
  • Mensaje al usuario: el score es inválido y debe estar dentro del rango.
// App\Exceptions\Handler.php
public function render($request, Throwable $e)
{
    if ($e instanceof InvalidScore) {
        return response()->json([
            'message' => 'El score es inválido. Debes ingresar un valor que esté dentro de uno y cinco.',
        ]);
    }

    return parent::render($request, $e);
}

¿Por qué mover la lógica al método render de la excepción?

  • Para no contaminar el handler con lógica de negocio.
  • La excepción puede definir su propio método render y devolver la respuesta JSON directamente.
  • Ventaja: código más limpio y responsabilidad bien definida.
// App\Exceptions\InvalidScore.php
class InvalidScore extends \Exception
{
    public function __construct(public int $from, public int $to)
    {
        parent::__construct();
    }

    public function render($request)
    {
        return response()->json([
            'message' => trans('rating.Invalid score', [
                'from' => $this->from,
                'to' => $this->to,
            ]),
        ]);
    }
}

¿Cómo traducir el mensaje y parametrizar from y to?

Para mensajes consistentes y localizables, define una traducción con variables y úsala desde la excepción. Así, si cambias el rango en la configuración, el mensaje se actualiza automáticamente.

¿Cómo usar archivos de traducción y el helper trans?

  • Crear un archivo de traducción: Recursos/rating.php.
  • Clave: Invalid score con variables :from y :to.
  • Usar el helper trans en el método render de la excepción.
// resources/lang/es/rating.php
return [
    'Invalid score' => 'El valor debe estar dentro de :from y :to.',
];

¿Cómo pasar from y to al constructor de la excepción?

  • Recibir $from y $to en el constructor de InvalidScore.
  • Guardar en propiedades y enviarlas al helper de traducción.
  • Resultado: mensaje dinámico según configuración.
throw new InvalidScore($from, $to);

¿Cómo probar el rango desde el cliente HTTP o tests?

  • Enviar un score fuera del rango a tu endpoint de REST.
  • Incluir un product_id existente y ejecutar la petición.
  • Ver respuesta JSON: “debes ingresar un valor que esté dentro de X y Y.”.
  • Cambiar config a 5 y 10 y repetir: el mensaje refleja el nuevo rango.

  • Habilidades desarrolladas: validación de entrada robusta. manejo de errores con excepciones. configuración centralizada con config. respuestas JSON consistentes. internacionalización con archivos de traducción. diseño limpio usando el método render en la excepción.

¿Quieres compartir cómo estructuraste tu trait o tu archivo de traducción para este caso? Cuéntame en los comentarios y revisamos mejoras puntuales.