Laravel

Laravel

Tutorial Laravel: Bases de datos y Eloquent ORM

Aprende a usar Eloquent ORM para persistencia en aplicaciones web PHP con bases de datos SQL y almacenar modelos persistentes.

Aprende Laravel GRATIS y certifícate

Configuración de la base de datos

Para aprovechar al máximo el framework Laravel, es imprescindible configurar correctamente la conexión a la base de datos. Laravel simplifica este proceso mediante el uso de archivos de configuración y variables de entorno, lo que facilita la gestión de diferentes entornos como desarrollo, pruebas y producción.

Archivo .env

El archivo .env ubicado en la raíz del proyecto contiene las variables de entorno que definen la configuración específica de cada entorno. Para configurar la base de datos, es necesario editar las siguientes líneas:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=nombre_base_datos
DB_USERNAME=usuario
DB_PASSWORD=contraseña
  • DB_CONNECTION: especifica el controlador de base de datos a utilizar, como mysql, pgsql, sqlite o sqlsrv.
  • DB_HOST: define la dirección IP o el nombre del host del servidor de base de datos.
  • DB_PORT: indica el puerto por el cual se establece la conexión (por defecto, 3306 para MySQL).
  • DB_DATABASE: nombre de la base de datos a la que se conectará Laravel.
  • DB_USERNAME y DB_PASSWORD: credenciales de acceso a la base de datos.

Es fundamental mantener estas credenciales seguras y no compartir el archivo .env públicamente. Las variables de entorno permiten cambiar la configuración sin modificar el código fuente, lo que mejora la seguridad y la flexibilidad de la aplicación.

Archivo de configuración config/database.php

El archivo config/database.php contiene la configuración global de las conexiones a bases de datos en Laravel. Aunque el archivo referencia a las variables de entorno, es importante revisarlo para comprender cómo Laravel gestiona las conexiones:

'default' => env('DB_CONNECTION', 'mysql'),

'connections' => [

    'mysql' => [
        'driver' => 'mysql',
        'url' => env('DATABASE_URL'),
        'host' => env('DB_HOST', '127.0.0.1'),
        'port' => env('DB_PORT', '3306'),
        'database' => env('DB_DATABASE', 'nombre_base_datos'),
        'username' => env('DB_USERNAME', 'usuario'),
        'password' => env('DB_PASSWORD', 'contraseña'),
        'unix_socket' => env('DB_SOCKET', ''),
        'charset' => 'utf8mb4',
        'collation' => 'utf8mb4_unicode_ci',
        'prefix' => '',
        'prefix_indexes' => true,
        // Otras opciones...
    ],

    // Otras conexiones...

],
  • La opción default determina la conexión por defecto que utilizará la aplicación.
  • En el arreglo connections, se definen las diferentes conexiones de base de datos disponibles.
  • Cada conexión utiliza las variables de entorno para mantener la configuración dinámica y segura.

Configuración para diferentes bases de datos

Laravel es compatible con múltiples sistemas de gestión de bases de datos. A continuación, se muestran ejemplos de configuración para algunos de ellos.

MySQL

Ya se ha mostrado la configuración básica para MySQL. Asegúrese de que el servicio de MySQL esté en ejecución y que el usuario tenga los permisos adecuados.

PostgreSQL

Para configurar PostgreSQL, ajuste las variables en el archivo .env:

DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=nombre_base_datos
DB_USERNAME=usuario
DB_PASSWORD=contraseña

Y modifique la conexión correspondiente en config/database.php:

'pgsql' => [
    'driver' => 'pgsql',
    'url' => env('DATABASE_URL'),
    'host' => env('DB_HOST', '127.0.0.1'),
    'port' => env('DB_PORT', '5432'),
    'database' => env('DB_DATABASE', 'nombre_base_datos'),
    'username' => env('DB_USERNAME', 'usuario'),
    'password' => env('DB_PASSWORD', 'contraseña'),
    'charset' => 'utf8',
    'prefix' => '',
    'prefix_indexes' => true,
    'schema' => 'public',
    'sslmode' => 'prefer',
],

SQLite

SQLite es ideal para entornos de desarrollo y pruebas debido a su simplicidad. Para utilizar SQLite:

  1. Cree un archivo de base de datos en el directorio database:
touch database/database.sqlite
  1. Actualice el archivo .env:
DB_CONNECTION=sqlite
DB_DATABASE=/ruta/al/proyecto/database/database.sqlite
  1. En config/database.php, asegúrese de que la conexión SQLite esté configurada:
