Using ModelNotFoundException - laravel

I'm starting out in Laravel and want to discover more about using error handling especially the ModelNotFoundException object.
<?php
class MenuController extends BaseController {
function f() {
try {
$menus = Menu::where('parent_id', '>', 100)->firstOrFail();
} catch (ModelNotFoundException $e) {
$message = 'Invalid parent_id.';
return Redirect::to('error')->with('message', $message);
}
return $menus;
}
}
?>
In my model:
<?php
use Illuminate\Database\Eloquent\ModelNotFoundException;
class Menu extends Eloquent {
protected $table = 'categories';
}
?>
Of course for my example there are no records in 'categories' that have a parent_id > 100 this is my unit test. So I'm expecting to do something with ModelNotFoundException.
If I run http://example.co.uk/f in my browser I receive:
Illuminate \ Database \ Eloquent \ ModelNotFoundException
No query results for model [Menu].
the laravel error page - which is expected, but how do I redirect to my route 'error' with the pre-defined message? i.e.
<?php
// error.blade.php
{{ $message }}
?>
If you could give me an example.

In Laravel by default there is an error handler declared in app/start/global.php which looks something like this:
App::error(function(Exception $exception, $code) {
Log::error($exception);
});
This handler basically catches every error if there are no other specific handler were declared. To declare a specific (only for one type of error) you may use something like following in your global.php file:
App::error(function(Illuminate\Database\Eloquent\ModelNotFoundException $exception) {
// Log the error
Log::error($exception);
// Redirect to error route with any message
return Redirect::to('error')->with('message', $exception->getMessage());
});
it's better to declare an error handler globally so you don't have to deal with it in every model/controller. To declare any specific error handler, remember to declare it after (bottom of it) the default error handler because error handlers propagates from most to specific to generic.
Read more about Errors & Logging.

Just use namespace
try {
$menus = Menu::where('parent_id', '>', 100)->firstOrFail();
}catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
$message = 'Invalid parent_id.';
return Redirect::to('error')->with('message', $message);
}
Or refer it to an external name with an alias
use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundException;

When you use the render() function in Laravel 8.x and higher versions, you will encounter 500 Internal Server Error. This is because with Laravel 8.x errors are checked within the register() function (Please check this link)
I'm leaving a working example here:
namespace App\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Throwable;
class Handler extends ExceptionHandler
{
public function register()
{
$this->renderable(function (ModelNotFoundException $e, $request) {
return response()->json(['status' => 'failed', 'message' => 'Model not found'], 404);
});
$this->renderable(function (NotFoundHttpException $e, $request) {
return response()->json(['status' => 'failed', 'message' => 'Data not found'], 404);
});
}
}

Try this
try {
$user = User::findOrFail($request->input('user_id'));
} catch (ModelNotFoundException $exception) {
return back()->withError($exception->getMessage())->withInput();
}
And to show error, use this code in your blade file.
#if (session('error'))
<div class="alert alert-danger">{{ session('error') }}</div>
#endif
And of course use this top of your controller
use Illuminate\Database\Eloquent\ModelNotFoundException;

Related

how to display exception handling error message in laravel

