Show me the error message you are getting. Copy and paste it here, but am guessing after writing all this you've probably already solved it.
Three way Eloquent relationship definition and saving
I'm building a Laravel app (with Vue3 and InertiaJS), and I'm attempting to create relationships between three models:
- User
- Area
- WorkHours
where WorkHours is the primary model. In addition to the main data (date, hours, comments, reason), I need to create the following relationships:
- User - the
WorkHoursentry is for work performed by the member (akaUser), so I need to be able to see total hours for the user for the year. One user can have manyWorkHoursrecords. - Area - The part of the club that the work hours has been performed in/for. Each
WorkHoursentry has one approver, and one approver can be associated with manyWorkHoursentries. - Approver - Every
Areahas specific people that can approveWorkHoursentries, and these are defined asapproversin theAreamodel related to theUsermodel asapprover_id(abelongsToMany()relationship both ways). EachWorkHoursentry has one approver, but one approver can be associated with manyWorkHoursentries.
It seems then that the work_hours table should have _id values for each of the three relations (user_id, area_id, and approver_id). However, as I read the Eloquent docs, that means that WorkHours would be a child of both Area and Approver via belongsTo(), since the child gets the _id value of the parent.
So with all that here's the code:
work_hours migrations
public function up()
{
Schema::create('work_hours', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->unsignedBigInteger('area_id');
$table->unsignedBigInteger('approver_id');
$table->date('date');
$table->decimal('hours', 5, 2);
$table->string('reason')->nullable();
$table->string('comments')->nullable();
$table->timestamps();
$table->softDeletes();
$table->foreign('user_id')
->references('id')
->on('users');
$table->foreign('approver_id')
->references('id')
->on('users');
$table->foreign('area_id')
->references('id')
->on('areas');
});
}
WorkHours
class WorkHours extends Model
{
use HasFactory, SoftDeletes;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'date',
'hours',
'reason',
'comments'
];
public function user()
{
return $this->belongsTo(User::class);
}
public function approver()
{
return $this->belongsTo(User::class, 'approver_id');
}
public function area()
{
return $this->belongsTo(Area::class);
}
}
Area
class Area extends Model
{
use HasFactory, SoftDeletes;
protected $fillable = [
'name'
];
public function approvers()
{
return $this->belongsToMany(User::class, 'area_user', 'area_id', 'user_id');
}
public function workHours()
{
return $this->hasMany(WorkHours::class);
}
}
User
class User extends Authenticatable
{
public function workHours()
{
return $this->hasMany(WorkHours::class);
}
public function areas() {
return $this->belongsToMany(Area::class);
}
public function approval()
{
return $this->belongsTo(WorkHours::class, 'approver_id');
}
}
Now where I'm running into the problem is saving everything when I submit my form to my controller. From my form I have the following pieces of info
- user_id
- area_id
- approver_id
- date
- hours
- reason
- comments
So based on the docs, I would think I would do something like this in WorkHoursController:
public function store(StoreWorkHoursRequest $request)
{
$validated = $request->validated();
$user = User::find($validated['user']);
$area = Area::find($validated['area']);
$approver = User::find($validated['approver']);
$wh = WorkHours::make([
'date' => $validated['date'],
'hours' => $validated['hours'],
'reason' => $validated['reason'],
'comments' => $validated['comments']
]);
$wh->user()->associate($user);
$wh->area()->associate($area);
$wh->approver()->associate($approver);
return Redirect::route('workHours.index')->with('success', 'Work Hours saved');
}
but I get an error about user_id not having a default value, which is true, since my understanding is that Eloquent handles assigning that. What I can do is make user_id, approver_id, and area_id fillable in the WorkHours model and save like this:
$wh = WorkHours::create([
'date' => $validated['date'],
'hours' => $validated['hours'],
'reason' => $validated['reason'],
'comments' => $validated['comments'],
'user_id' => $validated['user'],
'approver_id' => $validated['approver'],
'area_id' => $validated['area']
]);
and it works, but it is cloogy, and bypasses Eloquent.
- Do I have my relationships set up properly for what I am trying to accomplish?
- How do I need to store the records in my controller to properly use Eloquent?
Please or to participate in this conversation.