Reputation: 1271
I am struggling to bind a model to the request in a unit test so that the relationship of the model can be retrieved in the form request.
This is the form request:
class TimeSlotUpdateRequest extends FormRequest
{
public function rules(): array
{
return [
'time' => [
'required', 'string', 'max:50',
Rule::unique('time_slots')
->where('schedule_id', $this->timeSlot->schedule->id)
->ignore($this->timeSlot),
],
];
}
}
This is the test (The assertExactValidationRules
comes from Jason McCreary's Laravel test assertions package):
/** @test **/
public function it_verifies_the_validation_rules(): void
{
$timeSlot = TimeSlot::factory()->create();
$request = TimeSlotUpdateRequest::create(
route('admin.timeSlots.update', $timeSlot),
'PATCH'
)
->setContainer($this->app);
$request->setRouteResolver(function () use ($request) {
return Route::getRoutes()->match($request);
});
$this->assertExactValidationRules([
'time' => [
'required', 'string', 'max:50',
Rule::unique('time_slots')
->where('schedule_id', $timeSlot->schedule->id)
->ignore($timeSlot->id),
],
], $request->rules());
}
The test passes when the where clause is removed from the test and form request but fails with the where clause with the error ErrorException: Trying to get property 'schedule' of non-object
I tried to step through a request with xDebug but still don't understand how to route model binding is done.
How can the $timeSlot
model be bound request or route so that the schedule
relationship is accessible in the form request?
Any help will be appreciated.
Upvotes: 1
Views: 1183
Reputation: 11
This is an old question, but I got here with the same issue. For anyone confused by the accepted answer, here are the suggested changes:
in the FormRequest:
...
Rule::unique('time_slots')
->where('schedule_id', $this->route('timeSlot')->schedule->id)
->ignore($this->route('timeSlot')),
...
and in the test:
...
$request->setRouteResolver(function () use ($request, $timeSlot) {
$route = Route::getRoutes()->match($request);
$route->setParameter('timeSlot', $timeSlot);
return $route;
});
...
Upvotes: 1
Reputation: 50531
The Route Model Binding is handled via a middleware, the SubstituteBindings
middleware. So the request would have to pass through the middleware stack. Since you are not doing that I suppose you could set the parameter on the route yourself:
$route->setParameter($name, $value);
$route
would be the route object returned from match
.
Also when dealing with a Request, if you want a route parameter you should be explicit about it and not use the dynamic property as it will return an input before it falls back to returning a route parameter:
$this->route('timeSlot');
Upvotes: 2