'sqlite' => [
    'driver' => 'sqlite',
    'url' => env('DATABASE_URL'),
    'database' => env('DB_DATABASE', database_path('database.sqlite')),
    'prefix' => '',
    'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
],

Pruebas y migraciones

Una vez configurada la base de datos, es recomendable ejecutar las migraciones para crear las tablas necesarias:

php artisan migrate

Este comando utiliza las migraciones definidas en el directorio database/migrations para crear la estructura de la base de datos. Si la configuración es correcta, verá mensajes indicando que las migraciones se han ejecutado con éxito.

Ejecución del servidor de desarrollo

Para verificar que la aplicación funciona correctamente con la base de datos, ejecute el servidor de desarrollo integrado de PHP desde la carpeta principal del proyecto:

php -S localhost:8000 -t public

Esto iniciará el servidor en http://localhost:8000. Al acceder, Laravel debería mostrar la página de bienvenida o la interfaz definida en sus rutas y controladores.

Uso de variables de entorno adicionales

En casos donde se necesiten múltiples conexiones o configuraciones avanzadas, puede definir variables de entorno adicionales, como:

DB_READ_HOST=127.0.0.1
DB_READ_USERNAME=usuario_read
DB_READ_PASSWORD=contraseña_read

Y configurar las conexiones en config/database.php utilizando dichas variables. Esto es útil para implementar estrategias de replicación o separar lecturas y escrituras.

La correcta configuración de la base de datos es esencial para el funcionamiento de una aplicación Laravel. Utilizar variables de entorno y mantener las credenciales fuera del código fuente mejora la seguridad y facilita la gestión de diferentes entornos. Asegúrese siempre de proteger el archivo .env y de no incluirlo en el control de versiones.

Introducción a Eloquent ORM

El Eloquent ORM es el mapeador objeto-relacional que Laravel incorpora para facilitar la interacción con bases de datos de forma orientada a objetos. Eloquent proporciona una capa de abstracción que permite trabajar con las tablas y registros de la base de datos como si fueran clases y objetos en PHP, simplificando así las operaciones CRUD (Crear, Leer, Actualizar y Eliminar).

Con Eloquent, no es necesario escribir consultas SQL manualmente, ya que ofrece una sintaxis elegante y fluida para construir las consultas mediante métodos de PHP. Esto mejora la legibilidad y el mantenimiento del código, haciendo que las interacciones con la base de datos sean más intuitivas para los desarrolladores.

Una de las ventajas más destacadas de Eloquent es su capacidad para manejar las relaciones entre modelos de manera sencilla. Soporta relaciones uno a uno, uno a muchos, muchos a muchos, entre otras, y permite acceder y manipular los datos relacionados utilizando métodos y propiedades definidas en los modelos.

Eloquent sigue una serie de convenciones por defecto que facilitan su uso. Por ejemplo, asume que cada tabla de la base de datos tiene una clave primaria llamada id y que el nombre del modelo en plural corresponde al nombre de la tabla. Estas convenciones pueden ser personalizadas si la estructura de la base de datos no sigue estos estándares.

Además, Eloquent incluye características avanzadas como eventos, observadores, scopes y mutadores, que permiten extender su funcionalidad y adaptarla a las necesidades específicas de cada proyecto. También facilita la serialización de modelos a formatos como JSON, lo cual es útil para la creación de APIs y servicios web.

La integración de Eloquent con el resto de componentes de Laravel es muy estrecha. Por ejemplo, se puede combinar con migraciones para gestionar la estructura de la base de datos y con seeders para poblarla con datos de prueba. Asimismo, al utilizar Eloquent junto con Blade y las vistas, es posible pasar directamente los modelos a las plantillas para renderizar los datos de forma eficiente.

Definición y uso de modelos

En Laravel, un modelo es una clase que representa una tabla de la base de datos y proporciona una interfaz para interactuar con los datos de esa tabla. Los modelos sirven como una capa intermedia entre la base de datos y la lógica de la aplicación, permitiendo trabajar con datos de forma orientada a objetos y utilizando las funcionalidades del Eloquent ORM.

Creación de un modelo

Para crear un modelo, se utiliza el comando artisan make:model. Por ejemplo, para crear un modelo llamado Usuario, se ejecuta en la terminal:

php artisan make:model Usuario

Este comando genera un archivo Usuario.php dentro del directorio app/Models. Por convención, los nombres de los modelos están en singular y en mayúscula inicial, mientras que las tablas correspondientes en la base de datos están en plural y en minúsculas.

Estructura básica de un modelo

