⛩️ El Corazón de Laravel

Eloquent es el ORM de Laravel que transforma la interacción con bases de datos en poesía. Cada tabla es un modelo, cada relación es una conexión viva.


🎯 Definición Teórica: El Por Qué de Eloquent

Filosofía

Tabla Users   →   Modelo User
---------------------------------
id           →   $user->id
name         →   $user->name
email        →   $user->email
created_at   →   $user->created_at

El Problema que Resuelve

Sin EloquentCon Eloquent
50+ líneas de SQL1 línea de código
Consultas insegurasInyección SQL imposible
Arrays asociativosObjetos tipados
Relaciones manualesMétodos mágicos

🗡️ Guía de Implementación

1. Modelo Básico

<?php
// app/Models/User.php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    // Tabla (opcional si sigue convención)
    protected $table = 'users';
    
    // Primary key
    protected $primaryKey = 'id';
    
    // Timestamps automáticos
    public $timestamps = true;
    
    // Columns que pueden ser asignadas masivamente
    protected $fillable = [
        'name',
        'email', 
        'password',
        'role'
    ];
    
    // Columns que no pueden ser asignadas masivamente
    protected $hidden = [
        'password',
        'remember_token'
    ];
    
    // Casts automáticos
    protected $casts = [
        'email_verified_at' => 'datetime',
        'is_admin' => 'boolean',
        'settings' => 'array'
    ];
}

2. Relaciones (El Poder de Eloquent)

// ╔═══════════════════════════════════════════════════════════════╗
// ║                    TIPOS DE RELACIONES                          ║
// ╠══════════════════════════════╦═════════════════════════════════╣
// ║ One to One (hasOne)          ║  Usuario → Perfil               ║
// ║ One to Many (hasMany)        ║  Usuario → Publicaciones        ║
// ║ Many to Many (belongsToMany) ║  Usuario ←→ Roles               ║
// ║ Has One Through              ║  Usuario → Teléfono (país)      ║
// ║ Has Many Through             ║  País → Ciudades → Usuarios    ║
// ╚══════════════════════════════╩═══════════════════════════════════╝

One to One

// Modelo User
public function perfil() {
    return $this->hasOne(Perfil::class);
}

// Modelo Perfil  
public function usuario() {
    return $this->belongsTo(User::class);
}

// Uso
$usuario = User::find(1);
$perfil = $usuario->perfil;

One to Many

// Modelo User
public function publicaciones() {
    return $this->hasMany(Publicacion::class);
}

// Modelo Publicacion
public function autor() {
    return $this->belongsTo(User::class, 'user_id');
}

// Uso
$publicaciones = User::find(1)->publicaciones;

Many to Many

// Modelos: User y Rol
// Tabla pivote: role_user (o alphabetico: rol_user)

// Modelo User
public function roles() {
    return $this->belongsToMany(Rol::class);
}

// Modelo Rol
public function usuarios() {
    return $this->belongsToMany(User::class);
}

// Uso
$user = User::find(1);
$user->roles()->attach(1);           // Agregar rol
$user->roles()->detach(1);           // Quitar rol
$user->roles()->sync([1, 2, 3]);     // Sincronizar roles

// Con timestamps
$user->roles()->attach(1, ['expira_en' => now()->addYear()]);

3. Consultas Avanzadas

// ╔═══════════════════════════════════════════════════════════════╗
// ║                    MÉTODOS DE CONSULTA                          ║
// ╠═══════════════════════════════════════════════════════════════╣
// ║ all()              ║  Obtener todos                            ║
// ║ find($id)          ║  Buscar por ID                            ║
// ║ findOrFail($id)    ║  Buscar o lanzar 404                     ║
// ║ first()            ║  Primer resultado                         ║
// ║ firstOrFail()      ║  Primero o 404                            ║
// ║ get()              ║  Colección                                ║
// ║ pluck('columna')   ║  Solo una columna                         ║
// ║ count()            ║  Contar resultados                        ║
// ║ exists()           ║  Verificar existencia                     ║
// ╚═══════════════════════════════════════════════════════════════╝

// Where avanzado
$usuarios = User::where('email', 'like', '%@gmail.com')
    ->whereBetween('created_at', ['2024-01-01', '2024-12-31'])
    ->orWhere('role', 'admin')
    ->orderBy('name')
    ->limit(10)
    ->get();

