I want to direct random link to only one view except that I've define
e.g : localhost:8000/abxcdss
It will go to a view or home page.
Solution #1 - Via Exception Handler (404)
app/Exceptions/Handler.php
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
//
public function render($request, Exception $exception)
{
if ($exception instanceof NotFoundHttpException) {
return redirect('/');
}
return parent::render($request, $exception);
}
Solution #2 - Via Route
routes/web.php
// Last line!
Route::any('{any}', function () {
return redirect('/');
});
Related
So when a user randomly types a URL on a route that exists, they get an error message:
Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException
The GET method is not supported for this route. Supported methods: POST.
After doing some searching, all the posts I can find suggest to change the render function inside of App\Exceptions\Handler and change it to this:
public function render($request, Exception $exception)
{
if($exception instanceof \Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException){
return abort('404');
}
return parent::render($request, $exception);
}
However, with the newer version of Laravel this no longer exists. One post mentioned to add this in routes\web.php:
Route::fallback( function () {
abort( 404 );
} );
This works fine but I'm not sure if this is the best approach/right place to have it? Is there are any other alternative way?
I have also attempted to change the register function inside of App\Exceptions\Handler to this per the Laravel Doc (https://laravel.com/docs/9.x/errors#rendering-exceptions):
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
public function register()
{
$this->renderable(function (NotFoundHttpException $e, $request) {
if ($request->is('api/*')) {
return response()->json([
'message' => 'Record not found.'
], 404);
}
});
}
but it does not work
In a newer version on Laravel, you can add
$this->renderable(function (Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException $e) {
// do something
});
this line inside a register method on a class \App\Exceptions\Handler
If you want to handle NotFoundException you should use
$this->renderable(function (Symfony\Component\HttpKernel\Exception\NotFoundHttpException $e) {
// do something
});
You can find more detailed answer on Laravel documentation here:
https://laravel.com/docs/9.x/errors#rendering-exceptions
Info: All my routes look like this /locale/something for example /en/home
works fine.
In my controller I'm using the firstOrFail() function.
When the fail part is triggered the function tries to send me to /home.
Which doesn't work because it needs to be /en/home.
So how can I adjust the firstOrFail() function to send me to /locale/home ?
What needs to changed ?
You can treat it in several ways.
Specific approach
You could surround your query with a try-catch wherever you want to redirect to a specific view every time a record isn't found:
class MyCoolController extends Controller {
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\Redirect;
//
function myCoolFunction() {
try
{
$object = MyModel::where('column', 'value')->firstOrFail();
}
catch (ModelNotFoundException $e)
{
return Redirect::to('my_view');
// you could also:
// return redirect()->route('home');
}
// the rest of your code..
}
}
The only downside of this is that you need to handle this everywhere you want to use the firstOrFail() method.
The global way
As in the comments suggested, you could define it in the Global Exception Handler:
app/Exceptions/Handler.php
# app/Exceptions/Handler.php
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\Redirect;
// some code..
public function render($request, Exception $exception)
{
if ($exception instanceof ModelNotFoundException && ! $request->expectsJson())
{
return Redirect::to('my_view');
}
return parent::render($request, $exception);
}
I have a custom non-Eloquent class called Item. In the constructor, the Item attempts to authenticate with my app. I then have an Auth() method to check whether the authentication was successful, and if not to fire a redirect.
public function Auth() {
if (isset($this->authenticated)) {
return $this;
} else {
return redirect('/auth');
}
}
I use the Auth method to access Item statically via a Item Facade. The intended outcome is that if the Item is authenticated, we proceed to the Index with that Item as a variable. If not the redirect would be triggered.
public function index() {
$item = Item::Auth();
return view('index',$item);
}
However, if not authenticated, all that happens is a Laravel RedirectResponse object is passed to the index view. How can I force that redirect to actually fire?
Solutions I have thought of but don't like
if ($item instanceOf RedirectResponse)... in the controller, but this feels clunky
$item = new Item; if ($item->authenticated)... this is fine for the controller but I want to trigger the redirect from multiple parts of the app so there would be a lot of code re-use which doesn't feel efficient.
Thanks for any help. Either on the Facade front or firing the Redirect object.
You can handle this case by using an AuthenticationException:
public function Auth() {
if (isset($this->authenticated)) {
return $this;
}
throw new AuthenticationException();
}
The authentication exception will generate either a redirect to login or a 401 error on JSON routes. You can of course throw a different exception and handle it as a redirect in your App\Exceptions\Handler class
For example:
public function Auth() {
if (isset($this->authenticated)) {
return $this;
}
throw new ItemNotAuthorizedException(); //Custom class you need to create
}
In Handler.php:
public function render($request, Exception $exception)
{
if ($exception instanceof ItemNotAuthorizedException) {
return redirect("/auth");
}
return parent::render($request, $exception);
}
Note: Laravel 5.6 might also allow exceptions to implement their own render function but you should refer to the documentation for that.
Here's the documentation: https://laravel.com/docs/5.2/routing#route-model-binding
The routes:
Route::group(['prefix' => 'u'], function () {
Route::post('create', ['as' => 'createUser', 'uses' => 'UserController#create']);
Route::get('{uuid}', ['as' => 'userDashboard', 'uses' => 'UserController#dashboard']);
});
The UserController.php:
public function dashboard(User $uuid)
{
return View::make('user.dashboard');
}
Whenever the User isn't found in the database it throws these two exceptions:
2/2
NotFoundHttpException in Handler.php line 103:
No query results for model [App\User].
1/2
ModelNotFoundException in Builder.php line 303:
No query results for model [App\User].
How do I customize the error? I want to redirect to the createUser route. The documentation instructs to pass a Closure as a third argument but I don't know how to do that with my current code.
EDIT 1
This is what I've tried so far without success:
Route::model('{uuid}', ['as' => 'userDashboard', 'uses' => 'UserController#dashboard'], function () {
App::abort(403, 'Test.');
});
Route::get('{uuid}', ['as' => 'userDashboard', 'uses' => 'UserController#dashboard'], function () {
App::abort(403, 'Test.');
});
This is actually very simple. As none of the answers really give a definite answer I am answering it myself.
In the file RouteServiceController.php's boot function add the following:
$router->model('advertiser', 'App\Advertiser', function () {
throw new AdvertiserNotFoundException;
});
Then create a new empty class in App\Exceptions called (in this case) AdvertiserNotFoundException.php:
<?php
namespace App\Exceptions;
use Exception;
class AdvertiserNotFoundException extends Exception
{
}
The last thing to do is to catch the exception in the Handler.php's render function (App\Exception) like so:
public function render($request, Exception $e)
{
switch ($e)
{
case ($e instanceof AdvertiserNotFoundException):
//Implement your behavior here (redirect, etc...)
}
return parent::render($request, $e);
}
That's it! :)
for a similar case i did,
I took the parent Illuminate\Foundation\Exceptions\Handler isHttpException function and copied it to app/Exceptions/Handler.php and changed it's name to my isUserNotFoundException.
protected function isUserNotFoundException(Exception $e)
{
return $e instanceof UserNotFoundException;
}
and than in the render function add
if ($this->isUserNotFoundException($e))
return redirect('path')->with('error',"Your error message goes here");
Following code must be placed in your RouteServiceProvider::boot method
$router->model('uuid', 'App\User', function () {
throw new UserNotFoundException;
});
and make sure to include this in your view file
and this forum post might help you
https://scotch.io/tutorials/creating-a-laravel-404-page-using-custom-exception-handlers
To do so you need to check if the id exist in the model like so:
public function dashboard(User $uuid)
{
if(User::find($uuid))
{
return View::make('user.dashboard');
} else {
redirect('xyz');
}
}
I think this tutorial will be helpful for you Laravel Model Binding
You could add the exception and treat in in app/Exceptions/Handler.php
/**
* 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)
{
if (!env('APP_DEBUG')) {
if ($e instanceof \Illuminate\Database\Eloquent\ModelNotFoundException) {
//treat error
return response()->view('errors.404');
}
return parent::render($request, $e);
}
Edit 1:
This piece of code is from a working project so if this doesn't work it must have an error somewhere else:
if ($e instanceof \Illuminate\Database\Eloquent\ModelNotFoundException) {
$data= \App\Data::orderBy('order', 'asc')->get();
return response()->view('errors.404', [
'data' => $data
], 404);
}
Edit 2:
You can use the above code and this tutorial in order to create a new Exception type in order to get your desired behavior. To my understanding at least. :)
Hi I'm new to laravel and working with custom exception handling.
I have caught all exceptions known to my knowledge and it is working fine. As per my understanding, set_exception_handler is used for handling uncaught exceptions. Now I have two questions:
1) I have to know whether my understanding for set_exception_handler is correct or not.
2) How to implement it in laravel 5 to handle uncaught exceptions
This is how I have implemented set_exception_handler in my controller
class SearchController extends BaseController{
public function getTitleMessage($exc){
var_dump("set exception handler".$exc);
return json_encode("Error");
}
public function genericSearch(){
//Bussiness logic goes here
set_exception_handler('getTitleMessage');
throw new Exception("Search Failed");
}
This is showing an error that set_exception_handler is not a valid callback. So I have changed my code to
set_exception_handler(array($this,'getTitleMessage'));
But also not working for me. Someone guide me how to implement it in laravel controller. Thanks in advance
Laravel already uses a global exception handler
Take a look at the vendor\laravel\framework\src\Illuminate\Foundation\Bootstrap\HandleExceptions.php file; as you see in the bootstrap method, Laravel already uses set_exception_handler to set the handleException method as the global exception handler
That method will ultimately call App\Exceptions\Handler::render when an uncaught exception is raised.
So, if you want to handle in some way an exception that you're not catching manually, all you have to do is add your code to the render method:
app\Exceptions\Handler.php
public function render($request, Exception $e)
{
//DO WATHEVER YOU WANT WITH $e
return parent::render($request, $e);
}
You've to implement your custom exception handler logic in the app\Exceptions\Handler.php render method:
public function render($request, Exception $exception) {
if (method_exists($e, 'render') && $response = $e->render($request)){
return Router::prepareResponse($request, $response);
} elseif ($e instanceof Responsable) {
return $e->toResponse($request);
}
$e = $this->prepareException($e);
/* Your custom logic */
if ($e instanceof HttpResponseException) {
return $e->getResponse();
} elseif ($e instanceof AuthenticationException) {
return $this->unauthenticated($request, $e);
} elseif ($e instanceof ValidationException) {
return $this->convertValidationExceptionToResponse($e, $request);
}
return parent::render($request, $exception);
}