Laravel es un framework PHP de código abierto y fácil de usar. Una de sus características más potentes es Eloquent, un mapeador objeto-relacional (ORM) que simplifica el manejo de los registros de la base de datos.

Eloquent acelera las operaciones de creación, lectura, actualización y eliminación en una base de datos desde una aplicación. Cuando utilizas Eloquent, creas modelos que reflejan las tablas de la base de datos y usas esos modelos para crear tus consultas.

Este artículo examina seis elementos de la funcionalidad más potente de Eloquent: ámbitos de consulta, relaciones, mutadores y accesores, colecciones, eliminación de modelos y factories. Explica lo que hace cada función mediante ejemplos prácticos. Esperamos que puedas utilizar estos ejemplos para poner en marcha tu dominio de Laravel Eloquent.

1. Ámbitos de consulta de Eloquent

Cuando construyes una aplicación, a veces te encuentras con situaciones en las que utilizas condiciones más de una vez. Reescribir el código en cada caso puede aumentar la probabilidad de errores y hacer que tu código quede desordenado. Laravel resuelve este problema envolviendo dichas condiciones en sentencias reutilizables llamadas ámbitos.

Los ámbitos de consulta son métodos para añadir lógica de base de datos a un modelo y reutilizar la lógica de consulta.

A continuación se muestra un ejemplo de ámbito de consulta. Supón que quieres crear una plataforma de desarrollo de software para tu equipo que realice un seguimiento de las funciones completadas y en curso. Puedes utilizar esta condición para recuperar sólo las funciones en curso:

$onGoing = Project::where('ongoing', 1)->get();

Puede que necesites esta condición en otras páginas de la aplicación, como la página de estadísticas. Los ámbitos de consulta permiten que una página reutilice la condición anterior, simplificando tu consulta y haciendo que tu código sea más limpio.

A continuación te explicamos cómo puedes utilizar un ámbito de consulta para este escenario:

class Features extends Model
{
    public function scopeOngoing($query)
    {
        return $query->where('ongoing', 0);
    }
}

A continuación, utiliza el siguiente código para ejecutar ese ámbito:

$onGoing = Feature::ongoing()->get();

Hay dos tipos de ámbitos: global y local.

Ámbitos globales

Los ámbitos globales permiten añadir restricciones a todas las consultas de un modelo. Por ejemplo, puedes añadir una condición para filtrar características en función del nombre del jefe de equipo en todas las consultas de tu modelo.

Ámbitos locales

Los ámbitos locales permiten definir restricciones comunes para su reutilización. Por ejemplo, puede que quieras que la aplicación devuelva las características que tienen errores. Tu código podría implementar un ámbito local como éste:

namespace AppModels;
use IlluminateDatabaseEloquentModel;

class User extends Model
{
    public function scopeBugged($query)
    {
        return $query->where('bugged', '>', 1);
    }
}

El código anterior devuelve todas las características que tienen errores no corregidos.

2. Relaciones en Eloquent

Las relaciones en Eloquent te permiten relacionar distintas tablas fácilmente. Por ejemplo, un producto en un sitio web de comercio electrónico puede tener inventario, precio, vistas y opiniones. Con Eloquent, puedes gestionar fácilmente estas relaciones aunque sus registros estén en tablas diferentes.

Puedes definir las relaciones como métodos de las clases del modelo, igual que harías con un modelo Eloquent. Algunas de las relaciones Eloquent más utilizadas son: uno a uno, inversa y polimórfica.

Uno a uno

Aquí tienes un ejemplo de relación básica uno a uno que asocia un modelo de producto con un inventario.

public function Inventory()
{
    return $this->hasOne('AppInventory');
}

En el código anterior, el método Inventory() llama al método hasOne() del modelo de producto. Éste comprueba si el producto está disponible en ese momento.

Inversa

Eloquent también te permite crear una relación inversa. Por ejemplo, cuando quieras obtener productos en función de su número de vistas. Las relaciones inversas pueden proporcionarte los productos que suscitan más interés entre los visitantes de un sitio web. Puedes utilizar el método belongsTo(), que es el inverso de hasOne(). El siguiente código lo ilustra.

public function product()
{
    return $this->belongsTo('AppProduct');
}

En el código anterior, Eloquent hace coincidir el product_id con el número de vistas pasadas. El product_id puede entonces ayudar a obtener otros parámetros, como el precio y el inventario.

Polimórfica

