Laravel route not calling function of controller after adding auth middleware - php

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.

Related

Laravel update only the changed field attribute(s)

I'm trying to run this update function in my laravel controller. Here my domain name is an unique attribute.
The problem
But now every time when I'm trying to update any field rather than domain name field, it showing me an error saying domain name is already existing. So how can I update only the fields which have been changed? what changes do I need to be made in the following function.
public function update(Request $request,Website $app, $id)
{
$this->validate($request, [
'subDomainName' => ['required'],
'subDomainSuffix' =>['required'],
'packageType'=>['required'],
'themeid'=>['required'],
'lang'=>['required'],
'user'=>['required'],
'domain' => ['required', 'string','min:2', 'max:255','unique:apps'],
],$request->all());
$fullDomain = $request->domain;
$app->domain=$fullDomain;
Website::find($id)->update($request->all());
return redirect()->route('customers.index')
->with('success','Website updated successfully');
}
You can specify a model to be ignored on the unique attribute:
public function update(Request $request, Website $websiteModel, int $id)
{
$website = $websiteModel->find($id);
$this->validate($request, [
'subDomainName' => ['required'],
'subDomainSuffix' => ['required'],
'packageType' => ['required'],
'themeid' => ['required'],
'lang' => ['required'],
'user' => ['required'],
'domain' => [
'required',
'string',
'min:2',
'max:255',
Rule::unique('apps')->ignore($website)
],
], $request->all());
$website->update($request->all());
return redirect()
->route('customers.index')
->with('success','Website updated successfully');
}
Don't forget to import Rule: use Illuminate\Validation\Rule;

Return Laravel validation errors as JSON response

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.

Laravel Validator returns MethodNotAllowedHttpException Error

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.

Laravel validation does not work

I used laravel 5.2 to build my app but suddenly validation doesn't work out on registration`new users
Route::post('/register','userController#store');
my function on validation part for storing users details
public function store(Request $request)
{
$this->validate($request,[
'fname' => 'required|max:50',
'lname' => 'required|max:50',
'email' => 'required|email|unique:users',
'phone' => 'required|unique:users',
'provider' => 'required',
'company' => 'required',
'password' => 'required|min:8',
'IDtype' => 'required',
'IDnumber' => 'required',
'region' => 'required|max:32',
'signature' => 'required'
]);
}
Things were working well but now return
"fname":["validation.required"],"lname":["validation.required"],"email":["validation.required"],"IDtype":["validation.required"],"IDnumber":["validation.required"]} returned as response
`
You shoud use $request->all() instead of $request
public function store(Request $request)
{
$this->validate($request->all(),[
........
]);
}
In Laravel 5.5 you can call the validate method on request and it's recommended
$request->validate($rules);

Laravel 5.5 email confirmation and model adjustments

I'm using Laravel 5.5 and I want newly registered users to activate their account by confirming their email address. Also, I need some extra fields or name alterations on the existent Laravel User model. name is replaced by first_name and last_name.
I found out that Laravel manages most parts of the registration in the Auth/RegisterController and so I modified what I needed:
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:12',
'first_name' => 'required|string|min:2',
'last_name' => 'required|string|min:2',
'terms' => 'accepted'
]);
}
The validator works fine, if I change the first_name min:n, it is correctly thereafter validated and shown to the user [the validation errors].
protected function create(array $data)
{
$user = User::create([
'first_name' => $data['first_name'],
'last_name' => $data['last_name'],
'email' => $data['email'],
'status' => 'inactive',
'password' => bcrypt($data['password']),
'api_token' => static::generateApiKey(),
]);
$activationLink = route('account.activation', static::generateRandomString());
Mail::to($user)->send(new UserAccountConfirmationMail($user, $data['password'], $activationLink));
return $user;
}
However, the creation (create(array $data)) does not work at all. I kind of feel like the code is not even executed (tried to add dd or Log::info('...') in order to find out whether or not it at all is executed) and nothing truly happens when I attempt to register. The page is sort of refreshed, however, no message on the user creation (if successful or not, ...), and subsequently no email in my box.
Am I missing out on some crucial detail here?
One of these days that you have spent hours on finding the errors has just finished. The validator, of which I thought was all fine because it was ordinarily displaying the errors, has been the turning point. I forgot to remove name from the validation. However, this validation error was never shown to me since I only caught these errors on display that I truly needed.
Solution:
return Validator::make($data, [
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:12',
'first_name' => 'required|string|min:2',
'last_name' => 'required|string|min:2',
'terms' => 'accepted'
]);

Categories