Lección 19 de 45 18 min de lectura

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
<?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
<?php

use App\Models\Post;

$post = Post::create([
    'title' => 'Segundo artículo',
    'slug' => 'segundo-articulo',
    'content' => 'Más contenido...',
]);

echo $post->id; // 2
Recuerda $fillable

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
<?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
<?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
<?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
<?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
<?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
<?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
<?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
<?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
<?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
<?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
<?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
<?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
<?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
<?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
<?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
<?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
<?php

// En la migración
$table->softDeletes(); // Añade columna deleted_at

Con soft deletes activado:

php
<?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();
Cuándo usar Soft Deletes

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
<?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() o create(). firstOrCreate() busca antes de crear
  • Leer: all(), find(), where()->get(), first()
  • Actualizar: save() después de modificar, o update() con array
  • Eliminar: delete() en el modelo o destroy() por ID
  • findOrFail() y firstOrFail() 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() y decrement() para contadores

¿Te está gustando el curso?

Tenemos cursos premium con proyectos reales, soporte personalizado y certificado.

Descubrir cursos premium