En el desarrollo de aplicaciones, las relaciones no siempre son sencillas. A veces, tienes un modelo que pertenece a más de un tipo de modelo. Por ejemplo, los modelos de producto e inventario pueden tener relaciones polimórficas con un modelo de imagen.

Las relaciones polimórficas te permitirían utilizar la misma lista de imágenes tanto para el inventario como para los productos. A continuación se muestra un fragmento de código que implementa una relación polimórfica.

class Image extends Model
{
    /**
     * Getting the shared image.
     */
    public function myimage()
    {
        return $this->morphTo();
    }
}

class Product extends Model
{
    /**
     * Get the image to use on the product's page.
     */
    public function image()
    {
        return $this->morphOne(Image::class, 'myimage');
    }
}

class Inventory extends Model
{
    /**
     * Get the image to use on the inventory page.
     */
    public function image()
    {
        return $this->morphOne(Image::class, 'myimage');
    }
}

El código anterior utiliza el método morphTo() para recuperar la entidad principal del modelo polimórfico.

Esto es sólo la punta del iceberg sobre este tema. Para saber más, consulta nuestra guía avanzada sobre las relaciones Eloquent de Laravel.

3. Mutadores y accesores Eloquent

Los mutadores y accesores te permiten alterar los datos mientras los almacenas y recuperas. Los mutadores modifican los datos antes de guardarlos, mientras que los accesores lo hacen al recuperarlos.

Si quieres almacenar nombres en minúsculas en tu base de datos, puedes crear un mutador para ejecutar esa transformación. Si quieres mostrar el nombre y los apellidos del usuario como un solo nombre en las páginas de tu app, puedes crear un accesor para conseguirlo.

A continuación se muestra un ejemplo de un mutador que pone los nombres en mayúsculas antes de guardarlos.

class User extends Model
{
    /**
     * Mutators capitalizing first and last name.
     */
    public function setFirstNameAttribute($value)
    {
        $this->attributes['first_name'] = ucfirst($value);
    }

    public function setLastNameAttribute($value)
    {
        $this->attributes['last_name'] = ucfirst($value);
    }
}

A continuación se muestra un ejemplo de un accesor que combina el nombre y los apellidos del usuario.

class User extends Model
{
    /**
     * Accessor combining both names.
     */
    public function getFullNameAttribute()
    {
        return ucfirst($this->first_name) . ' ' . ucfirst($this->last_name);
    }
}

4. Colecciones de Eloquent

Las colecciones de Eloquent manejan métodos que devuelven múltiples resultados del modelo. Esta clase se encuentra en IlluminateDatabaseEloquentCollection.

Al igual que con los arrays, es posible iterar a través de las colecciones. A continuación se muestra una iteración sencilla.

use AppModelsProduct;

$products = Product::where('availability', 1)->get();

foreach ($products as $product) {
   echo $product->name;
}

Las colecciones son más potentes que los arrays porque puedes realizar operaciones más complejas con ellas. Por ejemplo, puedes mostrar la lista de todos los productos disponibles y omitir todos los que no estén «activos»

$names = Product::all()->reject(function ($product) {
   return $product->active === false;
})->map(function ($product) {
   return $product->name;
});

A continuación se muestran algunos de los métodos que proporciona la clase colecciones.

Contains

El método contains() comprueba si el código contiene un modo especificado, como se muestra en el código siguiente:

$products->contains(1);
$products->contains(Product::find(1));

All

El método all() devuelve los modelos contenidos en la colección, como se muestra a continuación:

$collection = Product::all();

La clase colecciones admite muchos otros métodos.

5. Eliminar modelos de Eloquent

En Eloquent, creas modelos para ayudar a construir consultas. Sin embargo, a veces necesitas eliminar modelos para que una aplicación sea más eficiente. Para ello, llama a delete en la instancia del modelo.

use AppModelsStock;

$stock = Stock::find(1);
$stock->delete();

El código anterior elimina el modelo Stock de una aplicación. Se trata de una eliminación permanente que no puede deshacerse.

Eliminación suave (Soft delete)

Otra función que contiene Eloquent es la capacidad de borrado suave de modelos. Cuando borras suavemente un modelo, no lo eliminas de la base de datos.

Lo marcas utilizando deleted_at para indicar la hora y la fecha del borrado suave. Esto es importante cuando quieres excluir una parte de los registros de la base de datos, como los que están incompletos, sin eliminarlos permanentemente. Ayuda a limpiar los resultados de las consultas de Eloquent sin añadir condiciones adicionales.

