Trucos y recetas para Laravel Eloquent

arrow_back Blog

Laravel Eloquent es el ORM de Laravel Framework, Si estás empezando en Laravel y no conoces mucho acerca de Eloquent, revisa nuestra entrada Introducción a Laravel Eloquent, es una introducción con todo lo que necesitas saber para empezar.

En este tutorial te voy a mostrar una serie de características de Laravel Eloquent que muchas veces pasan desapercibidas y son realmente potentes. Estoy seguro que muchas no las conoces, y otras sí, presta atención y exprime Eloquent al máximo.

Eloquent when, no más if-else

Cuando no conocemos el método when de los modelos Eloquent, normalmente hacemos lo siguiente para filtrar datos en nuestros modelos:

Con el método when podemos hacer lo siguiente:

Como puedes ver, eliminamos los condicionales, Eloquent hará la magia.

Accessors y Mutators mejorados en Laravel 9

En versiones anteriores de Laravel, para definir accesors y mutators hacíamos lo siguiente:

Lo cual sigue funcionando y podemos seguir utilizando, pero es mucho mejor hacer lo siguiente:

Un único método con un get y un set para crear el accessor y el mutator, fantástico.

Deshabilitar los timestamps en Eloquent

Existen muchos modelos en nuestros proyectos que no necesitan las columnas created_at y updated_at, ya que realmente no es un dato relevante y sólo ocupa espacio y gasta recursos.

Para decirle a Eloquent que un modelo no tiene timestamps, sólo debemos añadir lo siguiente en nuestros modelos:

Eloquent boot

El método boot de los modelos Eloquent nos permite interactuar con nuestros modelos cuando algún evento ha sucedido, a continuación, te adjunto los eventos que tenemos disponibles:

El evento forceDeleted estará disponible si nuestro modelo utiliza el trait Softdeletes.

En cada evento, podremos modificar la función callback para realizar las tareas que necesitemos, generar slugs, notificar a alguien, realizar procesos, o simplemente nada.

saveQuietly

Aunque hayamos definido eventos en nuestro modelo Eloquent, existirán casos en los que no deseemos que dichos eventos se desencadenen, para ello, podemos guardar los datos haciendo uso del método saveQuietly:

Métodos XorY

Eloquent nos ofrece varios métodos que realizan más de una tarea, veamos cuales son.

findOrFail

Busca un modelo o lanza una excepción Illuminate\Database\Eloquent\ModelNotFoundException:

firstOrCreate

Busca un modelo por los atributos pasados en el primer parámetro, si lo encuentra, lo retorna, en otro caso, lo crea, y lo guarda en base de datos, haciendo uso del primer y el segundo parámetro:

firstOrNew

Similar al método findOrFail, con la diferencia de que el modelo no será persistido en base de datos, si deseas guardarlo, deberás utilizar el método save de Eloquent:

firstOr

Busca un modelo, en caso de no encontrarlo, podemos utilizar una Closure para hacer lo que deseemos, crear un registro u obtener uno por defecto:

En nuestro caso, si no existe una categoría con nombre Category Special, retornaremos la primera categoría de nuestra tabla.

updateOrCreate

Este método es ideal para operaciones CRUD, ya que podemos crear una acción que haga una operación upsert, update or insert:

Busca una categoría por su nombre, si no la encuentra la crea, si la encuentra, la actualiza.

Guardar modelos y sus relaciones

Si en algún momento necesitamos guardar modelos con sus relaciones en Eloquent, lo mejor sin duda es utilizar el método push de la siguiente forma:

Fíjate cómo el método push persistirá en base de datos tanto el post como la categoría.

Detectar si un modelo se acaba de crear

Eloquent nos permite saber si un modelo se acaba de crear, esto es especialmente útil si utilizamos el método updateOrCreate, ya que nosotros en ese momento no tenemos forma de saberlo.

Por suerte para nosotros, la propiedad wasRecentlyCreated nos ofrece esta información:

Detectar si un modelo ha cambiado

isDirty nos informa acerca de si el modelo ha cambiado en algo, podemos hacer contra el modelo en su totalidad, o contra algún atributo:

Métodos whereX

Eloquent nos permite hacer uso de métodos mágicos que realmente no existen en ningún lugar:

Replicar modelos

En algunas ocasiones necesitamos crear modelos que contiene información igual o muy parecida a otros, para llevar a cabo esta tarea, lo mejor es hacer uso del método replicate:

Error de carga N+1 en Eloquent

En Eloquent podemos obtener un modelo y acceder a sus relaciones de la siguiente forma:

