I have this code:
class BunnyUpdateRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'id' => ['required', 'min:1'],
'status' => ['required', Rule::enum(BunnyStatus::class)]
];
}
public function validationData(){
return array_merge($this->all(), [
'id' => $this->route()->parameter('bunny_id'),
'status' => $this->route()->parameter('status')
]);
}
}
class BunnyController extends Controller
{
public function update(BunnyUpdateRequest $bunnyUpdateRequest)
{
$fields = $bunnyUpdateRequest->validated();
$bunny = Bunny::findOrFail($fields['id']);
if ($bunny->status === BunnyStatus::Done)
return Response::json(null, 422);
$bunny->status = $fields['status'];
$bunny->save();
return Response::json(null, 200);
}
}
Normally I would use $request->input
to get the validated body input field or query param. As far as I understand validation runs in this case. At least I hope so. The upper code gets path params which are empty if I try to get the same way. This is why I used the validated()
array. I don't like this approach, because I find the code ugly. Is there a way to get these path params as object properties on the request object just as body input fields and query params? Is there a way to get a Bunny instance instead of the id with request model binding somehow?
1st of all the answer you provided is good one, from the conventional point of view i.e. you fetched the two parameters from the URL
then validated (using custom Form Request
) and updated the records if BunnyStatus
not equal to DONE
.
But Laravel itself provides some in built features with which you can do the same operation with lesser lines of code as well as without custom Form Request
.
That is the reason I am writing this answer which will provide another perspective to do the same and also help you to manage 404 error
automatically.
Change Your Route defination like this.
use App\Http\Controllers\BunnyController;
use App\Models\Bunny;
use App\Enums\BunnyStatus;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;
Route::post('bunnies/{bunny}/update-status/{status}', [BunnyController::class, 'update'])
->missing(function (Request $request) {
// Redirect to custom error page or wherever you want your user to redirect if if an implicitly bound `model/Enum` is not found.
return Redirect::route('404');
});
Above I have implemented implicit model binding
, implicit enum binding
along with missing model/enum Behaviour
.That is the reason you will not need custom form request
because basic-validation
will be done there.
Then in the Controller do this. This will by default fetch & injected to the update()
method the matching model instance of the Bunny
model as Bunny $bunny
& BunnyStatus $status
as Enum passed to the URL
after validation that is being done in the Route defination.
public function update(Bunny $bunny, BunnyStatus $status):
{
// Check if the status is 'DONE' and return a 422 response
if ($status === BunnyStatus::DONE) {
return Response::json(null, 422);
}
// Update the Bunny's status
$bunny->status = $status->value;
$bunny->save();
return Response::json(null, 200);
}
Remember to import these class and also the orther required class to the top of the Controller class.
use App\Models\Bunny;
use App\Enums\BunnyStatus;
Citation:-