I am developing a database for giveaways. I have two main tables: participants
and giveaways
with an N:N relationship since a participant can participate to one or more giveaways and a giveaway can have one or more participants. My (simplified) table structure is the following:
giveaways
----------------------
uuid name
participant_giveaway
----------------------
id giveaway_uuid fiscal_code
participants
----------------------
fiscal_code first_name last_name
Now, I have followed the docs for Laravel 11 but the relationship gives me wrong results. For instance, I have 4 participants for a giveaway and when I try to retrieve them with Giveaway::find($uuid)->participants
, it returns 2 random participants that are linked to another giveaway.
This is my Giveaway
model.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Collection;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
class Giveaway extends Model implements HasMedia
{
use HasFactory, InteractsWithMedia, HasUuids;
protected $primaryKey = 'uuid';
protected $fillable = [
'name',
'terms_and_conditions',
'privacy_policy',
'date_start',
'date_end'
];
protected $casts = [
'date_start' => 'datetime',
'date_end' => 'datetime',
];
public function participants(): BelongsToMany
{
return $this->belongsToMany(Participant::class, 'participant_giveaway', 'giveaway_uuid', 'fiscal_code')
->withPivot('drawn', 'code', 'expiration_date', 'status', 'created_at')->withTimestamps();
}
public function drawableParticipants(): Collection
{
return $this->participants()->where('drawn', 0)->get()->pluck('participant');
}
}
This is my Participant
model.
<?php
namespace App\Models;
use Database\Factories\ParticipantFactory;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Support\Collection;
class Participant extends Model
{
use HasFactory;
protected $fillable = [
'name',
'date_start',
'date_end'
];
public function giveaways(): BelongsToMany
{
return $this->BelongsToMany(Giveaway::class, 'participant_giveaway', 'fiscal_code', 'giveaway_uuid')
->withPivot('drawn', 'code', 'expiration_date', 'status', 'created_at')->withTimestamps();
}
}
Edit: I made a dump of the query being run when accessing the giveaway's participants through the relationship. I get: "select * from participants inner join participant_giveaway on participants.id = participant_giveaway.fiscal_code where participant_giveaway.giveaway_uuid = ?"
. The problem is that Laravel is joining the participants table on the id
instead of the fiscal_code
. I correctly set up the fields on which to join in the model so I do get why it does not join on them.
Since I could not figure out why Laravel still persists to join on the id
column instead of the fiscal_code
, I opted for the easiest road and changed the participants primary key from id
to fiscal_code
.
Furthrmore, I also had a typo in my Participant giveaways()
method. Instead of using this->belongsToMany()
I was using this->BelongsToMany
(with a capital B).
Edit: I opened an issue on their repo and told me I had to pass another argument on the the belongsToMany method (from either side) to customize the joining column on the participants
table, like so:
public function participants(): BelongsToMany
{
return $this->belongsToMany(Participant::class, 'participant_giveaway', 'giveaway_uuid', 'fiscal_code',
relatedKey: 'fiscal_code')
->withPivot('drawn', 'created_at')
->withTimestamps();
}