How does Laravel handle PUT requests from browsers? - laravel

I know browsers only support POST and GET requests, and Laravel supports PUT requests using the following code:
<?= Form::open('/path/', 'PUT'); ?>
... form stuff ...
<?= Form::close(); ?>
This produces the following HTML
<form method="POST" action="http://example.com/home/" accept-charset="UTF-8">
<input type="hidden" name="_method" value="PUT" />
... form stuff ...
</form>
How does the framework handle this? Does it capture the POST request before deciding which route to send the request off to? Does it use ajax to send an actual PUT to the framework?

It inserts a hidden field, and that field mentions it is a PUT or DELETE request
See here:
echo Form::open('user/profile', 'PUT');
results in:
<input type="hidden" name="_method" value="PUT">
Then it looks for _method when routing in the request.php core file (look for 'spoofing' in the code) - and if it detects it - will use that value to route to the correct restful controller.
It is still using "POST" to achieve this. There is no ajax used.

Laravel uses the symfony Http Foundation which checks for this _method variable and changes the request to either PUT or DELETE based on its contents. Yes, this happens before routing takes place.

You can also use an array within your form open like so:
{{ Form::open( array('route' => array('equipment.update', $item->id ),
'role' => 'form',
'method' => 'put')) }}
Simply change the method to what you want.

While a late answer, I feel it is important to add this for anyone else who finds this and can't get their API to work.
When using Laravel's resource routes like this:
Route::resource('myRoute','MyController');
It will expect a PUT in order to call the update() method. For this to work normally (outside of a form submission), you need to make sure you pass the ContentType as x-www-form-urlencoded. This is default for forms, but making requests with cURL or using a tool like Postman will not work unless you set this.

PUT usually refers to update request.
When you open a form inside laravel blade template using,
{{ Form::open('/path/', 'PUT') }}
It would create a hidden field inside the form as follows,
<input type="hidden" name="_method" value="PUT" />
In order for you to process the PUT request inside your controller, you would need to create a method with a put prefix,
for example, putMethodName()
so if you specify,
{{ Form::open('controller/methodName/', 'PUT') }}
inside Form:open. Then you would need to create a controller method as follows,
class Controller extends BaseController {
public function putMethodName()
{
// put - usual update code logic goes here
}
}

Related

my delete query is not working in laravel

I am trying delete database data in Laravel. but this is not working my way.
my view page is
{{url('/deleteReview/'.$Review->id)}}
my web is
Route::post('/deleteReview/{id}','adminController#deleteReview');
my controller delete function is
public function deleteReview($id){
$deleteReview = Review::find($id);
$deleteReview->delete();
return redirect('/manageReview');
}
Are you trying to delete the review by opening the page /deleteReview/<id> in your browser? If so, this would be a GET request, so change the route to a get route:
Route::get('/deleteReview/{id}','adminController#deleteReview');
Please note as per the comments that a GET request should never change data server side. If data is changed using a GET request then there is a risk that spiders or browser prefetch will delete the data.
The correct way to do this in Laravel is using a POST request and use Form Method Spoofing to simulate a DELETE request. Your route entry would then look like this:
Route::delete('/deleteReview/{id}','adminController#deleteReview');
And your form would look like this:
<form action="/deleteReview/{{ $Review->id }}" method="POST">
<input type="hidden" name="_method" value="DELETE">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
</form>
At Controller you should first set Validation for ID that you have to Delete. Create your own customize request handler such as DeleteRequest.
Once you get ID at Controller then used this code
public function deleteReview(DeleteRequest $id){
DB::table('reviews')->where('id', $id)->delete();
return redirect('/manageReview');
}
I hope it will work.

Laravel - route("resource.destroy") calls "resource.show"

