Parámetros opcionales en las rutas de Laravel NO tienen sentido... - Opinión
Fíjate en algo muy curioso que me parece que tiene Laravel, y de lo cual realmente no me había dado cuenta hasta ahora. Estoy trabajando con una ruta que tiene un parámetro completamente opcional, y te explico lo que descubrí.
Tengo una ruta que apunta a /store/{productType?}, donde productType es un modelo (una categoría o clasificación). Este puede ser opcional, como lo indico en la definición.
Cuando se accede a /store sin ningún parámetro, el valor debería ser nulo o simplemente no estar definido.
Cuando se accede a /store/zapatos, entonces sí está definido.
Ahora viene lo curioso. Uno pensaría que, si este parámetro es opcional y no se pasa, el valor debería ser nulo, ¿cierto?
Como en Livewire este valor lo recibo en el mount(), asumí que simplemente podía hacer algo como:
function mount(?ProductType $productType)
{
$this->productType = $productType->id ? $productType : null;
}
En el caso de /store/zapatos, todo funciona como se espera: $productType tiene un valor válido.
Pero en /store, en vez de recibir un valor null, Laravel me pasa una instancia vacía del modelo ProductType.
Este comportamiento me choca un poco. Es como si Laravel estuviera haciendo esto internamente:
$productType = new ProductType;
Esto tiene sentido en ciertos contextos, como cuando trabajas con formularios para crear o editar modelos, donde quieres una instancia vacía para reutilizar código. Pero en este caso específico no tiene sentido.
Supongo que esto tiene que ver con el null safety, algo que se implementó más formalmente en versiones recientes de PHP. Pero me molesta porque:
- Te puede romper la lógica si asumes que estás trabajando con un objeto válido de base de datos.
- Puedes acceder al título ($productType->title) y te devuelve null, pero no sabes si eso es porque no existe en base de datos o porque Laravel te pasó una instancia vacía.
¿Y Si Fuerzo el Parámetro a ser Nulo?
Pensé en forzar el tipo de parámetro en el mount() como nullable:
function mount(?ProductType $productType = null)
{
***
}
Pero si accede se accede a /store Laravel lanza un 404 directamente si no encuentra el modelo. Es decir, ni siquiera llega al componente. Esto me molesta más todavía, porque rompe la ruta sin razón aparente.
Como me gustaría que trabajase
Yo preferiría que Laravel me dejara trabajar con un null directamente. Es más limpio para las validaciones y para quien mantiene el código.
Por ejemplo, es mucho más sencillo validar:
if ($productType)
Que:
if (is_null($productType->title)) ...
Esto último genera confusión para cualquier desarrollador que venga después:
¿El título es nulo porque así lo definiste tú, o porque Laravel creó un objeto vacío?
En Resumen
- Laravel no devuelve null cuando el modelo es opcional y no se encuentra: devuelve una instancia vacía.
- Si defines el parámetro como nullable, Laravel retorna un 404 si el modelo no existe.
- Este comportamiento es curioso y un poco molesto, al menos para mí.
- No sé desde qué versión exactamente funciona así, pero intuyo que es reciente.
Acepto recibir anuncios de interes sobre este Blog.
Hacemos un ejemplo de un parámetro opcional en la ruta, definir el parámetro como nulo y pruebas en general.
- Andrés Cruz