El modelo generado extiende la clase base Illuminate\Database\Eloquent\Model, heredando todas las funcionalidades del Eloquent ORM:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Usuario extends Model
{
    //
}

Aquí, el espacio de nombres App\Models indica la ubicación del modelo dentro del proyecto.

Configuración de atributos

Los modelos de Eloquent permiten configurar propiedades para adaptarse a las características de la tabla en la base de datos:

  • $table: especifica el nombre de la tabla si difiere del nombre convencional.
protected $table = 'usuarios_custom';
  • $primaryKey: define la clave primaria si es distinta de id.
protected $primaryKey = 'usuario_id';
  • $incrementing: indica si la clave primaria es autoincremental.
public $incrementing = false;
  • $keyType: establece el tipo de dato de la clave primaria.
protected $keyType = 'string';
  • $timestamps: habilita o deshabilita el manejo automático de created_at y updated_at.
public $timestamps = false;

Asignación masiva y seguridad

Para proteger la aplicación de vulnerabilidades como el Mass Assignment, se utilizan las propiedades $fillable y $guarded:

  • $fillable: lista de atributos que pueden ser asignados masivamente.
protected $fillable = ['nombre', 'email', 'password'];
  • $guarded: lista de atributos que no pueden ser asignados masivamente.
protected $guarded = ['is_admin'];

Es recomendable usar $fillable para especificar explícitamente qué campos son seguros para la asignación masiva.

Operaciones básicas con el modelo

Una vez definido el modelo, es posible realizar operaciones CRUD de manera sencilla.

  • Crear un nuevo registro:
$usuario = new Usuario();
$usuario->nombre = 'Juan Pérez';
$usuario->email = 'juan@example.com';
$usuario->password = bcrypt('secreto');
$usuario->save();
  • Asignación masiva al crear:
$datos = [
    'nombre' => 'María López',
    'email' => 'maria@example.com',
    'password' => bcrypt('secreto'),
];

$usuario = Usuario::create($datos);
  • Leer registros:
$usuarios = Usuario::all();

$usuario = Usuario::find(1);

$usuario = Usuario::where('email', 'juan@example.com')->first();
  • Actualizar un registro:
$usuario = Usuario::find(1);
$usuario->nombre = 'Juan P.';
$usuario->save();
  • Actualizar con asignación masiva:
$usuario->update(['nombre' => 'Juan Pérez García']);
  • Eliminar un registro:
$usuario = Usuario::find(1);
$usuario->delete();

Uso de métodos estáticos

Eloquent proporciona métodos estáticos que simplifican las consultas:

  • Obtener todos los registros:
$usuarios = Usuario::all();
  • Búsqueda por clave primaria:
$usuario = Usuario::find($id);
  • Condiciones en consultas:
$usuariosActivos = Usuario::where('activo', true)->get();

Personalización de consultas

Los modelos permiten definir scopes y utilizar métodos para personalizar las consultas:

  • Scope local:
public function scopeActivos($query)
{
    return $query->where('activo', true);
}

// Uso:
$usuarios = Usuario::activos()->get();
  • Ordenamiento y limitación:
$usuarios = Usuario::orderBy('nombre', 'asc')->take(10)->get();

Cast de atributos y formatos

Para convertir automáticamente los atributos a tipos específicos, se utiliza la propiedad $casts:

protected $casts = [
    'email_verified_at' => 'datetime',
    'activo' => 'boolean',
];

Esto asegura que al acceder a email_verified_at, se obtenga una instancia de Carbon para manejar fechas.

Eventos y hooks del modelo

Eloquent dispone de eventos que permiten ejecutar código en momentos específicos del ciclo de vida del modelo:

  • Creando un registro:
protected static function booted()
{
    static::creating(function ($usuario) {
        $usuario->token = Str::random(32);
    });
}

Este ejemplo genera un token aleatorio antes de crear un usuario.

Relación con controladores y vistas

En un controlador, se usa el modelo para interactuar con los datos y pasar información a las vistas:

public function index()
{
    $usuarios = Usuario::all();
    return view('usuarios.index', ['usuarios' => $usuarios]);
}

En una vista Blade, se accede a las propiedades del modelo:

@foreach($usuarios as $usuario)
    <p>{{ $usuario->nombre }} - {{ $usuario->email }}</p>
@endforeach

Prácticas recomendadas

  • Validación: siempre validar los datos antes de guardarlos en el modelo.
  • Eager Loading: usar cargado ansioso para evitar consultas innecesarias.