// Chunk para grandes cantidades
User::chunk(100, function ($usuarios) {
    foreach ($usuarios as $usuario) {
        // Procesar 100 usuarios a la vez
    }
});

4. Scopes (Alcances)

// En el modelo User
class User extends Model
{
    // Scope local (requiere 'scope' prefix)
    public function scopeActivos($query) {
        return $query->where('activo', true);
    }
    
    public function scopeAdmin($query) {
        return $query->where('role', 'admin');
    }
    
    public function scopeCreadoEntre($query, $inicio, $fin) {
        return $query->whereBetween('created_at', [$inicio, $fin]);
    }
    
    // Scope con parámetros
    public function scopeRol($query, $rol) {
        return $query->where('role', $rol);
    }
}

// Uso
$admins = User::activos()->admin()->get();
$usuarios = User::rol('editor')->creadoEntre('2024-01-01', '2024-06-30')->get();

5. Accessors y Mutators

class User extends Model
{
    // ACCESSOR: Transformar al LEER
    public function getNombreCompletoAttribute() {
        return ucfirst($this->name) . ' ' . ucfirst($this->apellido);
    }
    
    // MUTATOR: Transformar al ESCRIBIR
    public function setEmailAttribute($value) {
        $this->attributes['email'] = strtolower($value);
    }
    
    public function setPasswordAttribute($value) {
        $this->attributes['password'] = bcrypt($value);
    }
}

// Uso
$user = User::find(1);
echo $user->nombreCompleto; // "Juan Pérez"

$user->email = 'JUAN@EJEMPLO.COM';
$user->save();
// Se guarda como 'juan@ejemplo.com'

🥷 Reto Ninja

Nivel: Jonin

Misión 1: Crea un Blog Completo

// Modelos y relaciones para un blog

// Post.php
class Post extends Model
{
    protected $fillable = ['title', 'content', 'user_id', 'category_id', 'published'];
    
    public function autor() {
        return $this->belongsTo(User::class);
    }
    
    public function categoria() {
        return $this->belongsTo(Category::class);
    }
    
    public function comentarios() {
        return $this->hasMany(Comentario::class);
    }
    
    public function etiquetas() {
        return $this->belongsToMany(Etiqueta::class);
    }
    
    // Scope para posts publicados
    public function scopePublicado($query) {
        return $query->where('published', true)
                     ->where('published_at', '<=', now());
    }
}

Misión 2: Eager Loading Completo

// Obtener posts con todas sus relaciones
$posts = Post::publicado()
    ->with(['autor', 'categoria', 'comentarios.usuario', 'etiquetas'])
    ->withCount('comentarios')
    ->orderBy('published_at', 'desc')
    ->get();

// Con relaciones anidadas
// Post → Comentario → Usuario (autor del comentario)

Misión 3: Colecciones

$usuarios = User::all();

// Métodos de colección
$emails = $usuarios->pluck('email');
$nombres = $usuarios->pluck('name', 'id'); // [1 => 'Juan', 2 => 'María]

$primero = $usuarios->first();
$ultimo = $usuarios->last();

$admins = $usuarios->filter(function ($user) {
    return $user->role === 'admin';
});

$sinEmail = $usuarios->reject(function ($user) {
    return $user->email;
});

📜 Métodos Mágicos

// Crear con relaciones
$post = Post::create([
    'title' => 'Nuevo Post',
    'content' => 'Contenido...',
    'user_id' => 1
]);

// Relacionar automáticamente
$post->autor()->associate(User::find(1));
$post->save();

// Attach/Detach en many-to-many
$post->etiquetas()->attach([1, 2, 3]);
$post->etiquetas()->detach(1);
$post->etiquetas()->sync([2, 3, 4]);

🎓 Conclusión del Maestro

“Eloquent no es solo una herramienta, es una forma de pensar. Representa tus datos como objetos vivos, y las relaciones fluyen como el chakra.” — Maestro de Laravel


✅ Checklist de Dominio

  • Crear modelo con todas las relaciones
  • Implementar CRUD completo
  • Dominar scopes locales
  • Usar accessors y mutators
  • Implementar eager loading
  • Manejar relaciones many-to-many

Recompensa XP: 100 XP ⚔️