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
WorkHours
entry 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 manyWorkHours
records. - Area - The part of the club that the work hours has been performed in/for. Each
WorkHours
entry has one approver, and one approver can be associated with manyWorkHours
entries. - Approver - Every
Area
has specific people that can approveWorkHours
entries, and these are defined asapprovers
in theArea
model related to theUser
model asapprover_id
(abelongstoMany()
relationship both ways). EachWorkHours
entry has one approver, but one approver can be associated with manyWorkHours
entries.
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?