I have homecontroller in which I have a function storestudent it should able to handle exception, how to do it?
public function storestudent(Request $request)
{
try
{
$student= new student();
$student->sregno= $request['regno'];
$student->save();
return redirect('/home');
} catch (Exception $e){
throw new Execution;
}
}
try-catch exception is not working , help me to fix this please.
Thank you.
this is Execution.php
<?php
namespace App\Exceptions;
use Exception;
class Execution extends Exception
{
//
}
in handler.php
public function report(Exception $exception)
{
if($exception instanceof Execution)
{
echo "invalid register no";
}
parent::report($exception);
}
it gives me this error
This page isn’t working 127.0.0.1 is currently unable to handle this request.
HTTP ERROR 500
anyone help me to display my message and it should redirect to same page.
Here with try and catch you can use Log to keep errors in records and you can check records in log section in application:
public function storestudent(Request $request)
{
try
{
$student= new student();
$student->sregno= $request['regno'];
$student->save();
return redirect('/home');
} catch(Exception e){
$error = sprintf('[%s],[%d] ERROR:[%s]', __METHOD__, __LINE__, json_encode($e->getMessage(), true);
\Log::error($error);
}
}
For more info for Log fascade check this link: Logging.
And another way is to handle exception custom exception handling which you can get here.Error handling
To show error messages on redirect simply use flash messages in laravel without custom exceptions need. following code:
public function storestudent(Request $request)
{
try
{
$student= new student();
$student->sregno= $request['regno'];
$student->save();
\Session::flash('message','Saved successfully');
return redirect('/home');// if you want to go to home
} catch(Exception e){
\Session::flash('error', 'Unable to process request.Error:'.json_encode($e->getMessage(), true));
}
return redirect()->back(); //If you want to go back
}
Flash messages:
#if(Session::has('message'))
<p class="alert {{ Session::get('alert-class', 'alert-info') }}">{{
Session::get('message') }}</p>
#endif
or for more common flash view:
<div class="flash-message">
#foreach (['danger', 'warning', 'success', 'info','error'] as $msg)
#if(Session::has($msg))
<p class="alert alert-{{ $msg }}">{{ Session::get($msg) }}
</p>
#endif
#endforeach
</div>
Controller code:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Candidate;
use App\student;
use Exception;
class Homecontroller extends Controller
{
//function for login page
public function insertReg()
{
return view('login');
}
public function storestudent(Request $request)
{
try {
if ( !student::where('sregno',$request->regno )->exists() ) {
$student= new student();
$student->sregno= $request->regno;
if ($student->save()) {
\Session::flash('message','Saved successfully');
return redirect('/home');// if you want to go to home
} else {
throw new Exception('Unable to save record.);
}
} else {
throw new Exception('Record alreasy exists with same sregno');
}
} catch(Exception $e){
\Session::flash('error', 'Unable to process request.Error:'.json_encode($e->getMessage(), true));
}
return redirect()->back(); //If you want to go back
}
Hope this helps.

Only load route with existent parametre

Im doing a crud, i want to show item data using id, i have this in web.php:
Route::get('update/{id}', 'CrudController#update');
How can I deny that the user changes the id in the path to one that does not exist? That shows only those that exist and those that do not, that do not load?
In your update method, you can do the following:
public function update($id)
{
MyModel::findOrFail($id);
//...perform other actions
}
It will throw a 404 response if the requested $id is a non-existent one.
Then you can catch it if you want in the render() method of app\Exceptions\Handler.php:
use Illuminate\Database\Eloquent\ModelNotFoundException;
.
.
.
public function render($request, Exception $exception)
{
if ($exception instanceof ModelNotFoundException) {
if ($request->wantsJson()) {
return response()->json([
'data' => 'Resource not found'
], 404);
} else {
abort(404);
}
}
return parent::render($request, $exception);
}
Or, If you do not want to go through all the trouble of configuring it in the handler, you could also do:
public function update($id)
{
if (! $model = MyModel::find($id)) {
abort(404);
}
//...perform other actions with $model
}
The abort(404) method takes the user to the default Page not found page of laravel, which is an appropriate thing to do.

Why UserNotVerifiedException error is not trigered?

In my my laravel 5.7.3 application I use https://github.com/jrean/laravel-user-verification extention and with use of
middleware I generate UserNotVerifiedException error when logged is not verified
But with excception I want to make logout and redirect to /login page and reading https://laravel.com/docs/master/errors#the-exception-handler doc in
file app/Exceptions/Handler.php I do :
<?php
namespace App\Exceptions;
use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Auth;
use App\Exceptions\UserNotVerifiedException;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Foundation\Auth\RegistersUsers;
use Jrean\UserVerification\Traits\VerifiesUsers; // Do I need to add these declarations here ?
use Jrean\UserVerification\Facades\UserVerification;
class Handler extends ExceptionHandler
{
use RegistersUsers;
use VerifiesUsers;
protected $dontReport = [
//
];
protected $dontFlash = [
'password',
'password_confirmation',
];
public function report(Exception $exception)
{
parent::report($exception);
}
public function render($request, Exception $exception)
{
dump($exception);
if ($exception instanceof UserNotVerifiedException) {
dump("Make Logout");
Auth::logout();
return redirect('/admin/dashboard/index');
}
return parent::render($request, $exception);
}
}
In dump file I see first message, but not second(and why there is no redirection):
UserNotVerifiedException {#509 ▼
#message: "This user is not verified."
#code: 0
#file: "/mnt/_work_sdb8/wwwroot/lar/Votes/vendor/jrean/laravel-user-verification/src/Middleware/IsVerified.php"
#line: 26
trace: {▶}
}
Which is valid way ?
Thanks!
You can try to put the original namespace like:
if ($exception instanceof \Jrean\UserVerification\Exceptions\UserNotVerifiedException) {
dump("Make Logout");
Auth::logout();
return redirect('/admin/dashboard/index');
}

i cant use method store in laravel framework

i am learning to myself laravel framework, and now i am trying to save data in a table, However it does but it gives me the error
Fatal error-Use of undefined constant users - assumed 'users'
Sending the form:
<form method="post" action="{{route('users.store')}}">
and in the method store:
namespace App\Http\Controllers;
use App\User;
use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;
use App\Http\Requests;
use Exception;
class UserController extends Controller
{
public function index()
{
$data=User::all();
return view ('index',compact('data'));
}
public function create()
{
return view('create');
}
public function store(Request $request)
{
try{
$user=new User();
$user->name=$request->name;
$user->email=$request->email;
$user->password= bcrypt($request->password);
$user->save();
return redirect()->route(users.index);
} catch (Exception $e) {
return "Fatal error-" .$e->getMessage();
}
}
This is incorrect, you're missing the quotes:
return redirect()->route(users.index);
change to
return redirect()->route('users.index');

Handling Custom Exceptions from PHPUnit (Laravel 5.2)

I'm currently playing around with Exception Handler, and creating my own custom exceptions.
I've been using PHPUnit to run tests on my Controller Resource, but when I throw my custom exceptions, Laravel thinks it's coming from a regular HTTP request rathen than AJAX.
Exceptions return different response based on wether it's an AJAX request or not, like the following:
<?php namespace Actuame\Exceptions\Castings;
use Illuminate\Http\Request;
use Exception;
use Actuame\Exceptions\ExceptionTrait;
class Already_Applied extends Exception
{
use ExceptionTrait;
var $redirect = '/castings';
var $message = 'castings.errors.already_applied';
}
And the ExceptionTrait goes as follows:
<?php
namespace Actuame\Exceptions;
trait ExceptionTrait
{
public function response(Request $request)
{
$type = $request->ajax() ? 'ajax' : 'redirect';
return $this->$type($request);
}
private function ajax(Request $request)
{
return response()->json(array('message' => $this->message), 404);
}
private function redirect(Request $request)
{
return redirect($this->redirect)->with('error', $this->message);
}
}
Finally, my test goes like this (excerpt of the test that's failing)
public function testApplyToCasting()
{
$faker = Factory::create();
$user = factory(User::class)->create();
$this->be($user);
$casting = factory(Casting::class)->create();
$this->json('post', '/castings/apply/' . $casting->id, array('message' => $faker->text(200)))
->seeJsonStructure(array('message'));
}
My logic is like this although I don't think the error is coming from here
public function apply(Request $request, User $user)
{
if($this->hasApplicant($user))
throw new Already_Applied;
$this->get()->applicants()->attach($user, array('message' => $request->message));
event(new User_Applied_To_Casting($this->get(), $user));
return $this;
}
When running PHPUnit, the error I get returned is
1) CastingsTest::testApplyToCasting PHPUnit_Framework_Exception:
Argument #2 (No Value) of PHPUnit_Framework_Assert:
:assertArrayHasKey() must be a array or ArrayAccess
/home/vagrant/Code/actuame2/vendor/laravel/framework/src/Illuminate/Foundation/T
esting/Concerns/MakesHttpRequests.php:304
/home/vagrant/Code/actuame2/tests/CastingsTest.php:105
And my laravel.log is over here http://pastebin.com/ZuaRaxkL (Too large to paste)
I have actually discovered that PHPUnit is not actually sending an AJAX response, because my ExceptionTrait actually changes the response on this. When running the test it takes the request as a regular POST request, and runs the redirect() response rather than ajax(), hence it's not returning the correspond.
Thanks a bunch!
I have finally found the solution!
As I said, response wasn't the right one as it was trying to redirect rathen than return a valid JSON response.
And after going through the Request code, I found out that I need to use also wantsJson(), as ajax() may not be the case always, so I have modified my trait to this:
<?php
namespace Actuame\Exceptions;
trait ExceptionTrait
{
public function response(Request $request)
{
// Below here, I added $request->wantsJson()
$type = $request->ajax() || $request->wantsJson() ? 'ajax' : 'redirect';
return $this->$type($request);
}
private function ajax(Request $request)
{
return response()->json(array('message' => $this->message), 404);
}
private function redirect(Request $request)
{
return redirect($this->redirect)->with('error', $this->message);
}
}

Resources