I have two form pages which accept POST methods in my routing:
web.php
Route::post('select-room', ['as'=>'select-room','uses'=>'ClientBookingController#selectRoom']);
Route::post('book-room', ['as'=>'book-room','uses'=>'ClientBookingController#bookRoom']);
The functionality works as this. I submit data in page 'select-room' to 'book-room'
There is validation in methods 'selectRoom' and 'bookRoom'
public function selectRoom(Request $request){
$this->validate($request, [
'start_date' => 'required|date|after:yesterday',
'end_date' => 'required|date|after:start_date',
'number_people' => 'required',
'number_kids' => 'required'
]);
}
public function bookRoom(Request $request){
$validator = Validator::make($request->all(), [
'start_date' => 'required|date|after:yesterday',
'end_date' => 'required|date|after:start_date',
'people' => 'required',
'days_staying' => 'required',
'free_days' => 'required',
'room' => 'required|array',
'roomCost' => 'required|array',
'roomPeople' => 'required|array',
'totalCost' => 'required',
'name' => 'required|string|max:255',
'email' => 'required|email|string|max:255|unique:users',
'password' => 'required|string|min:6|max:255|confirmed'
]);
if ($validator->fails())
{
return redirect()->back()->withErrors($validator)->withInput();
}
}
When I submit the data and it does not validate in 'bookRoom' method the validation sends a get request and not a post request to 'select-room' url and I end up with a MethodNotAllowedHttpException Error.
I am still understanding Laravel is it possible that you cannot have a logical flow where you have a post page which then posts to another post page which if fails on the second post page will result in an error because your routing only allows post methods. Is the Validation functionality that restrictive that you must have a get request as a contingency for errors or is there something I may setup which can replicate the post request in the validation response set?
To answer your question your select-room route method should be any() instead of post() then.
But there is something wrong with your flow. You should have a GET route where you are displaying the select. A POST route where you are processing the POST data and go back to the GET route if you have errors.
Any redirects are performed using GET. Your forms should be rendered as GET methods, and the data submitted as a POST request. So make a new URL using get for the book-room.
Route::post('select-room', ['as'=>'select-room','uses'=>'ClientBookingController#selectRoom']);
Route::get('book-room', ['as'=>'book-room','uses'=>'ClientBookingController#showBookRoom']);
Route::post('book-room', ['as'=>'book-room','uses'=>'ClientBookingController#bookRoom']);
And in your controller-
public function selectRoom(Request $request){
$this->validate($request, [
'start_date' => 'required|date|after:yesterday',
'end_date' => 'required|date|after:start_date',
'number_people' => 'required',
'number_kids' => 'required'
]);
// Validate data
// Persist data ready for displaying book-room using get
return redirect('book-room');
}
public function showBookRoom()
{
return //your new view with post data from previous url
}
public function bookRoom(Request $request){
$validator = Validator::make($request->all(), [
'start_date' => 'required|date|after:yesterday',
'end_date' => 'required|date|after:start_date',
'people' => 'required',
'days_staying' => 'required',
'free_days' => 'required',
'room' => 'required|array',
'roomCost' => 'required|array',
'roomPeople' => 'required|array',
'totalCost' => 'required',
'name' => 'required|string|max:255',
'email' => 'required|email|string|max:255|unique:users',
'password' => 'required|string|min:6|max:255|confirmed'
]);
if ($validator->fails())
{
return redirect()->back()->withErrors($validator)->withInput();
}
}
So, whenever your second post fails, it will redirect to the intermediate URL using GET request. Read this post from Laracast, you will have a better understanding.
Related
After adding the auth:api middleware, my route suddenly stops calling the function it is supposed to. When I remove the middleware, it starts working again.
api.php route
Route::middleware('auth:api')->get('/addloancontroller', [\App\Http\Controllers\AddLoan::class, 'store'])
->name('addLoan');
AddLoan.php Controller
<?php
namespace App\Http\Controllers;
use App\Models\EarningsRecord;
use App\Models\Lender;
use App\Models\LoanLenders;
use App\Models\Loans;
use App\Models\Login;
use App\Providers\RouteServiceProvider;
use Illuminate\Http\Request;
use Auth;
use Illuminate\Support\Facades\DB;
class AddLoan extends Controller
{
public function store(Request $request) {
$request->validate([
'amount' => 'required',
'startDate' => 'required',
'endDate' => 'required',
'dateLoanSigned' => 'required',
'interestRate' => 'required',
'interestPaymentPeriod' => 'required',
'interest_only_period' => 'required',
'active' => 'required',
'loanType' => 'required',
'fName' => 'required',
'lName' => 'required',
'earnings' => 'required',
'irdNum' => 'required',
'bankAccNum' => 'required',
'address' => 'required',
'phone' => 'required',
]);
$company_id = $request->user();
dd($company_id);
$loan = Loans::create([
'companies_id' => $company_id,
'amount' => $request->amount,
'startDate' => $request->startDate,
'endDate' => $request->endDate,
'dateCreated' => $request->dateLoanSigned,
'interestRate' => $request->interestRate,
'interestPaymentPeriod' => $request->interestPaymentPeriod,
'interestOnlyPeriod' => $request->interestOnlyPeriod,
'active' => $request->active,
'refinanced' => 0,
'loanType' => $request->loanType
]);
$loan->save();
$lender = Lender::create([
'fName' => $request->fName,
'lName' => $request->lName,
'annualEarnings' => $request->earnings,
'irdNum' => $request->irdNum,
'bankAccNum' => $request-> bankAccNum,
'address' => $request-> address,
'phone' => $request->phone,
'loginID' => null
]);
$lender->save();
$taxAmount = DB::table('tax_rates')
->where('minAmount', '<', $request->earnings)
->where('maxAmount', '>', $request->earnings);
$loanLender = LoanLenders::create([
'loansID' => $loan->id,
'lenderID' => $lender->id,
'companyID' => $company_id,
'taxAmount' => $taxAmount->id
]);
$loanLender->save();
$earningsReport = EarningsRecord::create([
'lenderID' => $lender->id,
'annualEarnings' => $lender->annualEarnings,
'dateRecorded' => date('d-m-Y')
]);
$earningsReport->save();
return redirect(RouteServiceProvider::HOME);
}
}
The route is called as a action in a form:
<form method="GET" action="{{ route('addLoan') }}">
The reason all of my validation is just looking for 'required' is because I wanted to make sure it wasn't validation failing and just not producing a error.
What happens when I submit the form?
When I submit the form and the route has the middleware attached to it, it simply redirects me back to the home screen.
Cache
I have already run:
php artisan cache:clear
composer dump-autoload
Authentication Token
As explained in the laravel documentation, I have already added the api_token column to the migration file for the User (in my case, I use the Login model for authentication). Below is the line in the migration file where I add that column:
$table->string('api_token', 80)->unique()->nullable()->default(null);
This is the line in the documentation:
Schema::table('users', function ($table) {
$table->string('api_token', 80)->after('password')
->unique()
->nullable()
->default(null);
});
When I create the model object, I make the authenticated token by doing so:
'api_token' => Str::random(60)
When I check the database, I see that the api_token successfully has been added so I not sure to what the issue could be.
(The documentation link I used is here)
You have defined a route in your api routes file and protected it with the auth:api middleware (which is commonly Passport), yet you are calling the route from an HTML form which is not how you would typically consume an api.
I assume you're just looking to protect routes accessed via web pages within your application, therefore I suggest you research one of the web based authentication mechanisms for Laravel such as Fortify or if you don't want to roll your own views, either Jetstream or Breeze.
Update
Tokens are used in conjunction with an api, the workflow you've currently implemented (a web form) is a web workflow so using api tokens is not recommended.
The Auth facade is available in controller as long as a user is authenticated and works for both the web and api guards.
If you install either Breeze or Jetstream, which I would recommend over Fortify if you're just starting out, you will be able to use the auth middleware to protect your routes requiring users to authenticate themselves (login) in order to access a protected route. This then means that when a user has authenticated and you process a request in your controller Auth::id() will return the id of the authenticated user.
I'm recommended make refactoring your code in the controller, is the first I create FormRequest for your method, and move your validation code and rules in there. In then in FormRequest in method authorize I'm writing code like this:
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return auth('auth:api')->check(); // Method check return false/true.
}
public function rules()
{
return [
'amount' => ['required'],
'startDate' => ['required'],
'endDate' => ['required'],
'dateLoanSigned' => ['required'],
'interestRate' => ['required'],
'interestPaymentPeriod' => ['required'],
'interest_only_period' => ['required'],
'active' => ['required'],
'loanType' => ['required'],
'fName' => ['required'],
'lName' => ['required'],
'earnings' => ['required'],
'irdNum' => ['required'],
'bankAccNum' => ['required'],
'address' => ['required'],
'phone' => ['required']
];
}
also, I'm recommended to change the HTTP method GET to POST.
I am using Laravel 6.
I created a form to insert a meeting and I created a validate method in the controller to check if the data inserted in the db are correct.
Unfortunately when the validate method fails the default redirect back deletes every field that has been compiled by the user.
I tried many times but I am unable to understand how to do in case of failure a redirect back with the previous values filled in by the user.
Controller:
{
$this->validate($request, [
'participants' => [ 'required', new CheckParticipant() ],
'description' => 'required',
'room' => [ 'required', new CheckRoom() ],
'date_meeting' => [ 'required', new CheckDateTime() ],
'start' => [ 'required', new CheckTime() ],
'end' => 'required',
]);
$meeting = new Meeting();
$participants = request('participants');
$meeting->id_participants = implode(';', $participants);
$meeting->description = request('description');
$meeting->id_room = request('room');
$meeting->date = request('date_meeting');
$meeting->start_hour = request('start');
$meeting->end_hour = request('end');
$meeting->save();
$message_correct = "The meeting has been correctly inserted!";
return redirect()->route('home')->with('success', $message_correct);
}
Finally if the user filled in for example the name of a participant to the meeting but the validate method fails I would like that the participant appears already selected in the dropdown menu after the default redirect back.
Is someone able to help me?
In your view, you can use the old function to retrieve data flashed from the previous request.
Instead of calling $this->validate try this:
$validator = Validator::make($request->all(), [
'participants' => [ 'required', new CheckParticipant() ],
'description' => 'required',
'room' => [ 'required', new CheckRoom() ],
'date_meeting' => [ 'required', new CheckDateTime() ],
'start' => [ 'required', new CheckTime() ],
'end' => 'required',
]);
if($validator->fails()) {
return redirect('your/url')
->withErrors($validator)
->withInput();
}
Then, in your view you can access the old inputs with old('yourValue').
I have a form to create a conference and I have some validation rules like below. For example the city is not required but should be a string. The issue is that when the user click in the "Store" button without fill the non required fields it appears the validation errors like:
The city must be a string.
Do you know how to solve that issue? If the value of the form field is "" ignore the rules?
public function store(Request $request)
{
$this->validate($request, [
'name' => 'required|string',
'categories' => 'array|between:1,3',
'city' => 'string',
'zip_code' => 'string',
]);
...
}
you can use nullable if anyone field is non requied field.below you can see the code...
public function store(Request $request)
{
$this->validate($request, [
'name' => 'required|string',
'categories' => 'nullable|array|between:1,3',
'city' => 'nullable|string',
'zip_code' => 'nullable|string',
]);
...
}
In my RegisterController in Laravel I'm having trouble returning the errors to my front-end. Our application is built as a REST API, so the registration of a new user happens through an AJAX post to the registration route. This works fine if the validation passes, but if the validation fails, no errors are shown. It just redirects to a Laravel homepage. We are not using Blade for the front-end, so it's not possible to get the default validation errors from Blade. The front-end is a ReactJS client that communicates with the back-end through AJAX calls.
How do I get a JSON with the fields that didn't pass validation back to my front-end?
protected function validator(array $data)
{
return Validator::make($data, [
'first_name' => 'required|string|max:255',
'last_name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6|confirmed',
'birth_year' => 'required|integer|min:4',
'lat' => 'required|numeric',
'lon' => 'required|numeric',
]);
}
you can solve it by return the errors as json respone
$validator = Validator::make($data, [
'first_name' => 'required|string|max:255',
'last_name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6|confirmed',
'birth_year' => 'required|integer|min:4',
'lat' => 'required|numeric',
'lon' => 'required|numeric',
]);
if ($validator->fails()) {
return response()->json($validator->messages(), 200);
}
Your code is fine, you can catch the errors because laravel will automatically return a JSON response with a 422 HTTP status.
So basically in your ajax use the error function, if the validator fails ajax will automatically execute the code you have in your error from ajax.
For more info on how to properly handle error's for your ajax please take a look at this question. Displaying validation errors in Laravel 5 with React.js and AJAX
I solved the problem by disabling the 'guest' middleware in the RegisterController. I'm not sure if this is a solid solution, but for now it works.
I am pretty new in Laravel and I have the following problem.
I have this method that handle the submit of a form:
public function store(Request $request) {
Log::info('store() START');
$data = Input::all();
Log::info('INSERTED DATA: '.implode("|", $data));
$rules = array(
'name' => 'required',
'surname' => 'required',
'login' => 'required',
'email' => 'required|email',
'emailConfirm' => 'required|email',
'pass' => 'required',
'passlConfirm' => 'required',
'g-recaptcha-response' => 'required|captcha',
);
$validator = Validator::make($data, $rules);
if ($validator->fails()){
return Redirect::to('/registration')->withInput()->withErrors($validator);
}
else{
// Do your stuff.
}
}
As you can see it contains a $rules array containing the validation rules.
It works pretty fine but I want also perform the following 2 checks:
The email field have to contains the same text than the emailConfirm field.
The pass field have to contains the same text than the passConfirm field.
Can I implement this kind of check into the $rules array?
Actually Laravel comes with the validation rule called confirmed. You will need to change your fields to email_confirmation and pass_confirmation and add confirmed rule to email and pass fields.
As answered by #Mariusz, Laravel come up with value comparison rule as confirmed rule. To acheive your output you should write,
$rules = array(
'name' => 'required',
'surname' => 'required',
'login' => 'required',
'email' => 'required|confirmed|email',
'pass' => 'required|confirmed',
'g-recaptcha-response' => 'required|captcha',
);
As you have mentioned, you are using laravelcollective/html, then you have to also add following code to generate confirmation fields
echo Form::email("email_confirmation",null, $attributes = []);
echo Form::password("pass_confirmation",null, $attributes = []);