El código anterior realizará una consulta a base de datos por cada post que tenga ese usuario, si tiene 10 posts, hará 10 consultas adicionales, un auténtico problema.

Para solucionar este problema simplemente debemos hacer uso de la carga perezosa (Eager Loading) de Eloquent y definir qué relaciones queremos cargar:

Con eso Eloquent únicamente realizará una única consulta para obtener todos los posts del usuario realizando una consulta whereIn(?).

Eager Loading: Selección de columnas

Cuando cargamos relaciones en nuestras consultas, debemos preocuparnos de sólo traer aquellos datos que podamos necesitar, y no todos, de otra forma estaremos haciendo mal uso de Eloquent y nuestra aplicación se verá penalizada:

En este caso estamos obteniendo una categoría y sus posts, pero sólo queremos las columnas id, name y category_id.

Como dato, decirte que siempre que cargues relaciones de esta forma, deberás añadir a la select la PK y la FK involucradas para que las relaciones puedan ser cargadas correctamente.

Deshabilitar Lazy Loading

Si no prestamos atención a la carga de relaciones en Eloquent, es posible que tengamos un problema de consultas (N+1).

Imagina que queremos mostrar un listado de posts y su categoría al lado del título, si no realizamos la carga perezosa del modelo Category con Eloquent, por cada iteración, tendremos una consulta más para cada categoría, algo que arruinará nuestra aplicación.

Para evitar este comportamiento, podemos decirle a Eloquent que directamente no permita esta característica, y si sucede, que lance una excepción.

Al método preventLazyLoading podemos pasarle un booleano, si es false, Laravel no lanzará excepciones.

Chunk: manipulando grandes cantidades de datos

El método chunck de los modelos Eloquent nos permite hacer trozos de nuestros modelos, de esta forma, si tenemos 500 categorías en nuestra tabla categories, haciendo lo siguiente iteraremos 5 veces en lugar de 500 y podremos mejorar la performance de nuestra aplicacion:

Modificar los Timestamps

Esto suele ser algo que necesitamos hacer cuando la base de datos es heredada de alguna aplicación que debemos migrar. Si las columnas created_at o updated_at tienen otros nombres, Eloquent no sabrá cómo gestionar los timestamps.

Por suerte, en Eloquent podemos ajustar nuestros modelos de la siguiente forma:

Exactamente igual podemos hacer si nuestro modelo utiliza borrados lógicos:

Rutas con SoftDeletes

Desde Laravel 9, podemos crear rutas haciendo uso del método withTrashed para obtener registros borrados de forma lógica en nuestra base de datos.

Con esto me refiero a que si un modelo tiene la columna deleted_at con valor en una tabla, podríamos obtener dicho modelo a través de las rutas de la siguiente forma:

Además, desde Laravel 9.35, también podemos hacer esto para rutas resource:

Obtener muchos con el método find

Seguramente no lo sabías, pero el método find de Eloquent, además de permitir identificados, también admite un array, si le pasamos un array, en lugar de retornar un único registro, retornará todos los que tengan los ids pasados.

Especificar columnas en el método find

Cuando utilizamos el método find, también podemos definir qué columnas queremos seleccionar de la siguiente forma:

Especificar columnas en el método findOrFail

Igual que con el método find podemos seleccionar columnas, también podemos hacerlo con el método findOrFail:

Boot para cada Trait en Eloquent

En Eloquent podemos hacer que cada Trait ejecute su propio método boot, imagina que tenemos un Trait llamado HasUser que queremos añadir a aquellos modelos donde exista una relación con un usuario, en lugar de ir añadiendo el método boot en cada modelo, podríamos hacer lo siguiente en nuestro Trait HasUser:

Para ello sólo debemos definir el método boot{TraitName}, en nuestro caso bootHasUser, y Eloquent hará el resto.

whereRelation, atajo de whereHas

Imagina que tienes usuarios con un país asociado en tu base de datos y deseas obtener los usuarios de un país concreto por el nombre del país. Utilizando el método whereHas deberíamos hacer esto:

Utilizando el método whereRelation quedaría de la siguiente forma:

Así de sencillo sería obtener datos utilizando columnas de modelos relacionados en Eloquent.

addSelect, generar columnas al vuelo

Podríamos utilizar el método addSelect en Eloquent para saber la duración total de un curso de la siguiente forma:

De esta forma, podríamos generar una nueva columna llamada total_duration haciendo la suma de todas las unidades que componen el curso.

withDefault

