How to handle native exception in Laravel? - laravel

For example, I use:
return User::findOrFail($id);
When row does not exist with $id I get exception.
How I can return this exception in Json response? It returns HTML Laravel page now.
I need something like as:
{"error", "No query results for model"}

From their documentation:
Sometimes you may wish to throw an exception if a model is not found. This is particularly useful in routes or controllers. The findOrFail and firstOrFail methods will retrieve the first result of the query. However, if no result is found, a Illuminate\Database\Eloquent\ModelNotFoundException will be thrown.
So, you can either catch that exception, or go with the simple Find method. It will return false if not found, so you can handle it accordingly.
return User::find($id);
UPDATE:
Option 1:
try {
return User::findOrFail($id);
} catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
return json_encode(['error' => 'No query results for model']);
}
Option 2:
$user = User::find($id);
if($user) {
return $user;
}
return json_encode(['error' => 'No query results for model']);

You can handle various types of exceptions, that exception can be handle with a ModelNotFoundException in this case
try{
$user = User::findOrFail($id);
}catch(ModelNotFoundException $e){
return response()->json(['error' => 'User not found'], 400);
}
And there's another way to catch various types of exceptions in the Handler.php located on app/Exceptions/Handler.php there you can catch the exceptions and return whatever you want inside the render function.
For example insede that function you can add this before the return parent::render($request, $e):
if($e instanceof ModelNotFoundException)
{
return new Response(['message' => 'We haven\'t find any data'], 204);
}

You should look in render method of Handler file. You can test exception class here and depending on it return different response in Json format

Related

Why does Laravel Cashier silently catch Stripe exceptions?

There are numerous places in Laravel Cashier where exceptions are trapped within the Cashier code, but not really handled in any meaningful way - not even logged. This results in bizarre behaviour if there is something wrong with the Stripe request (e.g. invalid price_id specified), where a null value is returned with no indication about why.
Anyone know why they have silently 'trapped' these errors making it impossible for the calling code to report?
e.g. Laravel\Cashier\Concerns\ManageInvoices::upcomingInvoice():
public function upcomingInvoice(array $options = [])
{
if (! $this->hasStripeId()) {
return;
}
$parameters = array_merge([
'automatic_tax' => $this->automaticTaxPayload(),
'customer' => $this->stripe_id,
], $options);
try {
$stripeInvoice = $this->stripe()->invoices->upcoming($parameters);
return new Invoice($this, $stripeInvoice, $parameters);
} catch (StripeInvalidRequestException $exception) {
//
}
}

How to avoid error when using Eloquent's toArray when getting null result

l am getting start at a new laravel project with 5.7, but one problem, when l use first() to fetch data, and if data is not exist, it will return null, and then execute toArray() will throw a PHP error. So l use follow code to reslove it.
$user_model = \App\Model\User::where('id', $id);
if ($select) {
$user_model->select(explode(',', $select));
}
$user_data = $user_model->first();
$user_data = $user_data ?? $user_data->toArray();
So is there any better way?
Any one of the following will work, each providing their own way of dealing with a null result:
1. optional helper:
The optional function accepts any argument and allows you to access
properties or call methods on that object. If the given object is null,
properties and methods will return null instead of causing an error.
$user_data = optional($user_model->first())->toArray();
2. firstOr():
Execute the query and get the first result or call a callback.
$data = User::where('id', $id)->when(!is_null($select), function ($query) use ($select) {
return $query->select(explode(',', $select));
})->firstOr(function () {
return ['message' => 'No results'];
});
3. rescue helper:
The rescue function executes the given Closure and catches any exceptions that occur during its execution. All exceptions that are caught will be sent to your exception handler's report method; however, the request will continue processing.
$data = rescue(function () use ($select) {
\App\Model\User::where('id', $id);
if ($select) {
$user_model->select(explode(',', $select));
}
return $user_model->first()->toArray();
});
4. try catch:
try {
$user_model = \App\Model\User::where('id', $id);
if ($select) {
$user_model->select(explode(',', $select));
}
$user_data = $user_model->first();
$user_data = $user_data ?? $user_data->toArray();
} catch(\Exception $e) {
// handle the exception...
}
Laravel provides a firstOrFail method which throws an 404 Exception by default.
$user_data = $user_model->firstOrFail(); // If not found an exception is thrown and will be handled by default ExceptionHandler which displays a 404 error page.
// if found, cast the User to array
$user_data = $user_data->toArray();

display message for database insert operation

