I am new in Laravel, what I try to achieve is very simple thing, I would like to use FormRequest provided by Laravel to do validation of the request, but I encounter some puzzles (which I am sure is easy things to solve if you are experienced in Laravel).
Here is what I tried:
I have route maps to controller:
Route::put('user/{name}', 'UserController#show');
I can get the name parameter in show function:
class UserController {
public function show($name)
{
// validtion rules to apply
...
}
}
I have validation rules to apply to the request, so I decided to create form request by php artisan make:request ShowRequest, which creates the form request class:
class ShowRequest extends FormRequest {
public function authorize()
{
return true;
}
public function rules()
{
return [
// my validation rules here
];
}
}
Since I have above request class, so I refactored the show function in controller to receive the ShowRequest .
class UserController {
public function show(ShowRequest $request)
{
// now I don't need validtion rules in this function
// but how can I access the 'name' parameter now
...
}
}
I have two questions to ask:
Inside the refactored show function, how can I now access the route parameter name ?
If we forget about the parameter is a name (please don't focus on what to validate for name, imaging it is an object or value to validate in general). How to add custom logic for handling validation error instead of using Laravel default behaviour. I want to inject code like dummy code below:
if (!$validator->pass())
{
//my custom code for handling validation failure
}
Where to put my custom code for handling validation error now? I mean I don't know where to have this logic, in controller? in the request class? how?
You still can add the parameter $name in the show() method of your controller as it's part of the routed url more than the validated form/data. (recommanded)
class UserController {
public function show(ShowRequest $request, $name)
{
//...
}
}
You can also access it from the request object
class UserController {
public function show(ShowRequest $request)
{
$request->input('name');
}
}
As for the error messages (not the exception) you can add the messages() method to your ShowRequest::class
class ShowRequest extends FormRequest
{
/**
* #return array
*/
public function messages()
{
return [
'name.required' => 'The name is required',
'name.numeric' => 'The name must be a number',
//...
];
}
}
If you instead need to validate that the name catched by the route is only composed of letter OR really exists as a field in your DB (like a slug of a post) you need to add some validation in your route declaration.
Setup a route that catches request only if it is composed of letters.
Route::get('/user/{name}', 'Controller#show')->where(['name' => '[a-z]+']);
Setup a route that catches request only if the "name" exists in DB:
User.php
Class User //..
{
/**
* Get the route key for the model.
*
* #return string
*/
public function getRouteKeyName()
{
return 'name';
}
}
web.php
//
Route::get('/user/{user:name}', 'Controller#show');
And adapt your controller to take a user directly
class UserController {
public function show(ShowRequest $request, User $user)
{
//...
}
}
You can access the values of the Form Request using this
$validated = $request->validated();
The $validated will have all the values which had been validated by the FormRequest.
To answer your second question, if you want to throw custom validation, you can always use the following
throw ValidationException::withMessages(['name' => 'Something is wrong']);
Trying to play with Laravel today for the first time. I am getting the following error when I attempt to visit localhost/project/public:
InvalidArgumentException
Route [login] not defined.
app/routes.php:
<?php
Route::get('/', 'HomeController#redirect');
Route::get('login', 'LoginController#show');
Route::post('login', 'LoginController#do');
Route::get('dashboard', 'DashboardController#show');
app/controllers/HomeController.php:
<?php
class HomeController extends Controller {
public function redirect()
{
if (Auth::check())
return Redirect::route('dashboard');
return Redirect::route('login');
}
}
app/controllers/LoginContoller.php:
<?php
class LoginController extends Controller {
public function show()
{
if (Auth::check())
return Redirect::route('dashboard');
return View::make('login');
}
public function do()
{
// do login
}
}
app/controllers/DashboardController.php:
<?php
class DashboardController extends Controller {
public function show()
{
if (Auth::guest())
return Redirect::route('login');
return View::make('dashboard');
}
}
Why am I getting this error?
Try to add this at Header of your request: Accept=application/json postman or insomnia add header
You're trying to redirect to a named route whose name is login, but you have no routes with that name:
Route::post('login', [ 'as' => 'login', 'uses' => 'LoginController#do']);
The 'as' portion of the second parameter defines the name of the route. The first string parameter defines its route.
In app\Exceptions\Handler.php
protected function unauthenticated($request, AuthenticationException $exception)
{
if ($request->expectsJson()) {
return response()->json(['error' => 'Unauthenticated.'], 401);
}
return redirect()->guest(route('auth.login'));
}
Laravel has introduced Named Routes in Laravel 4.2.
WHAT IS NAMED ROUTES?
Named Routes allows you to give names to your router path. Hence using the name we can call the routes in required file.
HOW TO CREATE NAMED ROUTES?
Named Routes created in two different way : as and name()
METHOD 1:
Route::get('about',array('as'=>'about-as',function()
{
return view('about');
}
));
METHOD 2:
Route::get('about',function()
{
return view('about');
})->name('about-as');
How we use in views?
about-as
Hence laravel 'middleware'=>'auth' has already predefined for redirect as login page if user has not yet logged in.Hence we should use as keyword
Route::get('login',array('as'=>'login',function(){
return view('login');
}));
You need to add the following line to your web.php routes file:
Auth::routes();
In case you have custom auth routes, make sure you /login route has 'as' => 'login'
In case of API , or let say while implementing JWT . JWT middleware throws this exception when it couldn't find the token and will try to redirect to the log in route.
Since it couldn't find any log in route specified it throws this exception .
You can change the route in "app\Exceptions\Handler.php"
use Illuminate\Auth\AuthenticationException;
protected function unauthenticated($request, AuthenticationException $exception){
return $request->expectsJson()
? response()->json(['message' => $exception->getMessage()], 401)
: redirect()->guest(route('ROUTENAME'));
}
Am late to the party. if your expectation is some sort of json returned other than being redirected, then edit the exception handler so do just that.
Go to go to App\Exceptions\Handler.php
Then edit this code:
public function render($request, Exception $exception)
{
return parent::render($request, $exception);
}
to
public function render($request, Exception $exception)
{
return response()->json(
[
'errors' => [
'status' => 401,
'message' => 'Unauthenticated',
]
], 401
);
}
Try this method:
look for this file
"RedirectifAuthenticated.php"
update the following as you would prefer
if (Auth::guard($guard)->check()) {
return redirect('/');
}
$guard as an arg will take in the name of the custom guard you have set eg. "admin" then it should be like this.
if (Auth::guard('admin')->check()) {
return redirect('/admin/dashboard');
}else{
return redirect('/admin/login');
}
I ran into this error recently after using Laravel's built-in authentication routing using php artisan make:auth. When you run that command, these new routes are added to your web.php file:
Auth::routes();
Route::get('/home', 'HomeController#index')->name('home');
I must have accidentally deleted these routes. Running php artisan make:auth again restored the routes and solved the problem. I'm running Laravel 5.5.28.
Route::get('/login', function () {
return view('login');})->name('login');
Name your login route if using your own custom auth system.
Route::post('login', 'LoginController#login')->name('login')
works very well and it is clean and self-explanatory
Laravel ^5.7
The Authenticate Middleware
Laravel ^5.7 includes new middleware to handle and redirect unauthenticated users.
It works well with "web" guard... of course the "login" route (or whatever you name your login route) should be defined in web.php.
the problem is when your are using custom guard. Different guard would redirect unauthenticated users to different route.
here's a quick workaround based on John's response (it works for me).
app/Http/Middleware/Authenticate.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
class Authenticate extends Middleware
{
/**
* #var array
*/
protected $guards = [];
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param string[] ...$guards
* #return mixed
*
* #throws \Illuminate\Auth\AuthenticationException
*/
public function handle($request, Closure $next, ...$guards)
{
$this->guards = $guards;
return parent::handle($request, $next, ...$guards);
}
/**
* Get the path the user should be redirected to when they are not authenticated.
*
* #param \Illuminate\Http\Request $request
* #return string
*/
protected function redirectTo($request)
{
if (! $request->expectsJson()) {
if (in_array('admin', $this->guards)) {
return route('admin.login');
}
return route('login');
}
}
}
Source : Issue #26292
Replace in your views (blade files) all
{{route('/')}} ----- by ----> {{url('/')}}
If someone getting this from a rest client (ex. Postman) - You need to set the Header to Accept application/json.
To do this on postman, click on the Headers tab, and add a new key 'Accept' and type the value 'application/json'.
**Adding this for the future me.**
I encountered this because I was reusing Laravel's "HomeController", and adding my custom functions to it. Note that this controller calls the auth middleware in its __construct() method as shown below, which means that all functions must be authenticated. No wonder it tries to take you to login page first. So, if you are not using Laravel's authentication scafffolding, you will be in a mess. Disable the constructor, or do as you seem fit, now that you know what is happening.
public function __construct()
{
$this->middleware('auth');
}
//In Laravel 8
Route::post('login', [LoginController::class, 'do'])->name('login');
If using passport as api do:
routes/web.php:
Route::get('login', function() {
return response()->json(['message' => 'Unauthorized.'], 401);
});
Route::post('login', [ 'as' => 'login']);
For Laravel 8 I face the problem while access home url after creating login register system
First there is no route exists with the name login
Just add a route name like this
for single method like
Route::post('put url here',[Your Controller::class,'method name'])->name('login');
for multiple method like
Route::match(['get','post'],'put url here',[Your Controller::class,'method name'])->name('login');
Route must be valid, should give route name.
Route::group([
'prefix' => 'v1'
], function () {
Route::post('/login', [userController::class, 'loginAction'])->name('login');
});
I have created a simple function in App\Traits\Validate.
This function simply validates image as seen.
public function validate_image($request)
{
$check = true;
$validate = $this->validate($request, [
'image' => 'image|mimes:jpeg,png,jpg|max:2048',
]);
dd($validate);
if($validate->fails())
{
$check = false;
}
return $check;
}
Now when I access this function in Controller through
$check_image = $this->validate_image($request);
I am passing the whole request variable. But still in validate_image function I am getting null. What is that I am missing? I have other functions in Validate trait and those are working fine, but this function returning null value. Please help
And yess image is the name of the file field in form
I don't know why but try this...
first add
use Validator;
Now that you are sending $request I believe you it in array before passing to Validator
This
$data[] = $request->files;
$validate = Validator::make($data, [
'image' => 'image|mimes:jpeg,png,jpg|max:2048',
]);
Now dd() this. Hope it works.
first of all make sure that your form can send files.
<form method="POST" action="" enctype="multipart/form-data">
{!! Form::open([
'route' => '',
'method' => 'POST',
'files' => true
]) !!}
also create custom request. Do you really need validation in controller?
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class CustomRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'image' => 'image|mimes:jpeg,png,jpg|max:2048',
];
}
}
Ensure that from your form you are able to handle images.
Ensure that in your opening clause you have added:
enctype="multipart/form-data"
I'm making a real estate application. When the user opens one of his published properties to edit, in the edit page, the form opens like this:
{!! Form::model($property, ['method'=>'PUT', 'route'=>['property.update', 'id'=>$property->id], 'files'=>true]) !!}
As you can see, in the 'route' array I'm sending the named route and the id of the property to be edited. But how do I access that $id in the Request Class?
class EditPropertyRequest extends Request
{
/**
* Determine if the user owns this property and is authorized to make this request.
*
* #return bool
*/
public function authorize($id)
{
return Property::where('user_id', auth()->user()->id)
->where('id', $id)
->exists();
}
}
The error I get is
Missing argument 1 for
App\Http\Requests\EditPropertyRequest::authorize()
This is from doc
public function authorize()
{
$commentId = $this->route('comment');
return Comment::where('id', $commentId)
->where('user_id', Auth::id())->exists();
}
So $this->route('comment'); is a URL parameter Route::post('comment/{comment}');
request('id')
You can use request();
I'm folowing a tutorial on https://laracasts.com/series/laravel-5-fundamentals
then I started digging into nested controllers from this tutorial https://www.flynsarmy.com/2015/02/creating-a-basic-todo-application-in-laravel-5-part-4/
I've got a similar logic Project which has one hypothesis.
So I've setup my nested routes
Route::resource('project','ProjectsController');
Route::resource('project.hypothesis','HypothesisController');
Then created a form for adding a hypothesis to a Project
{!! Form::model(new App\Hypothesis, ['route' => ['project.hypothesis.store', $project->id]]) !!}
#include ('hypothesis.form',['submitButtonText'=>'create']);
{!! Form::close() !!}
I also created a HyphothesisRequest class with basic validation rules
<?php namespace App\Http\Requests;
use App\Http\Requests\Request;
class HyphothesisRequest extends Request {
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return false;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'description' =>'required'
];
}
}
Now according to the above tutorials in my controller i've got
public function store(Project $project, HyphothesisRequest $request)
{
$this->validate($request);
$h = new Hypothesis;
$h->description = $request->description;
$h->project_id = $project->id;
$h->save();
return Redirect::route('project.show', $project->id);
}
The problem is that when the HyphothesisRequest $request is passed as an argument I get an forbidden page from laravel. When I remove this it goes to the desired page but without validation.
I'm at the basic level of this so please be patient :)
Try change
public function authorize()
{
return false;
}
to
public function authorize()
{
return true;
}