En los posts anteriores aprendiste a crear rutas, vistas y controllers. Ahora es momento de trabajar con la base de datos usando el poderoso Eloquent ORM.
¿Qué es Eloquent ORM?
ORM significa Object-Relational Mapping (Mapeo Objeto-Relacional). Eloquent es el ORM de Laravel que te permite trabajar con la base de datos usando objetos PHP en lugar de escribir SQL directamente.
Beneficios de usar Eloquent:
- Sintaxis elegante:
Post::all()en lugar deSELECT * FROM posts - Type-safe: Tu IDE puede autocompletar propiedades
- Relationships: Define relaciones entre tablas fácilmente
- Protección: Previene SQL injection automáticamente
- Migrations: Versiona cambios en tu base de datos
El patrón Active Record
Eloquent usa el patrón Active Record, donde cada model representa una tabla y cada instancia del model representa una fila:
// Una instancia = una fila en la tabla
$post = new Post();
$post->title = 'Mi primer post';
$post->save(); // INSERT INTO posts...
Creando tu Primer Model
Usa el comando Artisan make:model. El flag -m crea automáticamente una migration:
php artisan make:model Post -m
Esto crea dos archivos:
- Model:
app/Models/Post.php - Migration:
database/migrations/xxxx_create_posts_table.php
Convenciones de naming:
- Model name:
Post(singular, PascalCase) - Tabla asociada:
posts(plural, snake_case) - Primary key:
id(autoincremento por defecto) - Timestamps:
created_atyupdated_at(automáticos)
Convención sobre configuración: Si sigues las convenciones de Laravel, no necesitas configurar casi nada. El model Post automáticamente usa la tabla posts.
Migrations: Construyendo tu Schema
Las migrations son como “control de versiones” para tu base de datos. Cada migration define cómo crear o modificar tablas.
Abre la migration generada (database/migrations/xxxx_create_posts_table.php):
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->boolean('published')->default(false);
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('posts');
}
};
Column types comunes:
id()- Primary key autoincremento (BIGINT UNSIGNED)string('name', 100)- VARCHAR(100)text('content')- TEXTinteger('views')- INTEGERboolean('published')- BOOLEANtimestamp('published_at')->nullable()- TIMESTAMP NULLtimestamps()- Crea created_at y updated_atforeignId('user_id')->constrained()- Foreign key a tabla users
Ejecutando Migrations
Para crear las tablas en tu base de datos:
php artisan migrate
Verás algo como:
INFO Running migrations.
2025_02_14_000001_create_posts_table ............ 10ms DONE
Otros comandos útiles:
php artisan migrate:rollback # Deshace el último batch
php artisan migrate:fresh # Borra todas las tablas y re-crea
php artisan migrate:refresh # Rollback + migrate
Nunca modifiques migrations ya ejecutadas en producción. Siempre crea una nueva migration para cambios.
CRUD con Eloquent
Ahora que tienes tu tabla, puedes interactuar con ella usando el model.
Create - Crear registros:
// Opción 1: Create + Save
$post = new Post();
$post->title = 'Mi Primer Post';
$post->content = 'Contenido del post...';
$post->save();
// Opción 2: Create (mass assignment)
$post = Post::create([
'title' => 'Mi Primer Post',
'content' => 'Contenido del post...',
]);
// Opción 3: firstOrCreate (busca o crea)
$post = Post::firstOrCreate(
['title' => 'Mi Primer Post'],
['content' => 'Contenido...']
);
Read - Leer registros:
// Todos los posts
$posts = Post::all();
// Buscar por ID
$post = Post::find(1);
// Buscar por ID o lanzar 404
$post = Post::findOrFail(1);
// Primera coincidencia
$post = Post::where('published', true)->first();
// Múltiples condiciones
$posts = Post::where('published', true)
->where('views', '>', 100)
->get();
// Ordenar
$posts = Post::orderBy('created_at', 'desc')->get();
// Limitar resultados
$posts = Post::take(10)->get();
// Paginación
$posts = Post::paginate(15);
Update - Actualizar registros:
// Opción 1: Find + Update
$post = Post::find(1);
$post->title = 'Título Actualizado';
$post->save();
// Opción 2: Update directo
$post = Post::find(1);
$post->update([
'title' => 'Título Actualizado',
'published' => true,
]);
// Opción 3: Update masivo (sin instanciar)
Post::where('published', false)
->update(['published' => true]);
Delete - Eliminar registros:
// Opción 1: Find + Delete
$post = Post::find(1);
$post->delete();
// Opción 2: Delete directo por ID
Post::destroy(1);
// Opción 3: Delete múltiples
Post::destroy([1, 2, 3]);
// Opción 4: Delete condicional
Post::where('views', '<', 10)->delete();
Mass Assignment Protection
Por seguridad, Laravel protege contra mass assignment (asignación masiva). Debes especificar qué campos son “llenables”:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $fillable = [
'title',
'content',
'published',
];
}
O especificar qué campos NO son llenables:
protected $guarded = ['id', 'user_id'];
¿Por qué mass assignment protection? Imagina un usuario malicioso enviando
is_admin=1en un formulario. Sin protección, podría hacerse admin!
Relationships: Conectando Models
Una de las features más poderosas de Eloquent son las relaciones.
Ejemplo: Un User tiene muchos Posts (One-to-Many)
1. Agrega foreign key en la migration:
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->string('title');
$table->text('content');
$table->timestamps();
});
2. Define la relación en el Model User:
class User extends Model
{
public function posts()
{
return $this->hasMany(Post::class);
}
}
3. Define la relación inversa en Post:
class Post extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
}
4. Usa las relaciones:
// Obtener posts de un usuario
$user = User::find(1);
$posts = $user->posts; // Collection de Posts
// Obtener el autor de un post
$post = Post::find(1);
$author = $post->user; // User model
El Problema N+1 y Eager Loading
Sin eager loading, Eloquent ejecuta 1 query por cada relación:
// ❌ N+1 Problem - 1 query + N queries
$posts = Post::all(); // 1 query
foreach ($posts as $post) {
echo $post->user->name; // 1 query por post!
}
// Total: 1 + 10 = 11 queries para 10 posts
Solución: usa with() para eager loading:
// ✅ Eager Loading - Solo 2 queries
$posts = Post::with('user')->get(); // 2 queries total
foreach ($posts as $post) {
echo $post->user->name; // Sin queries adicionales
}
El problema N+1 es una de las causas principales de lentitud en aplicaciones Laravel. Siempre usa eager loading cuando accedas a relaciones en loops.
UUIDv7 en Laravel 12
Novedad en Laravel 12: Ahora puedes usar UUIDs versión 7 como primary keys. Los UUIDv7 son time-ordered (ordenados por tiempo), lo que mejora el performance en bases de datos.
use Illuminate\Database\Eloquent\Concerns\HasUuids;
class Post extends Model
{
use HasUuids; // Usa UUIDv7 automáticamente
// No necesitas definir $keyType, Laravel lo detecta
}
Y en tu migration:
Schema::create('posts', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->string('title');
// ...
});
Casting: Transformación Automática
Eloquent puede convertir automáticamente tipos de datos:
class Post extends Model
{
protected $casts = [
'published_at' => 'datetime', // String → Carbon instance
'settings' => 'array', // JSON → PHP array
'published' => 'boolean', // 0/1 → true/false
'views' => 'integer',
];
}
Ahora puedes usar:
$post->published_at->format('Y-m-d'); // Carbon methods
$post->settings['theme']; // Array access
Accessors & Mutators (Breve)
Accessors transforman datos al leerlos:
// Accessor: convierte title a uppercase
public function getTitleAttribute($value)
{
return strtoupper($value);
}
echo $post->title; // "MI PRIMER POST"
Mutators transforman datos al escribirlos:
// Mutator: limpia el title antes de guardar
public function setTitleAttribute($value)
{
$this->attributes['title'] = trim(strip_tags($value));
}
$post->title = '<h1> Mi Post </h1>'; // Guarda "Mi Post"
Siguiente Paso
Ahora que dominas Models, Migrations y Eloquent, es momento de poner todo en práctica. En el próximo post crearemos un Blog completo desde cero, usando todo lo aprendido: rutas, controllers, vistas, models y relaciones.
Recursos Adicionales
Video de la lección
Acá te dejo la playlist en youtube donde iré agregando los videos de la serie: Aprende Laravel @ YouTube
