Fail to retrieve Post data with Laravel - laravel

I try to learn Laravel (v.9) from scratch but fail to do a simple basic task:
I just want to send "post_var" by POST request and display the var.
My form (blade template):
<form action="/post_and_show" method="POST">
#csrf
#method('post')
<input type="text" name="post_var">
<input type="submit" value="send">
</form>
My Route (in web.php) with some dd() i tried to find the problem
Route::post('/post_and_show', function (Request $request) {
dd($request->method()); // returns GET ?? !!
// chrome debugger network tab show clearly its a POST request...
dd($request->all()); // returns empty Array
dd($request->post_var); // returns null
dd($request->getContent()); // returns string but i want param only
// "_token=yBBYpQ303a1tSiGtQF6zFCF6p6S7qadVfHMk4W7Q&_method=post&post_var=12345"
});
What am i doing wrong here?
Tried several methods i found in the documentation but non worked so far.
EDIT: I removed "#method('post')"
Btw.: My initial version that did not work either had no "#method('post')". I added it later on in the hope it might help...
<form action="/post_and_show" method="POST">
#csrf
<input type="text" name="post_var">
<input type="submit" value="send">
</form>
But have still the same problems:
Route::post('/post_and_show', function (Request $request) {
dd($request->method()); // returns GET ?? !! but chrome says its a post request
dd($request->post_var); // returns null
dd($request->get('post_var'));// returns null
dd($request->getContent()); // returns complete body and header in one string
dd($request->all()); // return empty Array
});
EDIT 2:
Googleing i found "createFromGlobals":
use Illuminate\HTTP\Request; // just added this to show which class i use here...
use Illuminate\Support\Facades\Route;
Route::post('/post_and_show', function () {
dd(Request::createFromGlobals()->get('post_var')); // returning expected value
});
This works for me, but i can't find this method in documentation. Sorry, i am new to laravel and even php, so this seems all completely crazy to me.. ;-)
EDIT 3:
If i use a simple Controller it works too...
Controller:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class FormController extends Controller
{
public function show(Request $request)
{
dd($request->post_var); // returns expected value...
}
}
Route:
Route::post('post_and_show', [FormController::class, 'show']);
So only in case i use the $request immediatly in the callback it does not work as expected. ( Either by design or bug??)

Related

Why is record not deleting and response is 303 in Laravel 9, Inertia and Vue3?

I have following code in route web.php file.
Route::resource('dailyrevenue', DailyRevenueController::class)->middleware('auth');
Then in my DailyRevenueController.php
public function destroy(DailyRevenue $revenue)
{
$revenue->delete();
return redirect()->back();
}
And in my vue3 code:
const submit = function (id) {
const check = confirm("Are you sure to delete ?")
if (check) {
Inertia.delete(route('dailyrevenue.destroy',id), {
id: id,
method: 'delete',
forceFormData: true
})
}
}
Finally in the template:
<template #cell(actions)="{item: tax}">
<form method="delete" #submit.prevent="submit(tax.id)">
<input type="hidden" name="_method" value="delete"/>
<button type="submit">Delete</button>
</form>
</template>
Now request reaches to the method. But nothing is deleted. The request sent is DELETE request. Instead of 302 response it sends back 303 (See others).
Community help is appreciated.
Thanks.
I found the solution. The reson behind it was the variable name. In url endpoint the variable name was decleared as dailyrevenue and in the method as $revenue.
You can find your url variable by typing php artisan route:list.
I found that the url variable name must match with variable name in method.
Hope this helps others too.

How to pass params from laravel to ReactJS?