$usuarios = Usuario::with('perfil')->get();
  • Mantenimiento: mantener los modelos enfocados en la interacción con la base de datos y mover la lógica de negocio a servicios o helpers.

Consultas básicas con Eloquent

Eloquent ORM ofrece una interfaz expresiva y sencilla para realizar consultas en la base de datos. Permite construir consultas de manera fluida, combinando métodos que representan criterios y operaciones comunes en SQL. A continuación, se detallan las operaciones básicas de consulta que se pueden realizar con Eloquent.

Para ilustrar los ejemplos, consideraremos el modelo Usuario previamente definido.

Recuperación de todos los registros

Para obtener todos los registros de una tabla, se utiliza el método estático all() del modelo:

$usuarios = Usuario::all();

El resultado es una colección de instancias del modelo Usuario, que se puede iterar y manipular como un array.

Uso de cláusulas where

Las condiciones se establecen mediante el método where(), que recibe el nombre del campo, el operador y el valor:

$usuariosActivos = Usuario::where('activo', '=', true)->get();

Si el operador es =, se puede omitir, simplificando la expresión:

$usuariosActivos = Usuario::where('activo', true)->get();

Es posible encadenar múltiples cláusulas where() para añadir más condiciones:

$usuariosFiltrados = Usuario::where('activo', true)
    ->where('edad', '>', 18)
    ->get();

Cláusulas orWhere

Para agregar condiciones OR, se utiliza el método orWhere():

$usuarios = Usuario::where('rol', 'admin')
    ->orWhere('rol', 'editor')
    ->get();

Este ejemplo obtiene usuarios cuyo rol sea admin o editor.

Condiciones avanzadas

Eloquent proporciona métodos para condiciones más complejas:

  • whereIn(): selecciona registros donde el valor de un campo está en una lista dada.
$usuarios = Usuario::whereIn('id', [1, 2, 3])->get();
  • whereBetween(): selecciona registros donde el valor de un campo está entre dos valores.
$usuarios = Usuario::whereBetween('edad', [18, 30])->get();
  • whereNull() y whereNotNull(): filtra registros con campos nulos o no nulos.
$usuariosSinTelefono = Usuario::whereNull('telefono')->get();
  • whereDate(), whereMonth(), whereYear(): filtran por componentes de fecha.
$usuariosRecientes = Usuario::whereYear('created_at', date('Y'))->get();

Agrupación de condiciones

Para agrupar condiciones y definir la precedencia lógica, se utiliza una función anónima dentro de where():

$usuarios = Usuario::where('activo', true)
    ->where(function ($query) {
        $query->where('rol', 'admin')
              ->orWhere('rol', 'editor');
    })
    ->get();

De este modo, se obtienen usuarios activos que sean admin o editor.

Selección de columnas específicas

Por defecto, Eloquent recupera todas las columnas. Para seleccionar columnas específicas, se usa el método select():

$nombres = Usuario::select('nombre', 'email')->get();

Esto es útil para mejorar el rendimiento y obtener únicamente los datos necesarios.

Ordenamiento de resultados

Para ordenar los resultados, se utiliza orderBy():

$usuarios = Usuario::orderBy('nombre', 'asc')->get();

También se puede encadenar para múltiples criterios de orden:

$usuarios = Usuario::orderBy('apellido', 'asc')
    ->orderBy('nombre', 'asc')
    ->get();

Limitación y desplazamiento

Para limitar la cantidad de registros y establecer un desplazamiento, se usan take() y skip(), o sus alias limit() y offset():

$usuarios = Usuario::skip(10)->take(5)->get();

Este ejemplo obtiene 5 usuarios, saltando los primeros 10.

Paginación

Eloquent facilita la paginación mediante el método paginate():

$usuarios = Usuario::orderBy('id', 'desc')->paginate(15);

Esto devuelve una colección de 15 usuarios por página, incluyendo información para crear links de paginación.

Uso de agregaciones

Para realizar operaciones de agregación, existen métodos como count(), max(), min(), avg() y sum():

  • Contar registros:
$totalUsuarios = Usuario::count();
  • Máximo valor de un campo:
$edadMaxima = Usuario::max('edad');
  • Promedio de un campo:
$edadPromedio = Usuario::avg('edad');

Consultas crudas

Aunque Eloquent cubre la mayoría de necesidades, en ocasiones es necesario realizar consultas SQL crudas con DB::raw():

use Illuminate\Support\Facades\DB;

$usuarios = Usuario::select(DB::raw('COUNT(*) as total'), 'rol')
    ->groupBy('rol')
    ->get();