El método withDefault nos permite definir datos por defecto a las relaciones de nuestros modelos. Imagina que cuando se registra un usuario el país no es un campo requerido, o que lo has añadido más tarde a tu base de datos y ahora aparece en null. Si necesitamos tener un valor por defecto, podríamos modificar la relación country en el modelo User:

Si ahora obtenemos un usuario que no tenga un país asociado, veremos que el valor de country.name es Unknown.

latestOfMany

Algunas veces necesitamos obtener en diferentes lugares de nuestra aplicación el último registro de un modelo. Podemos escribir una consulta u obtenerlo directamente con el método latestOfMany. En nuestro caso vamos a obtener el último comentario de una relación con posts:

Prunable, manteniendo limpia la BD

Desde Laravel 8.5 tenemos a nuestra disposición un trait llamado Prunable. Este trait podemos utilizarlo en nuestros modelos Eloquent y puede ser útil en muchos casos.

Añadiendo el trait y definiendo el método prunable con la condición que se debe cumplir para eliminar los registros no es suficiente. Para que los registros que no deseamos vayan desapareciendo de nuestra base de datos debemos ejecutar el comando php artisan model:prune, y como no, lo mejor es utilizar el scheduler de Laravel:

Cada día a las 3 AM el scheduler de Laravel eliminará los registros que utilicen el trait prunable utilizando la consulta aplicada en el método prunable de cada modelo.

saveMany y saveManyQuietly

Cuando tenemos que relacionar múltiples modelos a un modelo existente, podemos caer en el error de realizar la operación en un bucle, debemos entender que esa metodología es errónea y provocará realizar demasiadas consultas a la base de datos.

En lugar de eso, podemos utilizar los métodos saveMany o saveManyQuietly de Eloquent de la siguiente forma:

De esta forma habremos relacionado tres comentarios a un post.

getOriginal

Algunas veces necesitamos saber qué información había originalmente en un modelo después de hacer una modificación. El método getOriginal nos permite hacer esto a través de un atributo o del objeto completo:

Es importante tener en cuenta que el método getOriginal nos dirá la verdad si no hemos utilizado el método save, una vez hemos persistido los datos en base de datos, getOriginal nos devolverá los datos actualizados.

getChanges

Si lo que necesitamos saber son los cambios aplicados a un modelo una vez se ha persistido en base de datos, entonces debemos hacer uso del método getChanges:

Cancelar operaciones de guardado utilizando eventos

Imagina que quieres poner un check en tus modelos para que si una condición no se cumple, no se haga el cambio en base de datos, sea un alta, una edición o un borrado. Pues justo esto lo podemos hacer a través del método boot:

Retornando false en los eventos de Eloquent podemos deshacer la operación.

Métodos Raw en Eloquent

Existen ocasiones en las que necesitamos ejecutar código SQL en nuestras consultas, para ello, podemos utilizar los métodos raw del Builder de Laravel, tanto para el QueryBuilder como para el Builder de Eloquent.

havingRaw

En el siguiente ejemplo, obtenemos los posts que tengan 3 o más comentarios:

selectRaw

También podemos utilizar el método selectRaw para hacer una consulta select específica:

orderByRaw

Otra cosa que podemos hacer es utilizar los métodos de ordenación, en este caso orderByRaw:

Puedes ver que los ejemplos utilizados con los métodos raw de Eloquent son sencillos, lo importante es el concepto, con los métodos raw podremos solucionar muchos problemas llegado el momento.

Métodos whereXAndX~ y whereXOrX~

Estos métodos seguramente no los has visto antes. Imagínate que necesitas buscar un proyecto por id de usuario y título. Como todo en Eloquent, existen diferentes caminos para hacerlo, el primero y más sencillo sería el siguiente:

Alternativamente podríamos hacer lo siguiente utilizando los métodos whereX que ya conocemos:

Pero en Eloquent tenemos más opciones:

Pero además, podemos concatenar más cláusulas, por ejemplo una cláusula where con una cláusula orWhere:


Hasta aquí esta entrada acerca de Laravel Eloquent, espero que te haya parecido interesante y te haya ayudado a profundizar más en este poderoso ORM.

Si te ha servido, comparte la entrada con tus conocidos.

Si quieres seguir aprendiendo Laravel Eloquent haciendo uso de las mejores prácticas, no te pierdas nuestro curso de Eloquent ORM.

Cursosdesarrolloweb Cursosdesarrolloweb

Cursosdesarrolloweb es una plataforma educativa con cursos y tutoriales en texto y vídeo.

Términos y condiciones Política de privacidad Formulario de contacto

Copyright 2023 © Todos los derechos reservados.

Contacto