I have an application that I would like to be able to attach notes to various types of models through nested scoped bindings.
/**
* Note Routes - Using scoped bindings for polymorphic relationships
*/
Route::scopeBindings()->group(function () {
Route::post('projects/{project}/notes', [NoteController::class, 'store']);
Route::put('projects/{project}/notes/{note}', [NoteController::class, 'update']);
Route::delete('projects/{project}/notes/{note}', [NoteController::class, 'destroy']);
Route::post('clients/{client}/notes', [NoteController::class, 'store']);
Route::put('clients/{client}/notes/{note}', [NoteController::class, 'update']);
Route::delete('clients/{client}/notes/{note}', [NoteController::class, 'destroy']);
Route::post('users/{user}/notes', [NoteController::class, 'store']);
Route::put('users/{user}/notes/{note}', [NoteController::class, 'update']);
Route::delete('users/{user}/notes/{note}', [NoteController::class, 'destroy']);
Route::post('projects/{project}/trial-balances/{trialBalance}/notes', [NoteController::class, 'store']);
Route::put('projects/{project}/trial-balances/{trialBalance}/notes/{note}', [NoteController::class, 'update']);
Route::delete('projects/{project}/trial-balances/{trialBalance}/notes/{note}', [NoteController::class, 'destroy']);
Route::post('projects/{project}/trial-balances/{trialBalance}/accounts/{account}/notes', [NoteController::class, 'store']);
Route::put('projects/{project}/trial-balances/{trialBalance}/accounts/{account}/notes/{note}', [NoteController::class, 'update']);
Route::delete('projects/{project}/trial-balances/{trialBalance}/accounts/{account}/notes/{note}', [NoteController::class, 'destroy']);
Route::post('projects/{project}/trial-balances/{trialBalance}/journal-entries/{journalEntry}/notes', [NoteController::class, 'store']);
Route::put('projects/{project}/trial-balances/{trialBalance}/journal-entries/{journalEntry}/notes/{note}', [NoteController::class, 'update']);
Route::delete('projects/{project}/trial-balances/{trialBalance}/journal-entries/{journalEntry}/notes/{note}', [NoteController::class, 'destroy']);
});
I thought the scoped bindings were working, but apparently not, no errors thye would just work anyway - I found that I was not adding the expected models to the controller method
Before:
public function store(StoreNoteRequest $request): NoteResource
{
// Get the parent model that should receive the note
$parent = $this->getParentFromRoute($request);
// $data = $request->validated();
$data['created_by'] = auth()->user()->id;
$note = $parent->notes()->create($data);
return new NoteResource($note);
}
after
public function store(StoreNoteRequest $request, Project $project, User $user, TrialBalance $trialBalance, Account $account, Resource $resource): NoteResource
{
// Get the parent model that should receive the note
$parent = $this->getParentFromRoute($request);
// $data = $request->validated();
$data['created_by'] = auth()->user()->id;
$note = $parent->notes()->create($data);
return new NoteResource($note);
}
The "after" example works even if the route is not providing some of the models AND one of the method parameters can't actually get passed in the request. The way I see it this should not be working at all!
So:
- My route definitions feel sloppy and repetitive - is there a better (dynamic) way to define the note methods on different models?
- How is the method working at all?? Does not seem to matter what order they (method parameters) are in or if only some of the models are passed. Testing with several of the routes that would exist show that Laravel is actually resolving the bindings! I don't understand.