En este ejemplo, se cuentan usuarios agrupados por rol.

Conversión a array y JSON

Los resultados de las consultas pueden convertirse fácilmente a array o JSON:

  • Convertir a array:
$usuariosArray = Usuario::all()->toArray();
  • Convertir a JSON:
$usuariosJson = Usuario::all()->toJson();

Esto es útil para enviar datos a la vista o a través de una API.

Uso de modelos en las vistas

Al pasar los datos a las vistas, se pueden utilizar directamente en las plantillas Blade:

return view('usuarios.lista', ['usuarios' => $usuarios]);

En la vista, se recorre la colección:

@foreach($usuarios as $usuario)
    <p>{{ $usuario->nombre }} - {{ $usuario->email }}</p>
@endforeach

Métodos adicionales de consulta

Eloquent incluye una variedad de métodos que permiten construir consultas de manera flexible:

  • first(): obtiene el primer registro que coincide con la consulta.
$usuario = Usuario::where('email', 'juan@example.com')->first();
  • findOrFail(): busca por clave primaria y lanza una excepción si no encuentra el registro.
$usuario = Usuario::findOrFail($id);
  • firstOrCreate(): obtiene el primer registro que coincide o lo crea si no existe.
$usuario = Usuario::firstOrCreate(
    ['email' => 'juan@example.com'],
    ['nombre' => 'Juan Pérez', 'password' => bcrypt('secreto')]
);
  • updateOrCreate(): actualiza un registro existente o lo crea con los datos proporcionados.
$usuario = Usuario::updateOrCreate(
    ['email' => 'juan@example.com'],
    ['nombre' => 'Juan P.', 'activo' => true]
);

Comparaciones avanzadas

Para operadores más allá del =, se pueden utilizar otros dentro de where():

$usuarios = Usuario::where('edad', '>=', 18)->get();

También es posible utilizar whereColumn() para comparar dos columnas:

$usuarios = Usuario::whereColumn('created_at', '>', 'updated_at')->get();

Uso de scopes

Los scopes locales permiten encapsular condiciones reutilizables en el modelo:

public function scopeAdultos($query)
{
    return $query->where('edad', '>=', 18);
}

// Uso:
$usuariosAdultos = Usuario::adultos()->get();

Esto mejora la claridad y la reutilización del código.

Ejemplos prácticos

  • Obtener usuarios cuyo nombre comience con una letra específica:
$usuarios = Usuario::where('nombre', 'like', 'A%')->get();
  • Obtener los 5 usuarios más recientes:
$usuariosRecientes = Usuario::orderBy('created_at', 'desc')
->take(5)
->get();
  • Contar usuarios por rol:
$conteoRoles = Usuario::select('rol', DB::raw('COUNT(*) as total'))
->groupBy('rol')
->get();

Consideraciones sobre rendimiento

  • Eager Loading: para evitar el problema conocido como n+1 consultas, se utilizan las relaciones con with():
$usuarios = Usuario::with('perfil')->get();
  • Chunking: para procesar grandes cantidades de registros sin cargar todo en memoria:
Usuario::chunk(100, function ($usuarios) {
    foreach ($usuarios as $usuario) {
        // Procesar cada usuario
    }
});

Depuración de consultas

Para visualizar la consulta SQL generada, se puede utilizar el método toSql():

$sql = Usuario::where('activo', true)->toSql();
// Muestra: "select * from `usuarios` where `activo` = ?"

Esto es útil para depurar y entender cómo Eloquent construye las consultas.

Para seguir leyendo hazte Plus

¿Ya eres Plus? Accede a la app

Plan mensual

19.00 € /mes

Precio normal mensual: 19 €
47 % DE DESCUENTO

Plan anual

10.00 € /mes

Ahorras 108 € al año
Precio normal anual: 120 €
Aprende Laravel GRATIS online

Todas las lecciones de Laravel

Accede a todas las lecciones de Laravel y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Accede GRATIS a Laravel y certifícate

En esta lección

Objetivos de aprendizaje de esta lección

  1. Comprender la importancia de una adecuada configuración de la base de datos en Laravel.
  2. Establecer conexiones seguras usando el archivo .env.
  3. Gestionar conexiones múltiples y diferentes tipos de bases de datos (MySQL, PostgreSQL, SQLite).
  4. Realizar pruebas y migraciones de bases de datos de manera efectiva.
  5. Utilizar variables de entorno para adaptar configuraciones según el entorno.
  6. Proteger credenciales y datos sensibles en archivos de configuración.