My application uses Lavarel and I have certain ReactJS components. Routing is done by Laravel. For a route /Users/<userid>, if the controller is UserController.php and view is userview.blade.php, how do I get the <userid> from the URL in my react component loaded in a div on userview.blade.php?
You can try out this library from Laracasts which allows you to pass server-side data (string/array/collection) to your JavaScript via a Facade in your Controller.
This may look something like this (haven't tested it, but you get the gist).
public function UserController($userid)
{
JavaScript::put([
'userid' => $userid,
]);
return View::make('yourview');
}
The docs further show how to access it from your view.
https://github.com/laracasts/PHP-Vars-To-Js-Transformer
UserController.php
you can access the userid and send it to view like this:
public function getUser($userid) {
return view('userview')->with('userid', $userid);
}
userview.blade.php
you can grab it (in some input) like this:
<input type="text" value="{{ $userid }}" />
This is, how I understand your problem. If it is not so, kindly correct me!!!

custom validation, method not allowed on error

<form method="post" action="{{action('PLAYERController#update', $ply->reg_no)}}">
{{csrf_field()}}
Getting method not allowed exception on custom validation with false return. Tried mentioning PUT, PATCH and DELETE inside csrf field. Still, does not work.
UPDATE
using post for form method. Using method_field('POST'). not defining get method for the update function. If I go back from the error page back to the form page and press refresh, then the validation message is displayed as it should.
UPDATE 2
Validator::extend('check_sold_amount', function($attribute, $value, $parameters, $validator) {
if(($value%5000)==0)
{
return true;
}
return false;
});
}
UPDATE 3
Controller code
public function update(Request $request, $reg_no)
{
//
$this->validate($request, [
'sold_amount' => 'required|check_sold_amount',
'sold_to_team'=>'required'
]);
$ply = Player::find($reg_no);
$ply->sold_amount = $request->get('sold_amount');
$ply->sold_to_team = $request->get('sold_to_team');
$team_name=$ply->sold_to_team;
$team=Team::find($team_name);
if($ply->category=='indian')
{
$team->indian_players=$team->indian_players+1;
}
else {
$team->foreign_players=$team->foreign_players+1;
}
$team->balance=$team->balance-$ply->sold_amount;
$ply->save();
$team->save();
//return view('player.index');
}
Method not allowed means you do not have a route set up for the request that happened. There are 2 possibilities:
The route for the form submission is not set up
The code you have shown us does not include any method_field(...), so it looks like you are doing a normal POST. So you need a corresponding POST route like:
Route::post('/some/path', 'PLAYERController#update');
The route for the failed validation response is not set up
I'm guessing this is the problem. Say you are on pageX, and you landed here via a POST. You have a post route set up, so that you can land on this page OK. Now from this page, you submit the form you have shown us, but validation fails. When that happens, Laravel does a GET redirect back to pageX. But you have no GET route set up for pageX, so you'll get a Method not allowed.
Along with your POST route for the current page, you need a GET route to handle failed validations.
Also, you say Tried mentioning PUT, PATCH and DELETE inside csrf field - as others pointed out, you should use method_field() to spoof form methods, eg:
<form ...>
{{ csrf_field() }}
{{ method_field('PATCH') }}
Laravel form method spoofing docs
UPDATE
Based on your comments, I think it is actually your initial POST that is failing. Checking your code again, I think your action() syntax is incorrect.
According to the docs, if the method specified in the action() helper takes parameters, they must be specified as an array:
action="{{ action('PLAYERController#update', ['reg_no' => $ply->reg_no]) }}"
If your update route using patch method (example Route::patch('.....');) then add this {{ method_field('PATCH') }} below {{csrf_field()}} in your update form
UPDATE
If you are not using PATCH method for the update route, try this :
Route::patch('player/update/{reg_no}', 'PLAYERController#update')->name('plyupdate');
and then in the form you can do like below :
<form method="POST" action="{{route('plyupdate', $ply->reg_no)}}">
{{csrf_field()}}
{{ method_field('PATCH') }}
//Necessary input fields and the submit button here
</form>
This way always works fine for me. If it still didn't work, maybe there's something wrong in your update method in the controller
UPDATE
Untested, in your update method try this :
public function update(Request $request, $reg_no) {
$input = $request->all();
$ply = Player::find($reg_no);
$validate = Validator::make($input, [
'sold_amount' => 'required|check_sold_amount',
'sold_to_team'=>'required'
]);
if ($validate->fails()) {
return back()->withErrors($validate)->withInput();
}
$ply->sold_amount = $request->get('sold_amount');
$ply->sold_to_team = $request->get('sold_to_team');
$team_name=$ply->sold_to_team;
$team=Team::find($team_name);
if($ply->category=='indian') {
$team->indian_players=$team->indian_players+1;
}
else {
$team->foreign_players=$team->foreign_players+1;
}
$team->balance=$team->balance-$ply->sold_amount;
$ply->save();
$team->save();
return view('player.index');
}
Don't to forget to add use Validator; namespace
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
class UserController extends Controller
{
/**
* Show the profile for the given user.
........................
Did you reference a validation request controller?
Hope this helps :)

Laravel REST Routes with different parameters

I'm building a REST application and I have a doubt about the best practice in case of different routes calling the same controller method.
Example:
Route::post('/company/{id}/people/store', 'PeopleController#store')
Route::post('/people', 'PeopleController#store')
In the first case, I have an extra parameter $company_id to link the person to the company.
Is it correct, or I should use a different method for each route?
Usually, you're storing form data, so just add an extra parameter using hidden input:
<input type="hidden" name="company_id" value="{{ $company->id }}">
Then in the store() method you can get this parameter with:
public function store(Request $request)
{
$companyId = $request->company_id;

Laravel back using {{ URL::previous() }} doesn't work if there are validation errors

I want to make a cancel button on a simple CRUD edit form. However it seems that when there are validation errors the cancel button does not work.
I guess because it routes from controller#edit to controller#update the button just goes to controller#edit again instead of the actual previous page. Is this normal or did I do something wrong? How do I make it work?
attendee/edit.blade.php
<div class=pull-right>
{{Form::submit('Update',array('class'=>'btn btn-success'))}}
<a href = "{{URL::previous()}}" class = 'btn btn-warning'>Cancel</a>
</div>
{{ Form::close() }}
routes.php
Route::get('user/attendees', 'UserController#getAttendees');
Route::resource('attendee', 'AttendeeController');
attendee controller
public function edit($id)
{
$user = Auth::user();
if(empty($user->id))
return Redirect::to('/');
//return if attendee doesn't belong to user
if( !($user->attendee->contains($id)) )
return Redirect::to('user/index')->with( 'error', 'attendee id error.' );
$attendee = Attendee::find($id);
return View::make('attendees.edit', compact('attendee'));
}
/**
* Update the specified attendee in storage.
*
* #param int $id
* #return Response
*/
public function update($id)
{
$attendee = Attendee::findOrFail($id);
$validator = Validator::make($data = Input::all(), Attendee::$rules);
if ($validator->fails())
{
return Redirect::back()->withErrors($validator)->withInput()->with('id', $id);
}
$attendee->update($data);
return Redirect::intended();
}
user controller
public function getAttendees()
{
list($user,$redirect) = $this->user->checkAuthAndRedirect('user');
if($redirect){return $redirect;}
// Show the page
return View::make('site/user/attendees/index', compact('user'));
}
It's actually working correctly, it's just the usage that is incorrect.
Take the following:
You submit a form at GET /attendee/edit/{id}
The form takes you to POST /attendee/edit/{id}
You fail validation and are redirected to GET /attendee/edit/{id}
You cannot link to a page using a method other than GET. Your previous route was actually POST /attendee/edit/{id} but the link will always be GET.
Instead, nominate a page to be redirected to, I usually use the index for the section.
I think you should add a hidden input, like this
{!! Form::hidden('redirect_to', old('redirect_to', URL::previous())) !!}
and use this value in your link:
cancel
Redirect::back() doesn't really accomplish the right thing when using the validator provided by Laravel. What I've done before is pass the page to redirect back to as a hidden input in the form, and simply ignore it using Input::except("return"). Here's what I mean:
// On your HTML Form
<input type="hidden" name="return" value="{{ Request::path() }}" />
// In your PHP Controller
$validator = Validator::make($data = Input::except("return"), Attendee::$rules);
if ($validator->fails())
{
return Redirect::to(Input::get("return"))->withErrors($validator)->withInput()->with('id', $id);
}
Hope that can help shed some light. Other options are returning to a higher up, such as instead of attendee/edit/{id} redirect to attendee/edit/, but it all depends on the structure of you website.
I am now using the browser back via JS in onclick. Seems to work:
<a onclick="window.history.back();">Back</a>
I used this jquery for the cancel button.
$(document).ready(function(){
$('a.back').click(function(){
parent.history.back();
return false;
});
});
May you use the Front-End validation to test the input validation without a need to reload the page. So the {{URL::previous()}} won't affected.
The simple way to do that is by using Ajax or validator.js in your Laravel cade.
Here is a full example how to use jquery ajax in Laravel 5 to test the validation, may help:
http://itsolutionstuff.com/post/laravel-5-ajax-request-validation-exampleexample.html

Resources