This is the web.php
Route::group(['middleware' => 'auth'],
function () {
Route::get('letters/getRows', 'LetterController#getRows')->name('letters.getRows');
Route::get('letters/{letter}/A4', 'LetterController#A4')->name('letters.A4');
Route::get('letters/{letter}/A5', 'LetterController#A5')->name('letters.A5');
Route::resource('letters', 'LetterController');
}
);
I created a link as follow
"<a class='mx-2 h5' href='".route('letters.destroy', $entity->id)."'><i class='icon-remove-circle'></i></a>".
where the $entity->id is the id of the letter. The problem is, it links to show method not the destroy method. What can I do?
Using a form like this
{{ Form::open(array('route' => array('letters.destroy', $entity->id), 'method' => 'delete')) }}
<button type="submit" >Delete Account</button>
{{ Form::close() }}
may solve the problem but I want to use a tag not a form.
update
In the php artisan route:list, the url of destroy and show are the same
thanks
When you use the Route::resource method it will create, among others, a route to DESTROY a resource like this: /letters/:id/ and another route to EDIT the resource: /letters/:id, and one more to SHOW /letters/:id
They all look the same. However, the difference is in the HTTP method/verb used to reach each route.
If you look to the output if php artisan route:list, you will find the list of HTTP methods used. Something like:
GET|HEAD | letters/{letter} | letters.show
PUT|PATCH | letters/{letter} | letters.update
DELETE | letters/{letter} | letters.destroy
Therefore, to show a letter, you use a GET method, to edit a letter, use PUT method, and to destroy/delete, you use a DELETE method.
When you use an a tag, the browser will use the GET method, thus will reach the letters.show route. Html forms, can use POST or GET. Finally to use the DELETE http method, you need a form with hidden input named _method and the value="delete inside the form. Check the docs for more details.
There is also a note about this in LaravelCollective package documentations
Note: Since HTML forms only support POST and GET, PUT and DELETE methods will be spoofed by automatically adding a _method hidden field to your form.
Finally, if you must use an anchor tag <a>, you could use javascript to listen to the click event and submit a form with DELETE method.
Update to add an example:
You can find an example of using an anchor tag to submit the form, in the default app layout in the framework here
And this is a modified version to submit a delete request:
<a class="dropdown-item" href="#"
onclick="event.preventDefault();
document.getElementById('destroy-form').submit();">
{{ __('DELETE') }}
</a>
<form id="destroy-form" action="{{ route('letters.destroy', $entity) }}" method="POST" style="display: none;">
#method('DELETE')
#csrf
</form>
You cant. If you want to make a DELETE request you need to spoof it via a form (method POST, _method DELETE) or use Javascript.
Hyperlinks will cause new requests which will be GET requests. That is just how the web works.

Laravel confused if I should use <form> tag or not when doing a ajax put request

I am making a simple put request to my app backend using axios.put();
This all works, I have a button that is binded to vue like #click="submitForm"
However looking around I see that some people still wrap their input fields in forms like those:
<form method="POST" #submit.prevent="onSubmit" action="{{ route('someRoute') }}" id="form-submit">
{{ method_field('PUT') }}
{{ csrf_field() }}
Even if I dont use a form like the one above I get the same result when calling my ajax put request.
Laravel allready adds csfr headers to axios by default in resources/assets/js/bootstrap.js
So is there any reason I still should wrap my inputs in a form like above?
Thanks
Your ajax request doesn't matter if you do your inputs in form tags or not, because the request still sends and receives data from a server.
I would use a form tag because everybody can read the markup much easier and it could be usefull for writing less code in javascript - one example
<form action="" method="">
<div class="form-group">
<label class="control-label">Input</label>
<input type="text" name="input" />
</div>
</form>
$(document).ready(function() {
$('#some-form').on('submit', function() {
var data = $(this).serialize();
... do whatever you want (like ajax call) ...
return false;
});
);
You're using an Ajax request, in which case a standard "form submit" would get prevented. Putting a form around it is not obligatory, especially if you use a button element, which is not a classic form element anyway.

can I use route() to make a DELETE request in laravel

I'm using laravel and trying to delete something. Is it possible to specify the DELETE method on laravel's route()??
e.g
route('dashboard-delete-user', ['id' => $use->id, 'method'=> 'delete'])
or something like that??
EDIT:
What I meant was could I specify that in a link or a button in my blade template. Similar to this:
href="{{ route('dashboard-delete-user') }}
Yes, you can do this:
Route::delete($uri, $callback);
https://laravel.com/docs/master/routing#basic-routing
Update
If for some reason you want to use route only (without a controller), you can use closure, something like:
Route::get('delete-user/{id}', function ($id) {
App\User::destroy($id);
return 'User '.$id.' deleted';
});
No or at least I haven't figure out how to.
The only way for this to work out of the box would be to build a form to handle it. At the very minimum, you would need...
<form action="{{ route('dashboard-delete-user') }}" method="POST">
{{ method_field('DELETE') }}
{{ csrf_field() }}
<button type="submit" value="submit">Submit</button>
</form>
Or you can just create the get route which you are trying to link to and have it handle the logic. It doesn't need to be a route which only respondes to delete requests to delete a resource.
Yes you can, using a URL helper. https://laravel.com/docs/5.2/helpers#urls
There are several options to choose from.

Pass old input after Form Request validation in laravel 5

if the validation fails it's not clear to me how i could pass the old input to fill again the form.
I mean, I know how to pass the data when using the Validator class and redirecting after fail with the method withInput(), but I'm trying to learn how to use Form Requests provided in laravel 5. Thanks
$username = Request::old('username');
or in view:
{{ old('username') }}
Read more: http://laravel.com/docs/5.0/requests#old-input
You can redirect with old data like below with validation error
return redirect()->back()->withErrors($validator)->withInput();
<input type="text" name="username" value="{{ old('username') }}">
you must also define withInput() for the http route when redirecting to a page for example
return back()->withInput();

Resources