Is there any mechanism that we can know that the data sent from app is successfully inserted to database, as in stored procedure, we use output parameter.
How can we be sure that the data is inserted into database and in case if the data insertion operation is failed, how to catch the error cause and display in a user friendly way?
// controller code
public function store(Request $request)
{
$validatedInput = $request -> validate([
'NBookName' => 'required|string|min:3|max:100',
'NBookId' => 'required|string|min:2|max:10|unique:books,BookID', // unique:table_name,column_name
'NBookUnitPrice' => 'required|max:5|'
]);
$book = new Book;
$book -> BookName = $request->input('NBookName');
$book -> BookID = $request->input('NBookId');
$book -> BookUnitPrice = $request->input('NBookUnitPrice');
$book->save();
return view('pages.about');
}
The Eloquent method save returns either true or false, thus checking the return of the save will let you know if the operation was successful.
You can alternatively use the method saveOrFail which will also return true / false, but may also give a Throwable
From the documentation: https://laravel.com/api/5.3/Illuminate/Database/Eloquent/Model.html#method_save
Examples:
if( $book->save() ){
return response()->json($book, 200);
} else {
return response()->json(['error' => 'Could not save'], 400);
}
or
try {
$book->saveOrFail();
return response()->json($book, 200);
} catch( \Exception $e ){
return response()->json(['error' => $e->getMessage()], 400);
}
save() will return a boolean, saved or not saved. So you can either do Like:
$saved = $book->save();
if(!$saved)
{
App::abort(500, 'Error');//Or return any message to view
}
For more details:check-if-laravel-model-got-saved-or-query-got-executed
I'd start off by separating the layer, I don't like watching validations, Eloquent queries and view related output in the same place.
Before reading the answer below, take a look at
https://laravel.com/docs/5.6/validation#form-request-validation
I'd make middleware to authenticate and authorize users, then use formrequests to validate the input data, and by the time it reaches the controller, the user is authenticated, authorized, data validated and all it's needed is call someone that is responsible for the insert operation and return something to the UI.
"How can we be sure that the data is inserted into database and in
case if the data insertion operation is failed"
Generally, a try catch will do:
public function store(Request $request)
{
try {
$validatedInput = $request -> validate([
'NBookName' => 'required|string|min:3|max:100',
'NBookId' => 'required|string|min:2|max:10|unique:books,BookID', // unique:table_name,column_name
'NBookUnitPrice' => 'required|max:5|'
]);
$book = new Book;
$book -> BookName = $request->input('NBookName');
$book -> BookID = $request->input('NBookId');
$book -> BookUnitPrice = $request->input('NBookUnitPrice');
$book->save();
} catch (\Exception $e) { 
// return your pretty response
// If the operation saving to the database fails, you'll get the information here on whatever it is about,
// as the generic exception catchs it. It should catch the stored procedure output aswell
}
return view('pages.about');
}
If you plan on having a series of insertions and updates/deletes and you don't want them to break logic (insert some and stop at inserting when 1 is wrong), you can use DB; and use DB::beginTransaction(), DB::commit() and DB::rollback() on your code
https://laravel.com/docs/5.6/database

How to add custom error in Laravel?

How to call custmo error in controller, that after to show in template?
For example, I have condition:
if($id == 500){
// call error
}
If you want to call just the error in the controller and abort, you do
abort(500, 'Internal error');
If you want to return an error
return redirect()->back()->withErrors(['error' => 'was 500']);
You can do this by catching the error in the Handler (app/Exceptions/Handler.php), something like this:
public function render($request, Exception $e){
// other errors here by your wish
// custom error message
if ($e instanceof \ErrorException) {
return response()->view('errors.500', [], 500);
}else{
return parent::render($request, $e);
}
return parent::render($request, $e);
}
Note that you need 500 template in resources/views/errors/500.blade.php (create if it doesnt exist, and fill if with your data or iformation about the exception)

Custom 404 page in Lumen

I'm new to Lumen and want to create an app with this framework. Now I have the problem that if some user enters a wrong url => http://www.example.com/abuot (wrong) => http://www.example.com/about (right), I want to present a custom error page and it would be ideal happen within the middleware level.
Furthermore, I am able to check if the current url is valid or not, but I am not sure how can I "make" the view within the middleware, the response()->view() won't work.
Would be awesome if somebody can help.
Seeing as errors are handled in App\Exceptions\Handler, this is the best place to deal with them.
If you are only after a custom 404 error page, then you could do this quite easily:
Add this line up the top of the Handler file:
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
Alter the render function to look like so:
public function render($request, Exception $e)
{
if($e instanceof NotFoundHttpException){
return response(view("errors.404"), 404);
}
return parent::render($request, $e);
}
This assumes your custom 404 page is stored in an errors folder within your views, and will return the custom error page along with a 404 status code.
You may want to add this so that when for example blade blows up the error page hander will not throw a PHP error.
public function render($request, Exception $exception)
{
if (method_exists('Exception','getStatusCode')){
if($exception->getStatusCode() == 404){
return response(view("errors.404"), 404);
}
if($exception->getStatusCode() == 500){
return response(view("errors.500"), 404);
}
}
return parent::render($request, $exception);
}
I am using Lumen 8.x version and below solution worked for me:
File path: ‎⁨▸ ⁨app⁩ ▸ ⁨Exceptions⁩ ▸ ⁨Handler.php
public function render($request, Throwable $exception)
{
// start custom code
if($exception->getStatusCode() == 404){
return response(view("errors.404"), 404);
}
if($exception->getStatusCode() == 500){
return response(view("errors.500"), 404);
}
// end custom code
return parent::render($request, $exception);
}
Do not forget to create errors folder at /resources/views/errors and create the below 2 new files in errors folder:
404.blade.php
500.blade.php
and add html tags and messages in those files what you want to add.
Happy to help you. Thanks for asking this question.
I faced the same situation. response(view("errors.404"), 404)did not work for me, so I changed it as follows:
public function render($request, Exception $exception)
{
if($exception instanceof NotFoundHttpException){
return response(view('errors.404')->render(), 404);
}
return parent::render($request, $exception);
}

Resources