I have 3 tables users
, products
, product_users
and this logic:
- User has many products
- Product belongs to User
- this relationship stores in
product_users
by ids.
Why don’t I simply store
user_id
in products table and avoid this suffering?Because I want history of product ownership.
Anyway, I have hard time getting products owner (user) data by model relationships. It always return null
This is what I have so far:
Product.php
public function owner()
{
return $this->belongsTo(User::class, 'product_users', 'product_id', 'user_id'); // probably should get latest entry as current owner
}
User.php
public function products()
{
return $this->belongsToMany(Product::class, 'product_users', 'user_id', 'product_id');
}
product_users
Schema: (simply just stores ids of both products and user nothing more)
Schema::create('product_users', function (Blueprint $table) {
$table->id();
$table->foreignId('product_id')->nullable();
$table->foreignId('user_id')->nullable();
$table->timestamps();
});
Schema::table('product_users', function (Blueprint $table) {
$table->foreign('product_id')->references('id')->on('products')->onUpdate('cascade')->onDelete('cascade');
$table->foreign('user_id')->references('id')->on('users')->onUpdate('cascade')->onDelete('cascade');
});
What did I do wrong here?
2
Answers
You should use
hasOneThrough()
instead ofbelongsTo()
.The
belongsTo()
means you have a foreign id onProduct
, but since you have the pivot table, your all relation should build through the pivot table.Try:
User
Product
belongsTo
relationship is a relationship where one of your model has a reference column to another model, this doesn’t support having a pivot table. You cannot just build a model relationship you want then have a different database set-up relationship.Your database relationship is a "PLAIN"
many-to-many
so you should just treat the model relationship asmany-to-many
.wether you like it or not, your table design can support a user with many product and a product with many user, so you need to determine how you handle that case.
Assume you only want 1 user result for each product even though your table allows you to have many, you can just add additional column in your pivot table to determine the actual "Owner" of that product even though you have many to many relationship.
You can have your pivot table like below;
then your User Model
then your Product Model
this way, you have
users
relationship in your product which query all users belonging to a productthen an
owner
relationship also stored in your pivot table butowner
column value is 1all you have to do is make sure to owner value to 1 in the pivot table for the relationship that actually owns the product