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?