简体   繁体   中英

Laravel Eloquent 3 tables + 1 pivot table

I'm designing a database to manage products . Each product might have multiple color and multiple size (for example, if the product is a T-shirt, the same shirt can be Small, Medium or Large and be red, green or blue) So I ended up with 3 tables.

  • Color: id, name
  • Size: id, name
  • Product: id, name

I need to be able to store how many products with a specific size and a specific color are in stock and the price for each as well. So I've created a 4th table with the fields:

  • color_id, size_id, product_id, quantity, price

I have a model for each table and to define the relationship between all of them I'm using the belongsToMany method. The "problem" is that it only allows to specify the foreign key of 2 tables (the example of the documentation is users, roles, and role_user).

Is there a way to define this relationship between these tables in Eloquent?

I need to be able to query the database to get, for example, all the available green, large products. I know how to achieve this using pure SQL, but I'm looking for a more Eloquent version.

What you are calling 'products' might be better named 'styles'. The products table is the pivot table with quantity and price. Yes, you have four tables: colors , sizes , and styles (see seeders for examples), plus the color_size_style pivot table, which I'll call products :

Migrations for colors, sizes, and styles tables:

// create colors table
Schema::create('colors', function (Blueprint $table) {
    $table->id();
    $table->string('color', 100);
});

// create sizes table
Schema::create('sizes', function (Blueprint $table) {
    $table->id();
    $table->string('size', 100);
});

// create styles table
Schema::create('styles', function (Blueprint $table) {
    $table->id();
    $table->string('style', 100);
});

Migration for products table, which is the color_size_style three-way pivot table with additional columns quantity and price:

// create products table
Schema::create('products', function (Blueprint $table) {
    $table->id();
    $table->foreignId('color_id')->constrained();
    $table->foreignId('size_id')->constrained();
    $table->foreignId('style_id')->constrained();
    $table->integer('quantity')->default(0);
    $table->decimal('price')->default(0.00);
});

Models for color, size, and style

// define color model with size and style relationships
class Color extends Model
{
    public function sizes()
    {
        return $this->belongsToMany(Size::class, 'products');
    }
    public function styles()
    {
        return $this->belongsToMany(Style::class, 'products');
    }
}

// define size model with color and style relationships
class Size extends Model
{
    public function colors()
    {
        return $this->belongsToMany(Color::class, 'products');
    }
    public function styles()
    {
        return $this->belongsToMany(Style::class, 'products');
    }
}

// define style model with color and size relationships
class Style extends Model
{
    public function colors()
    {
        return $this->belongsToMany(Color::class, 'products');
    }
    public function sizes()
    {
        return $this->belongsToMany(Size::class, 'products');
    }
}

Seeders for colors, sizes, and styles:

// seed default colors
class ColorSeeder extends Seeder
{
    public function run()
    {
        $colors = [
            ['color' => 'black'],
            ['color' => 'white'],
            ['color' => 'gray'],
            ['color' => 'maroon'],
            ['color' => 'purple'],
            ['color' => 'navy'],
            ['color' => 'teal']
        ];

        DB::table('colors')->insert($colors);
    }
}

// seed default sizes
class SizeSeeder extends Seeder
{
    public function run()
    {
        $sizes = [
            ['size' => 'XS'],
            ['size' => 'S'],
            ['size' => 'M'],
            ['size' => 'L'],
            ['size' => 'XL'],
            ['size' => 'XXL']
        ];

        DB::table('sizes')->insert($sizes);
    }
}

// seed default styles
class StyleSeeder extends Seeder
{
    public function run()
    {
        $styles = [
            ['style' => 'Unisex Short Sleeve T-Shirt'],
            ['style' => 'Unisex Tank Top'],
            ['style' => 'Unisex Pullover Hoodie'],
            ['style' => 'Women\'s Short Sleeve T-Shirt'],
            ['style' => 'Women\'s Flowy Long Sleeve Shirt'],
            ['style' => 'Men\'s Polo Shirt']
        ];

        DB::table('styles')->insert($styles);
    }
}

Now you can add an entry into the products table:

$color = Color::inRandomOrder()->first();
$size = Size::inRandomOrder()->first();
$style = Style::inRandomOrder()->first();

$color->sizes()->attach($size, ['style_id' => $style->id]);

// or in any other combination:
// $color->styles()->attach($style, ['size_id' => $size->id]);
// $size->colors()->attach($color, ['style_id' => $style->id]);
// $size->styles()->attach($style, ['color_id' => $color->id]);
// $style->colors()->attach($color, ['size_id' => $size->id]);
// $style->sizes()->attach($size, ['color_id' => $color->id]);

To get all possible combinations (not what we want):

select colors.color,sizes.size,styles.style from colors join sizes join styles;

To get what we've marked as products that exist:

select products.id,products.quantity,styles.style,sizes.size,colors.color,products.price
from products
join colors on colors.id=products.color_id
join sizes on sizes.id=products.size_id
join styles on styles.id=products.style_id
order by style,size,color;

Although technically not necessary, you'll probably want a product model as well. Or maybe a controller is enough - I'm not sure. But this should be enough to get your head around the three-way pivot concept. ;)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM