Laravel API routes and Controller variable - laravel

I'm a new user of Laravel, and i'm a bit confused with Laravel route API and the name of variable in the controller.
Here an example to explain :
An API route
Route::middleware('auth:sanctum')->group( function () {
Route::resource('cepage', CepageController::class);
});
For a PUT or PATCH, i have this function in the CepageController :
public function update(Request $request, Cepage $cepage)
{
$input = $request->all();
$validator = Validator::make($input, [
'libelle' => 'required',
'abrege' => 'required'
]);
if($validator->fails()){
return $this->sendError($validator->errors());
}
$cepage->libelle = $input['libelle'];
$cepage->abrege = $input['abrege'];
$cepage->save();
return $this->sendResponse(new CepageResource($cepage), 'Cépage mis à jour');
}
If you see my route name "cepage" have the same name of the $cepage variable of the function declaration in the controller, Laravel update the record in the database.
If they are no identical, Laravel create a new record in the database.
Why they need to be exactly the same ?
I think i miss something in the documenation of Laravel.
Thanks for your explanations.

It needs to be the same, for laravel to know what object does he needs to create for us.
Route::resource does a few routes for you, with the base url give into it (https://laravel.com/docs/8.x/controllers#actions-handled-by-resource-controller)
So once you have defined Route::resource('cepage', CepageController::class)
You will have the following routes defined:
Verb URI Action Route Name
GET /cepage CepageController#index cepage.index
GET /cepage/create CepageController#create cepage.create
POST /cepage CepageController#store cepage.store
GET /cepage/{cepage_id} CepageController#show cepage.show
GET /cepage/{cepage_id}/edit CepageController#edit cepage.edit
PUT/PATCH /cepage/{cepage_id} CepageController#update cepage.update
DELETE /cepage/{cepage_id} CepageController#destroy cepage.destroy
And in the controller you need to follow the naming, because in the url you have only ids of the object. But if you follow the naming, laravel will fetch the object for you by its id. See:
public function update(Request $request, $cepage_id)
{
$cepage = Cepage::find($cepage_id);
//here you have to fetch the object for yourself to access it
}
public function update(Request $request, Cepage $cepage)
{
//here you can already access $cepage variable
}

Related

Why this Implicit Binding is not working? - Laravel

I'm using Laravel 9. I have a problem, i wil appreciate any help.
I Have a Model named Entity, a controller EntityControler, and a FormRequest UpdateEntityRequest.
My API Routes looks like:
Route::apiResource('entities', EntityController::class);
so i have show, create, store, update, delete... routes.
This is muy update method in EntityController (without the code/not important now)
public function update(UpdateEntityRequest $request, Entity $entity)
{
return $entity;
}
the update method works perfect. But I want another update method for only a section and here starts the problem.
This is my new API Routes:
Route::apiResource('entities', EntityController::class);
Route::patch('/entities/{id}/{section}',[EntityController::class, 'updateSection' ]);
And this is the new method in the controller(without code yet):
public function updateSection( UpdateEntityRequest $request,Entity $entity, $section)
{
return $entity;
}
But this last method return [] insted of the Entity and the update method works. WHY?
I change de uri in Postman for update PUT {{baseUrl}}/entities/1 and for updateSection {{baseUrl}}/entities/1/1 .
Why does work in update and not in updateSection?
PD:
This method work, and give the id, and I can create a Entity from this:
public function updateSection( UpdateEntityRequest $request, $entity, $section)
{
return $entity;
}
But this is not what I want. Any idea why this happen?
please make sure your uri segment is same as the variable name in the controller, in your case replace id with entity
Route::patch('/entities/{entity}/{section}',[EntityController::class, 'updateSection' ]);
for more please see documentation
Make the route param name consistent in your route api.php and your function updateSection in EntityController
Route::patch('/entities/{entity}/{section}',[EntityController::class, 'updateSection' ]);
and
public function updateSection( UpdateEntityRequest $request,Entity $entity, $section)
{
return $entity;
}

Laravel - how to retrieve url parameter in custom Request?

I need to make custom request and use its rules. Here's what I have:
public function rules()
{
return [
'name' => 'required|min:2',
'email' => 'required|email|unique:users,email,' . $id,
'password' => 'nullable|min:4'
];
}
The problem is that I can't get $id from url (example.com/users/20), I've tried this as some forums advised:
$this->id
$this->route('id')
$this->input('id')
But all of this returns null, how can I get id from url?
When you are using resources, the route parameter will be named as the singular version of the resource name. Try this.
$this->route('user');
Bonus points
This sound like you are going down the path of doing something similar to this.
User::findOrFail($this->route('user'));
In the context of controllers this is an anti pattern, as Laravels container automatic can resolve these. This is called model binding, which will both handle the 404 case and fetching it from the database.
public function update(Request $request, User $user) {
}

Laravel - How to not pass unused parameter in controller

I have a route for example -
Route::get('/api/{user}/companies/{company}', [CompanyController::class, 'getCompanies'])
and a function in this controller
public function getCompanies(User $user, Company $company) {
$companies = $company->all();
return response()->json(['companies' => $companies]);
}
I am not using the $user instance in the function and I would like to not pass a User $user param in it, but I want that the route has user id as a param for clarity on the frontend.
I found a solution of using middleware with the forgetParameter() method but I don't want to add new middleware or declare it only for this route.
I can just leave that unused param in my function and everything will work just fine, but I am curious is there some elegant solution for this case.
public function getCompanies(Company $company, ?User $user = null)
{
return response()->json(['companies' => $company->all()]);
}
Pass $user to the last position and give it a default value
I think you can put a _ instead of passing a parameter, but I could be wrong.

Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException The POST method is not supported for this route. Supported methods: GET, HEAD

these are my codes for route and controller
routes:
Route::get('/form/create','MyformController#create')->name('form');
Route::post('form', 'MyformController#store');
controller:
public function create()
{
return view('formsubmitted');
//i have put form.create as shown in a laravel tutorial
//but it was showing an error that view form.create is not found, hence i
//changed it to formsubmitted(i created that form)
}
public function store(Request $request)
{
$validateData = $request->validate(
[
'Full Name'=>'required',
'Email'=>'required',
'Feedback'=>'required',
]);
form::create($request->all());
}
I am new to laravel and doing the task of creating a feedback form and storing user info and answer to a database.
I hope to hear from you guys soon. Thank you
/form/create/ and form are two different routes. If you want the same route for the GET and POST function, the routes have to be the same.
Route::get('/form/create','MyformController#create')->name('form');
Route::post('/form/create', 'MyformController#store');
If it is rest api then it might me authentication issue
goto VerifyCsrfToken.php and add there your url for eception
for eg.
protected $except = [
'/anyotherurl',
'/api/userlist'
];

PUT in laravel API

I'm studying api rest with laravel, I was able to implement all methods except PUT. Although the routes and controllers are correctly configured a response to a request using the PUT method is "laravel put Sorry, the page you are looking for could not be found.", As now image.
here is the method code in the controller in app/Http/Controllers/LivroController.php:
public function store(Request $request) {
$livro = $request->isMethod('put') ? Livro::findOrFail($request->livro_id) : new Livro;
$livro->id = $request->input('livro_id');
$livro->nome = $request->input('nome');
$livro->descricao = $request->input('descricao');
$livro->user_id = 1; //$request->user()->id;
if($livro->save()) {
return new LivroResource($livro);
}}
here is the route code in /routes/api.php:
Route::put('livro', 'LivroController#store');
change your postman method to POST and then add new parameter in your Body :
"_method" : PUT
This is because HTML forms do not support PUT, PATCH or DELETE actions. So, when defining PUT, PATCH or DELETE routes that are called from an HTML form, you will need to add a hidden _method field to the form
If you want to create new data, you should use post method,
Route::post('livro', 'LivroController#store');
public function store(Request $request) {
If you want to update exist data you should use put method,
Route::put('livro/{id}', 'LivroController#update');
public function update(Request $request, $id) {
You can use this package https://github.com/durmus-aydogdu/laravel-resource for rest calls. This package highly customizable for rest and resource calls.
Is better that you use controllers type resources and for this case the put method. Also you should validate the request. For example:
public function update(Request $request, $id)
{
$livro = Livro::findOrFail($id);
$validator = Validator::make($request->all(), [
'livro_id' => 'required',
'nome' => 'required',
'descricao' => 'required',
]);
if ($validator->fails()) {
return response()->json(['errors'=>$validator->messages()],Response::HTTP_UNPROCESSABLE_ENTITY);
}else{
$livo->update($request->all());
return response()->json(['livro'=>$livro], Response::HTTP_OK);
}
}

Resources