Puedes activar la eliminación suave añadiendo el trait softDeletes a un modelo y añadiendo una columna deleted_at en la tabla de base de datos relacionada.

Añadir el borrado suave a un modelo

Para activar el borrado suave de un modelo, añade el trait IlluminateDatabaseEloquentSoftDeletes, como se muestra a continuación.

namespace AppModels;
use IlluminateDatabaseEloquentModel;
use IlluminateDatabaseEloquentSoftDeletes;

class Flight extends Model
{
   use SoftDeletes;
}

Cómo añadir una columna delete_at

Antes de que puedas empezar a utilizar el borrado suave, tu base de datos debe tener una columna delete_at. Añade esta columna utilizando un método de ayuda del constructor de Laravel Schema, como se muestra a continuación:

use IlluminateDatabaseSchemaBlueprint;
use IlluminateSupportFacadesSchema;

Schema::table('users', function (Blueprint $table) {
   $table->softDeletes();
});

Schema::table('users', function (Blueprint $table) {
   $table->dropSoftDeletes();
});

Esto añade una columna delete_at que se actualiza con la fecha y la hora, en caso de que una acción de borrado suave tenga éxito.

Cómo incluir modelos con borrado suave

Si quieres que los resultados de la consulta incluyan modelos con borrado suave, debes añadir el método withTrashed() a la consulta. A continuación se muestra un ejemplo:

$stocks = Stock::withTrashed()->where('stock_id', 20)->get();

La consulta anterior también incluirá los modelos con el atributo deleted_at.

Cómo recuperar únicamente modelos con borrado suave

Eloquent también permite recuperar exclusivamente modelos con borrado suave. Puedes hacerlo llamando al método onlyTrashed(), por ejemplo:

$Stock = Stock::onlyTrashed()->where('stock_id', 1)->get();

Cómo restaurar modelos con borrado suave

También puedes restaurar los modelos borrados en pantalla llamando al método restore().

$stocks = Stock::withTrashed()->where('stock_id', 20)->restore();

Esto cambia el campo delete_at de un modelo con borrado suave a null. Si el modelo no ha sido borrado suavemente, deja el campo sin cambios.

6. Eloquent Factories

Las Factories de modelos en Laravel crean datos ficticios que puedes usar para probar tu aplicación o para sembrar tu base de datos. Para implementar esto, creas un modelo en una clase Factory, como se muestra en el ejemplo a continuación. El fragmento de código crea una factory de modelo que puede generar proveedores ficticios de un producto y sus precios.

namespace DatabaseFactories;
use IlluminateDatabaseEloquentFactoriesFactory;
use IlluminateSupportStr;

class StockFactory extends Factory
{
    public function definition()
    {
        return [
            'supplier_name' => fake()->name(),
            'price' => fake()->numberBetween($min = 1500, $max = 6000),
        ];
    }
}

El método definition() del ejemplo anterior devuelve un conjunto de valores de atributos que Laravel utiliza al construir el modelo. El ayudante fake facilita que la factory acceda a la biblioteca de PHP, Faker.

Resumen

Eloquent simplifica las tareas de desarrollo de aplicaciones en Laravel. Es igual de eficaz a la hora de construir consultas simples o complejas, gracias a implementaciones como las relaciones. La sencillez de generar datos ficticios funcionales mediante factories lo hace perfecto para los desarrolladores que quieren crear pruebas robustas para sus aplicaciones. Además, los ámbitos de Eloquent ayudan a simplificar las consultas complejas de forma que el código quede ordenado.

Aunque este artículo sólo ha abordado seis de sus principales características, Eloquent tiene otras potentes funcionalidades. El uso de modelos compartibles y reutilizables ha hecho de Eloquent una característica popular entre los desarrolladores, y la simplicidad de las consultas de Eloquent hace de Laravel un framework fácil de usar para los desarrolladores, incluso para los principiantes.

Sea cual sea tu nivel de experiencia, la plataforma de Alojamiento de Aplicaciones web de Kinsta apoya a desarrolladores como tú. Nuestra plantilla de inicio rápido de Laravel muestra lo fácil que es poner en marcha tu aplicación en nuestros servidores dentro de la red de nivel premium de Google Cloud.

Steve Bonisteel Kinsta

Steve Bonisteel es un Editor Técnico de Kinsta que comenzó su carrera de redactor como periodista de prensa escrita, persiguiendo ambulancias y camiones de bomberos. Lleva tratando temas relacionados con la tecnología de Internet desde finales de la década de 1990.