let's say I have some
Route::get('/path/{model}', 'Controller#method');
In the case of mysite.com/path/1 & no Model#1, I getting 404 which is default Laravel behavior
I want to handle (basically, redirect to another named route) "NoModelFound" for specific group of routes / specific route
As this route exists, Route::fallback or Route::any will not trigger here.
I know there is a Route()->missing method in Laravel 8, but I have Laravel 7 and can't update.
Also, in the best way, I search for solutions within routes ( web.php )
Is any solution for this? thanks in advance
You can globally handle exception in App\Exceptions\Handler class. If you really and i mean really want to be specific about handling ModelNotFoundException for only certain routes then you can do some thing like
// Exception Handle class
public function render($request, Exception $exception)
{
if(
$request->is('*path/') && // or string match
$exception instanceof ModelNotFoundException
){
redirect()->to('where-ever');
}
}
If you just want to redirect user whenever ModelNotFoundException occurs then you could do this,
// Exception Handle class
public function render($request, Exception $exception)
{
if(
$exception instanceof ModelNotFoundException
){
redirect()->to('where-ever');
}
}
Another way would be to use a middleware and check for certain model, if it doesnt exist, then redirect the user. Depends on what you are trying to do. You can find more information here
https://laravel.com/docs/8.x/middleware
https://laravel.com/docs/8.x/errors#the-exception-handler
Related
I am using Laravel 8 and building API's. I have an issue am not able to handle Route Not found exception. I don't know how to handle in laravel 8.
public function register()
{
$this->reportable(function (Throwable $e) {
//
});
}
Kindly help me.
If i type wrong url i face this error
[enter image description here][1]
But i want to display error message in response
[1]: https://i.stack.imgur.com/1qC9h.png
I found a fallback method for Route class in the documentation, it should satisfy what you need without using exceptions.
This is what is written in docs
Using the Route::fallback method, you may define a route that will be executed when no other route matches the incoming request.
Route::fallback(function () {
return abort(404);
// return view('errors.404'); // incase you want to return view
});
There is also the method of extending the render method of exception handler but I guess this satisfies your needs.
Edited:
I have a custom exception with render method which is being called when I throw it e.g. from controller, but not being called when I throw it in View composer.
So when I do something like that
public function compose(View $view)
{
throw new CustomException();
}
and put dd() to exception render method
public function render()
{
dd('render is called');
}
I get no result.
If I log my exception directly, finds out that first the CustomException being thrown, then as the result I see ErrorException.
I found a place where it being thrown.
\Illuminate\View\Engines\CompilerEngine::handleViewException
protected function handleViewException(Exception $e, $obLevel)
{
$e = new ErrorException($this->getMessage($e), 0, 1, $e->getFile(), $e->getLine(), $e);
parent::handleViewException($e, $obLevel);
}
I didn't found any mentions in Laravel docs about that case.
I found a tread on github with the same issue: https://github.com/laravel/framework/issues/24658
So the question is, is this expected? Is there any adequate way to avoid this behaviour?
Edit
So, as you know, any exception during view compilation is intercepted and rethrown as ErrorException or as FatalThrowableError.
What you can do is intercept ErrorException and check if ($e->getPrevious() instanceof \CustomException) if so, you do your code, else, let the handler continue.
So I've found working solution for myself.
I've extended CompilerEngine and added additional processing in order to not throw ErrorException when I don't want to.
The important thing is - your resulting Exception must be inherited from ErrorException. Otherwise you will face multiple calls to \App\View\Engines\CompilerEngine::handleViewException which can break your logic and write multiple log entities to your log file.
Currently have a POST route setup in Laravel
Route::post('/confirm', 'MainController#confirm');
'/confirm' makes use of some POST information sent over from the previous page.
What I am trying to accomplish is, if a user just types in 'index/confirm' into the url and not all of the POST info is present redirect to 'index'
I have the below code and cannot see why this would not work. I think it may be because inorder for the route to trigger at least some POST info needs to be present and if none is then error.
$input = $request->all();
if ( !isset($input) ) {
return redirect('');
}
Error message:
Symfony \ Component \ HttpKernel \ Exception \ MethodNotAllowedHttpException
No message
/Users/&name/Desktop/$filepath/vendor/laravel/framework/src/Illuminate/Routing/RouteCollection.php
protected function methodNotAllowed(array $others)
{
throw new MethodNotAllowedHttpException($others);
}
Commenters answered my question. Needed a seperate route for GET to handle unallowed user submitted url requests.
Route::get('/confirm', 'MainController#index');
That's fine for guarding one endpoint, but there's a more sweeping solution you can apply. Look to your App\Exceptions\Handler class. The render() method is given an awareness of the failed request, and the specific error that was thrown. public function render($request, Exception $e) .... Add this:
if ($e instanceof Symfony\Component\HttpKernel\Exception\NotFoundHttpException) {
return redirect('/index');
}
Just be careful with this. If you typo your redirect URL, you'll end up in an infinite loop. I'd also recommend an additional condition that respects the value of config('app.env') for debugging purposes.
Not sure how this is done in Laravel 5. In 4 you could add in App::error(function(Exception $exception, $code){} block to the routes.php file, and it would serve as a blanket exception handler. I get how it works in Laravel 5 where you add handling for individual exceptions and custom exceptions, which is great - but is there a sort of "Catch all" handling mechanism as well?
You would probably need to have to customize the render() method of App\Exceptions\Handler, as stated here : http://laravel.com/docs/5.0/errors#handling-errors
You can edit the app/Exceptions/Handler.php to do the job :
public function render($request, Exception $e)
{
//Your code here
return view('error');
}
Say you have a simple resource route like this:
Route::resource('overview', 'OverviewController');
And hit routes which you know don't exist. For example:
/overview/sdflkjdsflkjsd
/overview/sdflkjdsflkjsd/edit
Which in my case throws Trying to get property of non-object error from my view (as no resource is found)
I looked into adding 'Regular Expression Parameter Constraints' from the docs, but it looks like these are not available for resource routes either (plus don't really fix the problem).
I'm looking for a way to throw a single exception for this kind of thing, which I can then handle once, rather than add logic to each action (or at least the show and edit actions).. if possible.
EDIT After looking around github, I found the exception in the Symphony repo here. Is there a way I can hook into it?
Since you're getting a Trying to get property of non-object error, I assume you're fetching the resource via YourModel::find();
I'd suggest you use YourModel::findOrFail() instead. Then, you'd be getting a specific type of exception called ModelNotFoundException. Just register an error handler for this.
For instance,
App::error(function(ModelNotFoundException $e)
{
return Response::make('Not Found', 404);
});
UPDATE: This would actually go into render() method inside the app/Exceptions/Handler.php file in Laravel 5.1, and of course the code would utilize the passed $e parameter instead.
public function render($request, Exception $e)
{
if ($e instanceof ModelNotFoundException)
{
return \Response::make('Not Found', 404);
}
return parent::render($request, $e);
}