CRUD con Eloquent
CRUD son las cuatro operaciones básicas que realizamos con datos: Crear (Create), Leer (Read), Actualizar (Update) y Eliminar (Delete). Eloquent proporciona métodos intuitivos para cada una de estas operaciones.
Crear registros (Create)
Hay varias formas de crear nuevos registros en la base de datos con Eloquent.
Usando save()
Crea una instancia del modelo, asigna valores y
llama a save():
<?php
use App\Models\Post;
$post = new Post();
$post->title = 'Mi primer artículo';
$post->slug = 'mi-primer-articulo';
$post->content = 'Contenido del artículo...';
$post->save();
// $post ahora tiene un id asignado
echo $post->id; // 1
Usando create()
Crea y guarda en una sola línea pasando un array de datos:
<?php
use App\Models\Post;
$post = Post::create([
'title' => 'Segundo artículo',
'slug' => 'segundo-articulo',
'content' => 'Más contenido...',
]);
echo $post->id; // 2
Para usar create(), los
campos deben estar definidos en
$fillable del modelo. Vimos
esto en la lección anterior.
firstOrCreate y firstOrNew
Estos métodos buscan un registro y lo crean si no existe:
<?php
use App\Models\Category;
// Busca por slug, si no existe lo crea con name
$category = Category::firstOrCreate(
['slug' => 'tecnologia'], // Criterio de búsqueda
['name' => 'Tecnología'] // Datos adicionales si se crea
);
// firstOrNew: igual pero NO guarda automáticamente
$category = Category::firstOrNew(
['slug' => 'deportes'],
['name' => 'Deportes']
);
$category->save(); // Hay que guardar manualmente
Leer registros (Read)
Eloquent ofrece muchos métodos para consultar datos.
Obtener todos los registros
<?php
use App\Models\Post;
// Obtener todos los posts
$posts = Post::all();
// Iterar sobre los resultados
foreach ($posts as $post) {
echo $post->title;
}
Buscar por ID
<?php
use App\Models\Post;
// find() devuelve null si no existe
$post = Post::find(1);
if ($post) {
echo $post->title;
}
// findOrFail() lanza excepción 404 si no existe
$post = Post::findOrFail(1);
// Buscar múltiples IDs
$posts = Post::find([1, 2, 3]);
Condiciones con where()
<?php
use App\Models\Post;
// Condición simple (= implícito)
$posts = Post::where('is_published', true)->get();
// Con operador explícito
$posts = Post::where('views', '>', 100)->get();
// Múltiples condiciones
$posts = Post::where('is_published', true)
->where('views', '>', 50)
->get();
// O con orWhere
$posts = Post::where('is_published', true)
->orWhere('is_featured', true)
->get();
Obtener un solo registro
<?php
use App\Models\Post;
// first() devuelve el primer resultado o null
$post = Post::where('slug', 'mi-primer-articulo')->first();
// firstOrFail() lanza 404 si no encuentra
$post = Post::where('slug', 'mi-primer-articulo')->firstOrFail();
Ordenar y limitar
<?php
use App\Models\Post;
// Ordenar por fecha descendente
$posts = Post::orderBy('created_at', 'desc')->get();
// Atajos para ordenar
$latest = Post::latest()->get(); // Más recientes primero
$oldest = Post::oldest()->get(); // Más antiguos primero
// Limitar resultados
$posts = Post::latest()->take(5)->get();
// Saltar registros (para paginación manual)
$posts = Post::latest()->skip(10)->take(5)->get();
Seleccionar columnas específicas
<?php
use App\Models\Post;
// Solo traer ciertas columnas
$posts = Post::select('id', 'title', 'slug')->get();
// También con get()
$posts = Post::get(['id', 'title', 'slug']);
Contar y verificar existencia
<?php
use App\Models\Post;
// Contar registros
$total = Post::count();
$published = Post::where('is_published', true)->count();
// Verificar si existen
$hasPublished = Post::where('is_published', true)->exists();
// Verificar si NO existen
$noPosts = Post::where('is_published', true)->doesntExist();
Actualizar registros (Update)
Existen varias formas de actualizar registros existentes.
Actualizar un modelo
<?php
use App\Models\Post;
// Buscar, modificar y guardar
$post = Post::find(1);
$post->title = 'Título actualizado';
$post->is_published = true;
$post->save();
Usando update()
Actualiza con un array de datos en una sola línea:
<?php
use App\Models\Post;
$post = Post::find(1);
$post->update([
'title' => 'Nuevo título',
'content' => 'Nuevo contenido',
]);
Actualización masiva
Actualiza múltiples registros que coincidan con una condición:
<?php
use App\Models\Post;
// Publicar todos los borradores
Post::where('is_published', false)
->update(['is_published' => true]);
// Devuelve el número de filas afectadas
updateOrCreate
Actualiza un registro si existe, o lo crea si no existe:
<?php
use App\Models\Setting;
// Si existe setting con key='site_name', lo actualiza
// Si no existe, lo crea con ambos valores
$setting = Setting::updateOrCreate(
['key' => 'site_name'], // Criterio de búsqueda
['value' => 'Mi Blog'] // Valores a actualizar/crear
);
Incrementar y decrementar
<?php
use App\Models\Post;
$post = Post::find(1);
// Incrementar vistas en 1
$post->increment('views');
// Incrementar en cantidad específica
$post->increment('views', 5);
// Decrementar stock
$post->decrement('stock');
$post->decrement('stock', 3);
Eliminar registros (Delete)
Eliminar un modelo
<?php
use App\Models\Post;
// Buscar y eliminar
$post = Post::find(1);
$post->delete();
// Eliminar por ID directamente
Post::destroy(1);
// Eliminar múltiples por ID
Post::destroy([1, 2, 3]);
Eliminación masiva
<?php
use App\Models\Post;
// Eliminar posts antiguos no publicados
Post::where('is_published', false)
->where('created_at', '<', now()->subYear())
->delete();
Soft Deletes (eliminación suave)
En lugar de eliminar permanentemente, puedes
"marcar como eliminado" añadiendo el trait
SoftDeletes:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Post extends Model
{
use SoftDeletes;
protected $fillable = [
'title',
'slug',
'content',
'is_published',
];
}
La migración necesita la columna
deleted_at:
<?php
// En la migración
$table->softDeletes(); // Añade columna deleted_at
Con soft deletes activado:
<?php
use App\Models\Post;
// delete() marca deleted_at con la fecha actual
$post = Post::find(1);
$post->delete();
// Las consultas normales excluyen los eliminados
$posts = Post::all(); // No incluye eliminados
// Incluir eliminados en la consulta
$allPosts = Post::withTrashed()->get();
// Solo los eliminados
$trashedPosts = Post::onlyTrashed()->get();
// Restaurar un registro eliminado
$post = Post::withTrashed()->find(1);
$post->restore();
// Eliminar permanentemente
$post->forceDelete();
Usa soft deletes cuando necesites mantener histórico o permitir recuperar datos eliminados. Para datos temporales o sin importancia, la eliminación normal es suficiente.
Ejemplo práctico: Controlador CRUD
Veamos cómo se integran estas operaciones en un controlador típico:
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\Request;
use Illuminate\View\View;
use Illuminate\Http\RedirectResponse;
class PostController extends Controller
{
// Listar todos (Read)
public function index(): View
{
$posts = Post::latest()->get();
return view('posts.index', compact('posts'));
}
// Mostrar uno (Read)
public function show(int $id): View
{
$post = Post::findOrFail($id);
return view('posts.show', compact('post'));
}
// Guardar nuevo (Create)
public function store(Request $request): RedirectResponse
{
$post = Post::create([
'title' => $request->input('title'),
'slug' => $request->input('slug'),
'content' => $request->input('content'),
]);
return redirect()->route('posts.show', $post);
}
// Actualizar (Update)
public function update(Request $request, int $id): RedirectResponse
{
$post = Post::findOrFail($id);
$post->update([
'title' => $request->input('title'),
'content' => $request->input('content'),
]);
return redirect()->route('posts.show', $post);
}
// Eliminar (Delete)
public function destroy(int $id): RedirectResponse
{
$post = Post::findOrFail($id);
$post->delete();
return redirect()->route('posts.index');
}
}
Ejercicios
Ejercicio 1: Consultas básicas
Escribe el código Eloquent para: obtener los 10 productos más caros que estén activos, ordenados por precio descendente. Solo necesitas las columnas id, name y price.
Ver solución
<?php
use App\Models\Product;
$products = Product::select('id', 'name', 'price')
->where('is_active', true)
->orderBy('price', 'desc')
->take(10)
->get();
Ejercicio 2: CRUD de categorías
Crea un método que reciba un slug y un nombre. Si existe una categoría con ese slug, actualiza su nombre. Si no existe, créala. Devuelve la categoría.
Ver solución
<?php
use App\Models\Category;
function saveCategory(string $slug, string $name): Category
{
return Category::updateOrCreate(
['slug' => $slug],
['name' => $name]
);
}
// Uso
$category = saveCategory('tecnologia', 'Tecnología');
$category = saveCategory('tecnologia', 'Tech'); // Actualiza el nombre
Ejercicio 3: Soft delete y restauración
Tienes un modelo Article con soft
deletes. Escribe: (1) el código para eliminar
todos los artículos no publicados, (2) el código
para listar solo los artículos eliminados, y (3)
el código para restaurar un artículo por su ID.
Ver solución
<?php
use App\Models\Article;
// 1. Eliminar artículos no publicados (soft delete)
Article::where('is_published', false)->delete();
// 2. Listar solo los eliminados
$trashedArticles = Article::onlyTrashed()->get();
// 3. Restaurar un artículo por ID
$article = Article::withTrashed()->findOrFail($id);
$article->restore();
Resumen
-
Crear: usa
save()ocreate().firstOrCreate()busca antes de crear -
Leer:
all(),find(),where()->get(),first() -
Actualizar:
save()después de modificar, oupdate()con array -
Eliminar:
delete()en el modelo odestroy()por ID -
findOrFail()yfirstOrFail()lanzan error 404 si no encuentran -
updateOrCreate()actualiza o crea según exista -
Soft deletes permite eliminar sin borrar
realmente (columna
deleted_at) -
Usa
increment()ydecrement()para contadores
¿Has encontrado un error o tienes una sugerencia para mejorar esta lección?
Escríbenos¿Te está gustando el curso?
Tenemos cursos premium con proyectos reales, soporte personalizado y certificado.
Descubrir cursos premium