bump
Eloquent Relationship
Hi. I am defining an eloquent relation and I wondered what the best approach would be in describing this structure using Eloquent.
I have 3 tables, products, gifts and a link table that tells me which products have which gifts available to them. A single product can have many gifts and likewise a single gift can be attached to many products. In my admin panel I want to display the associated gifts on a product page and vice versa on the gift page.
Products
| ID | Name |
| 1 | Samsung TV |
| 2 | Sony TV |
| 3 | Xbox One |
Gifts
| ID | Name |
| 1 | T-Shirt |
| 2 | Mug |
Product Gifts
| ID | product_id | gift_id |
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 1 |
| 4 | 3 | 2 |
I have already written something but I'm a bit concerned I've made it more complicated than it needs to be. For example I've setup a Product and Gift model and I've also setup a Model for the ProductGift link table. Then in my Product model defined the following
class Products extends Model
{
public function productGifts()
{
return $this->hasMany('ProductGift');
}
}
This will return obviously the records fine but they are the "links" from the ProductGift table but not the gifts themselves.
On my Product model simply I want to return the gifts and on the Gift model I want to return the products. Something like this, possible?
class Products extends Model
{
public function gifts()
{
return $this->hasMany('Gift');
}
}
Any ideas and suggestions would be greatly appreciated. Thank You
A couple of thins stand out there.
First, Laravel uses a naming convention for pivot tables, so your Product Gifts table, should actually be gift_product. Next, hasMany() is a one-to-many and you are descripting a many-to-many relationship.
Many-To-Many: A product can have many gifts which can belong to many products. One-To-Many: A product can have many gifts which can belong to a product.
Also, your pivot table doesn't need its own id, you can make the relationship the primary key.
So, the migrations would look something like this:
//Products
class CreateProductsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
...
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('products');
}
}
//Gifts
class CreateGiftsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('gifts', function (Blueprint $table) {
$table->increments('id');
...
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('gifts');
}
}
//Pivot table
class CreateGiftProductTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('gift_product', function (Blueprint $table) {
$table->integer('gift_id')->unsigned();
$table->integer('product_id')->unsigned();
$table->timestamps();
$table->unique(['gift_id','product_id']);
$table->foreign('gift_id')
->references('id')
->on('gifts');
$table->foreign('product_id')
->references('id')
->on('products');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('gift_product');
}
}
Then your models will automagically resolve the pivot table name and field names.
//Product Model
class Product extends Model
{
public function gifts()
{
return $this->belongsToMany('App\Models\Gift');
}
}
//Gift Model
class Gift extends Model
{
public function products()
{
return $this->belongsToMany('App\Models\Product');
}
}
Here you have many to many setup and you can do this:
//show all the gifts for this product
$product = Product::where($id)->firstOrFail();
dd($product->gifts());
//show all the products for this gift
$gift= Gift::where($id)->firstOrFail();
dd($gift->products());
//show all the gifts this product has and what products those gifts belong to:
$product = Product::where($id)->firstOrFail();
$results = [];
foreach($product->gifts() as $gift) {
$results[$gift->name] = $gift->products();
}
//then act on $results, or this can be done purely in OOP, but I'll let you figure that out.
Please or to participate in this conversation.