custom validation, method not allowed on error - laravel

<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 :)

Related

Fail to retrieve Post data with 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??)

The PUT method is not supported for this route

I cannot submit form information through to store function in laravel controller. The form needs to create a - new - profile for a registered user.
I have even recreated the project, and redone the form - moving back into plain html as I suspect that the laravelCollective functions may be causing it but still the same error.
I have even rearranged the the form attributes as suggested in another post/thread.
I have even recreated the project, and redone the form - moving back into plain html as I suspect that the laravelCollective functions may be causing it but still the same error.
I have even rearranged the the form attributes as suggested in another post/thread.
The Form:
< form method="POST" enctype="multipart/form-data" action="{{ url('users/profile') }}" accept-charset="UTF-8" >
#csrf
...
// input fields here
...
< /form >
The Routes:
Route::resource('users/profile', 'ProfileController');
Route::get('/home', 'HomeController#index')->name('home');
Route::resource('users', 'UserController');
Route::post('users/profile', 'ProfileController#store')->name('profile.store');
The ProfileController#store function:
//some code omitted
public function store(Request $request)
{
$this->validate($request, [
'firstname'=>'required',
'lastname'=>'required',
...
'desc'=>'required'
]);
//handle file upload
if($request->hasFile('cover_image')) {
//Get file name with extension
$fileNameWithExt = $request->file('cover_image')->getClientOriginalName();
//Just file name
$fileName = pathinfo($fileNameWithExt, PATHINFO_FILENAME);
//Just Ext
$ext = $request->file('cover_image')->getClientOriginalExtension();
//FileName to Store
$fileNameToStore = $fileName.'_'.time().'_'.$ext;
//upload image
$path = $request->file('cover_image')->storeAs('public/users/'.auth()->user()->id.'cover_images/'.$request->input('firstname').'_'.$request->input('lastname').'_'.auth()->user()->id.'/',$fileNameToStore);
} else {
$fileNameToStore = 'noimage.jpg';
}
/*
*/
$profile = new Profile;
$profile->firstname = $request->input('firstname');
$profile->lastname = $request->input('lastname');
...
$profile->desc = $request->input('desc');
$profile->save();
return redirect('/users/profile');//->with('success','Profile Created');
}
The famous error:
Symfony \ Component \ HttpKernel \ Exception \
MethodNotAllowedHttpException The PUT method is not supported for this
route. Supported methods: GET, HEAD, POST.
Not sure what is causing the error, help appreciated.
If I understand it correctly this is for store function right? then you don't have to put #method('PUT') inside your form it should POST. The route of store in resource is POST.
this is your code that i deleted the #method('PUT')
< form method="POST" enctype="multipart/form-data" action="{{ url('users/profile') }}" accept-charset="UTF-8" >
#csrf ...
// input fields here ...
< /form >
The Routes: Route::resource('users/profile', 'ProfileController');
Route::get('/home', 'HomeController#index')->name('home');
Route::resource('users', 'UserController'); Route::post('users/profile', 'ProfileController#store')->name('profile.store');
and the PUT method is used for updating. When update in controller you need to pass id in your form that should look like this.
< form method="POST" enctype="multipart/form-data" action="{{ url('users/profile', $data->id) }}" accept-charset="UTF-8" >
#method('PUT')
#csrf ...
// input fields here ...
< /form >
I hope it helps!
you have problem in your routes file simply change your edit route to this route
Route::match(['put', 'patch'], 'the path you want /{id}','controllername#functionname');
you should notice that if you are new to laravel you should pass the id to this route as shown in this part {id} so that your edit function could display the previous data of it and also if you want to submit a the form it should have the put method and the html basic forms doesn't support that so you should find a way to submit it like using laravel collective or maybe put a hidden method in your form
if it doesn't work please give me a call
When using the Laravel resource method on a route, it makes things pretty specific in terms of what it is expecting. If you take a look at the chart on the manual, it is looking for a uri with the updating element id returned as part of the uri. The example looks like: /photos/{photo}. I'm not sure that this is how you've structured your html form.
You said you were using the LaravelCollective to get this working. This usually works fine, and has the massive advantage of easy form-model binding. But it helps to include the named route, which includes 'update' for the update resource. For example:
{!! Form::model($yourModel, array('route' => array('yourRoute.update',
$yourModel->id), 'method'=>'PUT', 'id'=>'Form'))!!}
I have not had an issue with the Collective using this method.

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!!!

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

Posting form in Laravel 4.1 and blade template

I'm having trouble posting forms using Laravel 4.1 with the blade template engine. The problem seems to be that the full URL including http:// is being included in the form action attribute. If I hard code the form open html manually and use a relative url, it works OK, however, when it has the full url, I am getting an exception.
routes.php
Route::any("/", 'HomeController#showWelcome');
HomeController.php
public function showWelcome()
{
echo($_SERVER['REQUEST_METHOD']);
return View::make('form');
}
Form opening tag in form.blade.php
{{ Form::open(["url" => "/","method" => "post","autocomplete" => "off"]) }}
{{ Form::label("username", "Username") }}
{{ Form::text("username", Input::old("username"), ["placeholder" => "john.smith"]) }}
{{ Form::label("password", "Password") }}
{{ Form::password("password", ["placeholder" => ""]) }}
{{ Form::submit("login") }}
{{ Form::close() }}
So if I go to my home dir / in the browser, I see the form that I have created. If I fill in the form details and click submit, I am simply taken to the same page - the request method is still GET as shown by echo($_SERVER['REQUEST_METHOD']);
I notice that the full
http://localhost/subdir/public/
url is used in the form markup. If I hardcode a form open tag in such as
<form action="/subdir/public/" method="post">
it works fine and $_SERVER['REQUEST_METHOD'] shows as post.
What am I doing wrong here?
You have created the route for the post?
example:
{{Form::open(["url"=>"/", "autocomplete"=>"off"])}} //No need to later add POST method
in Route.php
Route::post('/', 'YouController#postLogin');
you have not set up a route to handle the POST. You can do that in a couple of ways.
As pointed out above:
Route::post('/', 'HomeController#processLogin');
note that if you stick with your existing Route::any that the `Route::post needs to be before it as Laravel processes them in order (I believe).
You could also handle it in the Controller method showWelcome using:
if (Input::server("REQUEST_METHOD") == "POST") {
... stuff
}
I prefer the seperate routes method. I tend to avoid Route::any and in my login pages use a Route::get and a Route::post to handle the showing and processing of the form respectively.

Resources