Reputation: 303
I have a many-to-many relationship like so:
user
- user_id
user_blocks
- blocker_user_id
- blocked_user_id
- unblocked (Timestamp)
Where blocker and blocked_user_id are a composite primary key, both existing as a foreign key to the user table's user_id. Both tables are InnoDB.
When I attempt to do the following:
$user = User::find(1)
$blocked_user = $user->blocked()->where('blocked_user_id', 2)->first();
$blocked_user->unblocked = User::freshTimestamp();
$blocked_user->save();
It seems to think I wish to update a column in the user table, rather than the user_blocks table. This is simply an sql error where the user table is attempting to be updated with the non-existent column unblocked
.
I've tried adding ->pivot
and ->pivot()
to the assignment for $blocked_user in the example. The first gives me an error in Eloquent\Model::performUpdate, Call to a member function update() on a non-object
and the latter gives me call_user_func_array() expects parameter 1 to be a valid callback, class 'Illuminate\Database\Query\Builder' does not have a method 'pivot'
in Eloquent\Builder::__call.
The model for the user table defines the relationship to itself as:
public function blocked() {
return $this->belongsToMany(
'User',
'user_blocks',
'blocker_user_id',
'blocked_user_id'
)->withPivot('unblocked');
}
There is no model for the user_blocks table as I do not know how to define an Eloquent model with a composite primary key (I've searched everywhere and that doesn't seem to be a question anyone has asked).
I realize the schema is less than optimized for Eloquent, but this is grafting eloquent onto a Codeigniter project with a pre-established schema. An otherwise pleasant experience over using Codeigniter models.
Upvotes: 2
Views: 2725
Reputation: 303
It seems that Eloquent currently doesn't handle composite primary keys explicitly. However, I was able to solve the problem by making a model of the user_blocks table and specifying only one of the primary keys:
class Blocker extends Model {
protected $table = "user_blocks";
protected $primaryKey = "blocker_user_id";
public $timestamps = false; // Don't track nonexistent created_at/updated_at columns
}
Then, in the logic to update the unblocked column I simply did the following:
$blocked_user = Blocker::where('blocker_user_id', $user->user_id)
->where('blocked_user_id', $user_to_be_unblocked_id)
->first();
$blocked_user->unblocked = Blocker::freshTimestamp();
$blocked_user->save();
It isn't the most elegant way to solve the issue, but it does work until Eloquent gains support for composite primary keys.
Upvotes: 4