Manejo de relaciones en bases de datos con Laravel

Clase 8 de 33Curso Avanzado de Laravel

Contenido del curso

Laravel y Base de Datos

    Resumen

    Domina las relaciones de Eloquent en Laravel con una guía clara y práctica. Aquí verás cómo modelar productos, categorías y usuarios, crear migraciones con claves foráneas, ajustar factories y validar el flujo con tests. Todo con un enfoque directo y listo para aplicar.

    ¿Cómo conectar productos, categorías y usuarios con Eloquent?

    Para mapear la lógica del dominio, Eloquent permite declarar relaciones expresivas. Un producto pertenece a una categoría y una categoría tiene muchos productos. Además, un producto tiene un único usuario creador mediante el campo created_by.

    ¿Cómo declarar belongsTo y hasMany en los modelos?

    • En Product: relación con Category usando belongsTo.
    • En Category: relación inversa con hasMany.
    • En Product y User: relación created_by con belongsTo y hasMany.
    // app/Models/Product.php class Product extends Model { public function category() { return $this->belongsTo(Category::class, 'category_id'); } public function createdBy() { return $this->belongsTo(User::class, 'created_by'); } } // app/Models/Category.php class Category extends Model { public function products() { return $this->hasMany(Product::class, 'category_id'); } } // app/Models/User.php class User extends Model { public function products() { return $this->hasMany(Product::class, 'created_by'); } }

    ¿Qué conceptos clave debes interiorizar?

    • Eloquent: ORM de Laravel para mapear tablas a modelos.
    • belongsTo / hasMany: relaciones 1:N expresivas y legibles.
    • created_by: campo que enlaza producto con su creador.
    • Integridad referencial: la foreign key en base de datos refuerza la relación.

    ¿Qué migraciones y claves foráneas necesitas en Laravel?

    Primero, agrega category_id a products con un valor por defecto. Se crea una categoría “otros” y se usa su ID como default. Luego, define la foreign key y aplica un rollback para regenerarla correctamente.

    ¿Cómo crear la migración para category_id?

    php artisan make:migration add_category_id_to_products_table
    // database/migrations/xxxx_xx_xx_add_category_id_to_products_table.php return new class extends Migration { public function up(): void { // Crear categoría por defecto $defaultId = DB::table('categories')->insertGetId([ 'name' => 'otros', 'created_at' => now(), 'updated_at' => now(), ]); Schema::table('products', function (Blueprint $table) use ($defaultId) { $table->unsignedBigInteger('category_id')->default($defaultId); // Clave foránea recomendada para integridad de datos $table->foreign('category_id')->references('id')->on('categories'); }); } public function down(): void { Schema::table('products', function (Blueprint $table) { $table->dropColumn('category_id'); }); } };

    Aplicación de migraciones y rollback para regenerar la foreign key:

    php artisan migrate:rollback php artisan migrate

    ¿Cómo añadir created_by y vincular usuarios?

    Se agrega la columna created_by a products con un usuario “administrador” por defecto, creado con el factory de User.

    php artisan make:migration add_created_by_to_products_table
    // database/migrations/xxxx_xx_xx_add_created_by_to_products_table.php return new class extends Migration { public function up(): void { // Crear usuario por defecto: administrador $adminId = User::factory()->create(['name' => 'administrador'])->id; Schema::table('products', function (Blueprint $table) use ($adminId) { $table->unsignedBigInteger('created_by')->default($adminId); }); } public function down(): void { Schema::table('products', function (Blueprint $table) { $table->dropColumn('created_by'); }); } };

    ¿Cómo probar y sembrar datos con factories y seeders?

    El testing valida las relaciones y evita errores comunes, como olvidar el return en un método de relación. Las factories generan datos realistas; los seeders controlan el orden en que se crean.

    ¿Cómo ajustar tests para belongsTo category?

    • Crear Category y Product con category_id asignado.
    • Afirmar que $product->category no sea nulo y coincida el ID.
    // tests/Feature/ProductTest.php public function test_product_belongs_to_category(): void { $category = Category::factory()->create(); $product = Product::factory()->create([ 'category_id' => $category->id, ]); $this->assertNotNull($product->category); $this->assertEquals($category->id, $product->category->id); }

    ¿Cómo configurar factories para relaciones al azar?

    • En ProductFactory, elegir categoría y usuario al azar desde la base.
    • Evitar faker para estos campos relacionales.
    // database/factories/ProductFactory.php public function definition(): array { return [ 'name' => $this->faker->word(), 'category_id' => fn() => Category::inRandomOrder()->first()->id, 'created_by' => fn() => User::inRandomOrder()->first()->id, ]; }

    ¿Cómo ordenar los seeders para que todo funcione?

    • Crear usuarios antes que productos para resolver created_by.
    // database/seeders/DatabaseSeeder.php public function run(): void { User::factory(10)->create(); Category::factory(5)->create(); Product::factory(20)->create(); }

    ¿Te gustaría ver más ejemplos de relaciones en Eloquent o resolver un caso específico de tu proyecto? Comparte tus dudas y cuéntame qué modelo quieres conectar a continuación.