I'm trying to update Laravel from version 5.1 to 5.2 in my project, I have followed this upgrade guide from the documentation, but now I'm getting this HttpResponseException when a validation fails
* Handle a failed validation attempt.
*
* #param \Illuminate\Contracts\Validation\Validator $validator
* #return mixed
*
* #throws \Illuminate\Http\Exception\HttpResponseException
*/
protected function failedValidation(Validator $validator)
{
throw new HttpResponseException($this->response(
$this->formatErrors($validator)
));
}
In 5.1, the framework redirected to the previous url automatically with the validation errors.
This is my validation request
namespace domain\funcao\formRequest;
use autodoc\Http\Requests\Request;
class StoreFuncaoRequest extends Request
{
/**
* 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 [
'codigo' => 'required|max:255|unique:funcao,codigo,'.$this->input('id').',id,deleted_at,NULL',
'nome' => 'required|max:255|unique:funcao,nome,'.$this->input('id').',id,deleted_at,NULL'
];
}
}
I have already updated my Exceptions Handler according to the guide
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that should not be reported.
*
* #var array
*/
protected $dontReport = [
\Illuminate\Auth\Access\AuthorizationException\AuthorizationException::class,
\Illuminate\Database\Eloquent\ModelNotFoundException::class,
\Illuminate\Foundation\ValidationException\ValidationException::class,
\Symfony\Component\HttpKernel\Exception\HttpException::class,
];
...
}
Did someone had this problem??
I found the cause for this error, I was calling PrettyPageHandler from Whoops manually in my Exception Handler class.
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that should not be reported.
*
* #var array
*/
protected $dontReport = [
\Illuminate\Auth\Access\AuthorizationException\AuthorizationException::class,
\Illuminate\Database\Eloquent\ModelNotFoundException::class,
\Illuminate\Foundation\ValidationException\ValidationException::class,
\Symfony\Component\HttpKernel\Exception\HttpException::class,
];
...
/**
* Render an exception into an HTTP response.
*
* #param \Illuminate\Http\Request $request
* #param \Exception $e
* #return \Illuminate\Http\Response
*/
public function render($request, Exception $e)
{
// I just needed to remove this call to get rid of the problem
if (config('app.debug'))
{
return $this->renderExceptionWithWhoops($e);
}
return parent::render($request, $e);
}
/**
* Render an exception using Whoops.
*
* #param \Exception $e
* #return \Illuminate\Http\Response
*/
protected function renderExceptionWithWhoops(Exception $e)
{
$whoops = new \Whoops\Run;
$whoops->pushHandler(new \Whoops\Handler\PrettyPageHandler());
return new \Illuminate\Http\Response(
$whoops->handleException($e),
$e->getStatusCode(),
$e->getHeaders()
);
}
}
I'm still using Whoops, but now automatically through Laravel Exceptions
This was the first question I came across when I had this problem although for me it was with Sentry not Whoops.
Here's a couple of exceptions and how I dealt with them:
public function render($request, Exception $e)
{
if ($e instanceof TokenMismatchException) {
return redirect()->back()->withInput()->with('error', 'Your Session has Expired');
}
if ($e instanceof HttpResponseException) {
return $e->getResponse();
}
return response()->view('errors.500', [
'sentryID' => $this->sentryID,
], 500);
}
I handle the HttpResponseException by simply returning the response the same way the ExceptionHandler class does.
All you have to do is, just write your business logics inside the protected failedValidation() inside your custom FormRequest class like follows
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Contracts\Validation\Validator;
/**
* [failedValidation [Overriding the event validator for custom error response]]
* #param Validator $validator [description]
* #return [object][object of various validation errors]
*/
public function failedValidation(Validator $validator) {
// write your business logic here otherwise it will give same old JSON response
throw new HttpResponseException(response()->json($validator->errors(), 422));
}
Related
I have Authenticate middleware in my Lumen app that looks like this:
class Authenticate
{
public function handle(Request $request, Closure $next, string|null $guard = null): mixed
{
try {
/** #var \Illuminate\Auth\RequestGuard $requestGuard */
$requestGuard = $this->auth->guard($guard);
$signedIn = $requestGuard->check();
// ...
} catch (NoUserIdProvidedException) {
// ...
}
// ...
}
}
It works fine, but PhpStorm reports that the exceptions (I removed most from the example, there are a few) are not thrown by the containing block, when they are.
Seems that deep in the RequestGuard it uses call_user_func
return $this->user = call_user_func(
$this->callback, $this->request, $this->getProvider()
);
To call a closure set up in the AuthServiceProvider, which uses the middleware method on the custom Security class:
class AuthServiceProvider extends ServiceProvider
{
public function boot(): void
{
$this->app['auth']->viaRequest('api', function ($request) {
$security = new Security();
return $security->middleware($request);
});
}
}
The middleware looks to me docblocked correctly
/**
* #param Request $request
* #return bool|object|null
* #throws InvalidDomainUser
* #throws NoDomainUserException
* #throws NoTokenOnRecordException
* #throws NoTokenProvidedException
* #throws NoUserException
* #throws NoUserIdProvidedException
*/
public function middleware(Request $request): object|bool|null
{
adding the docblocks, like:
/**
* #throws NoUserIdProvidedException
*/
in the closure, the auth provider or the handle code does not make the warning go away, is there a way to comment or type hint the code to avoid false positives? I don't want to just switch off the inspection.
It seems that the way the guards work is just a bit too convoluted for static analysis, so I refactored, moving the underlying custom code out of the guard, and directly into the middleware and this worked, the exceptions are now correctly detected.
class Authenticate
{
public function handle(Request $request, Closure $next, string|null $guard = null): mixed
{
try {
$security = new Security();
$user = $security->middleware($request);
$signedIn = !empty($user->id);
// ...
} catch (NoUserIdProvidedException) {
// ...
}
// ...
}
}
The security class is custom logic, the important bit is that the doc blocks with the #throws are close enough to be found by the IDE
class Security{
/**
* #param Request $request
* #return bool|object|null
* #throws InvalidDomainUser
* #throws NoDomainUserException
* #throws NoTokenOnRecordException
* #throws NoTokenProvidedException
* #throws NoUserException
* #throws NoUserIdProvidedException
*/
public function middleware(Request $request): object|bool|null
{
// ....
}
}
I want to redirect my post route to error page if the request is not made with post but with get method. But i am getting the error "The GET method is not supported for this route. Supported methods: POST."
My route file
Route::get('/user/create',[UserController::class, 'create'])->name('user.create');
Route::post('/user',[UserController::class, 'store'])->name('user.store');
Into my controller i have used
public function store(Request $request){
if($request->isMethod('POST')){
dd($request->all());
}else{
return abort(404);
}
}
So when the route is Route::post('/user',[UserController::class, 'store'])->name('user.store'); for submitting the data by post method the url is http://127.0.0.1:8000/admin/user ok i dont have any problem with that, but when i do hit into my urlbar http://127.0.0.1:8000/admin/user with get method i get the above error but i dont want to show that rather it should get redirected to error page.
It's the logic to get a bad method error when someone is requesting a bad method but you can do something like this:
routes file:
Route::any('/user',[UserController::class, 'store'])->name('user.store');
and in controller:
public function store(Request $request){
if(! $request->isMethod('POST')){
return abort(404);
}
// and the rest of your code for the post request.
}
In case you don't want to edit the routes you can replace the exception.
in app/Exceptions/Handler.php add render method:
<?php
namespace App\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Throwable;
class Handler extends ExceptionHandler
{
/**
* A list of exception types with their corresponding custom log levels.
*
* #var array<class-string<\Throwable>, \Psr\Log\LogLevel::*>
*/
protected $levels = [
//
];
/**
* A list of the exception types that are not reported.
*
* #var array<int, class-string<\Throwable>>
*/
protected $dontReport = [
//
];
/**
* A list of the inputs that are never flashed for validation exceptions.
*
* #var array<int, string>
*/
protected $dontFlash = [
'current_password',
'password',
'password_confirmation',
];
/**
* Register the exception handling callbacks for the application.
*
* #return void
*/
public function register()
{
$this->reportable(function (Throwable $e) {
//
});
}
/**
* Render an exception into an HTTP response.
*
* #param \Illuminate\Http\Request $request
* #param \Throwable $e
* #return \Symfony\Component\HttpFoundation\Response
*
* #throws \Throwable
*/
public function render($request, Throwable $e)
{
if ($e instanceof MethodNotAllowedHttpException) {
return abort(404);
}
return parent::render($request, $e);
}
}
I am beginner to laravel. I came across one laravel application. In that I need to handle all types of exceptions/ errors that are getting. Exceptions like ViewExceptions, ErrorExceptions etc. I need to show one view page(site under maintenance) for all those system exceptions, errors and for all database or coding exceptions and errors.
I have checked Laravel Error handling and also googled for solutions. But more I searched I am getting confused for solution. As the application is already on production, I can't make changes to each controller to handle the exceptions. I am guessing, I need to make changes in App/Exception/Handler class only but not sure how that will work.
Form search I got that I have to make changes like in Handler class:
/**
* Render an exception into an HTTP response.
*
* #param \Illuminate\Http\Request $request
* #param \Throwable $exception
* #return \Illuminate\Http\Response
*/
public function render($request, Throwable $exception)
{
if ($exception instanceof CustomException) {
return response()->view('errors.site_down', [], 500);
}
return parent::render($request, $exception);
}
Above code not showing if there is ViewException.
I have observed that in .env APP_DEBUG is true and in config/app it's false. Does that affect?
How all exceptions or errors will redirect to site_down page? also please guide me exception and error handling in laravel. I am getting more confused.
Thanks in advance.
Just get rid of the if statement:
/**
* Render an exception into an HTTP response.
*
* #param \Illuminate\Http\Request $request
* #param \Throwable $exception
* #return \Illuminate\Http\Response
*/
public function render($request, Throwable $exception)
{
return response()->view('errors.site_down', [], 503);
}
You will also probably want to return 503, if you are trying to claim the site is down for maintenance.
In critique of this approach, I think it is dishonest and transparent to your users to claim the site is in maintenance for your errors, and this will not pay itself off in the long run.
Add a blade page on resources/views/errors/503.blade.php
You may publish Laravel's error page templates using the vendor:publish Artisan command. Once the templates have been published, you may customize them to your liking :
php artisan vendor:publish --tag=laravel-errors
This command will create all your custom error page on resources/views/errors/ directory. You can customize as you want.
See official documentation here
For custom exceptions first you have to make a custom exception file preferably in the exceptions folder App\Exceptions\CustomException.php
<?php
namespace App\Exceptions;
use Exception;
class CustomException extends Exception
{
//
}
Then in your exceptions handler file App\Exceptions\Handler.php
<?php
namespace App\Exceptions;
use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use App\Exceptions\CustomException as CustomException;
use Throwable;
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that are not reported.
*
* #var array
*/
protected $dontReport = [
//
];
/**
* A list of the inputs that are never flashed for validation exceptions.
*
* #var array
*/
protected $dontFlash = [
'password',
'password_confirmation',
];
/**
* Report or log an exception.
*
* #param \Throwable $exception
* #return void
*/
public function report(Throwable $exception)
{
parent::report($exception);
}
/**
* Render an exception into an HTTP response.
*
* #param \Illuminate\Http\Request $request
* #param \Throwable $exception
* #return \Illuminate\Http\Response
*/
public function render($request, Throwable $exception)
{
// Thrown when a custom exception occurs.
if ($exception instanceof CustomException) {
return response()->view('error.page.path', [], 500);
}
// Thrown when an exception occurs.
if ($exception instanceof Exception) {
response()->view('errors.page.path', [], 500);
}
return parent::render($request, $exception);
}
}
Remember to use App\Exceptions\CustomException; custom exceptions file where ever you need to throw a custom exception like so:
use App\Exceptions\CustomException;
function test(){
throw new CustomException('This is an error');
}
My final goal is to use data from the database to display on the 404 page.
I have added the following code to my Handler.php in render method:
if ($this->isHttpException($exception)) {
if ($exception->getStatusCode() == 404) {
return response()->view('errors.' . '404', [], 404);
}
}
Content of errors.404.blade.php is only "test".
I have checked the name of the PagesController file, and it is capitalized as it should. I've also tried to empty the cache with Artisan::call('route:clear');, Artisan::call('cache:clear');, Artisan::call('cache:clear');, and Artisan::call('view:clear'); (I don't have access to the terminal directly).
Any help is appreciated.
Thanks.
Edit: This is the full handler file:
<?php
namespace App\Exceptions;
use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Support\Facades\App;
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that are not reported.
*
* #var array
*/
protected $dontReport = [
//
];
/**
* A list of the inputs that are never flashed for validation exceptions.
*
* #var array
*/
protected $dontFlash = [
'password',
'password_confirmation',
];
/**
* Report or log an exception.
*
* #param \Exception $exception
* #return void
*
* #throws \Exception
*/
public function report(Exception $exception)
{
parent::report($exception);
}
/**
* Render an exception into an HTTP response.
*
* #param \Illuminate\Http\Request $request
* #param \Exception $exception
* #return \Symfony\Component\HttpFoundation\Response
*
* #throws \Exception
*/
public function render($request, Exception $exception)
{
if ($this->isHttpException($exception)) {
if ($exception->getStatusCode() == 404) {
return response()->view('errors.' . '404', [], 404);
}
}
return parent::render($request, $exception);
}
}
try this code
if ($exception instanceof UnauthorizedException) {
return response()->view('errors.403', [], 403);
}
return parent::render($request, $exception);
I'm using the Form Request classes to validate data being passed into my controllers.
Additionally, I'm using Policies to determine if a current user is allowed to show / update / destroy etc the object in question.
If I am using Policies, does this mean I can simply use:
public function authorize()
{
return true;
}
within my Request classes? Or should I be doing the check twice / writing them in different ways?
If someone could shed some light on this, that would be great.
Thanks.
See \Illuminate\Validation\ValidatesWhenResolvedTrait
<?php
namespace Illuminate\Validation;
use Illuminate\Contracts\Validation\ValidationException;
use Illuminate\Contracts\Validation\UnauthorizedException;
/**
* Provides default implementation of ValidatesWhenResolved contract.
*/
trait ValidatesWhenResolvedTrait
{
/**
* Validate the class instance.
*
* #return void
*/
public function validate()
{
$instance = $this->getValidatorInstance();
if (! $this->passesAuthorization()) {
$this->failedAuthorization();
} elseif (! $instance->passes()) {
$this->failedValidation($instance);
}
}
/**
* Get the validator instance for the request.
*
* #return \Illuminate\Validation\Validator
*/
protected function getValidatorInstance()
{
return $this->validator();
}
/**
* Handle a failed validation attempt.
*
* #param \Illuminate\Validation\Validator $validator
* #return mixed
*/
protected function failedValidation(Validator $validator)
{
throw new ValidationException($validator);
}
/**
* Determine if the request passes the authorization check.
*
* #return bool
*/
protected function passesAuthorization()
{
if (method_exists($this, 'authorize')) {
return $this->authorize();
}
return true;
}
/**
* Handle a failed authorization attempt.
*
* #return mixed
*/
protected function failedAuthorization()
{
throw new UnauthorizedException;
}
}
And \Illuminate\Foundation\Http\FormRequest
/**
* Determine if the request passes the authorization check.
*
* #return bool
*/
protected function passesAuthorization()
{
if (method_exists($this, 'authorize')) {
return $this->container->call([$this, 'authorize']);
}
return false;
}
It only checks the returning result and determine to continue or not when the request is resolved. It doesn't pass the policies or any middleware or sth. strange like that.