How to catch exception and send custom error message - php

I have a function
public function getCandidates($candidateEmail)
{
try {
$moduleIns = ZCRMRestClient::getInstance()->getModuleInstance('Candidats');
$response = $moduleIns->searchRecordsByEmail($candidateEmail, 1, 1);
$candidates = $response->getResponseJSON();
return $candidates;
} catch (ZCRMException $e) {
echo $e->getMessage();
echo $e->getExceptionCode();
echo $e->getCode();
}
}
And I use this function like that :
$obj = new ZohoV2();
$response = $obj->getCandidates($request->email);
$candidate = $response['data'][0];
return response()->json([ 'status' => 'success', 'candidate' => $candidate ], 200);
Theses functions allows me to retrieve a user from a database of a CRM.
But when the user does not exist, he sends me a 500 error.
{message: "No Content", exception: "zcrmsdk\crm\exception\ZCRMException",…}
exception: "zcrmsdk\crm\exception\ZCRMException"
file: "/home/vagrant/CloudStation/knok/myath/myath-app/vendor/zohocrm/php-sdk/src/crm/api/response/BulkAPIResponse.php"
line: 61
message: "No Content"
trace: [{,…}, {,…}, {,…}, {,…}, {,…}, {,…},…]
How to intercept this error so that I can process it as I want and send an error message ?
Thank you

Remove the try/catch from your first code block
public function getCandidates($candidateEmail)
{
$moduleIns = ZCRMRestClient::getInstance()->getModuleInstance('Candidats');
$response = $moduleIns->searchRecordsByEmail($candidateEmail, 1, 1);
$candidates = $response->getResponseJSON();
return $candidates;
}
And move it to the second code block (I assume it's the controller)
$obj = new ZohoV2();
try {
$response = $obj->getCandidates($request->email);
} catch (ZCRMException $e) {
return response()->json(['status' => 'failed', 'error' => $e->getMessage()], 404);
}
$candidate = $response['data'][0];
return response()->json([ 'status' => 'success', 'candidate' => $candidate ], 200);

Related

How to check if exception is reportable or not in Laravel 9?

I have only API laravel project. If I turn the debug mode off in .env file by setting APP_DEBUG=false, my application throws Server error for the errors that shouldn't be shown to user.
But it return json response like this:
{
"message": "Server Error"
}
I want to add code key to it ass well. What I am trying to achieve:
{
"code": 500,
"message": "Server Error"
}
What I tried so far (register method of Handler):
$this->renderable(function (Throwable|Exception $e) {
return response()->json([
'code' => $e->getCode(),
'message' => $e->getMessage()
], $e->getCode());
});
But this will return exception message that shouldn't shown to user. I need smth like this:
$this->renderable(function (Throwable|Exception $e) {
// ReportableException doesn't exist in laravel
if($e instanceof ReportableException){
return response()->json([
'code' => 500,
'message' => 'Server error'
], 500);
}
return response()->json([
'code' => $e->getCode(),
'message' => $e->getMessage()
], $e->getCode());
});
I found out that there is isHttpException method that is used to know if exception is reportable or unreportableto user. So that is my solution:
$this->renderable(function (Throwable $e) {
if (!$this->isHttpException($e)){
return response()->json([
'code' => 500,
'message' => "Internal server error"
], 500);
}
$code = $e->getCode() == 0 ? 500 : $e->getCode();
return response()->json([
'code' => $code,
'message' => $e->getMessage()
], $code);
});
You do have access to HttpResponseException so you can do something like this:
if ($exception instanceof \Illuminate\Http\Exception\HttpResponseException) {
//Can use this directly for details
$exception = $exception->getResponse();
//Or handle the exception manually
switch ($exception->getStatusCode()) {
case 401:
$response->code = 401;
$response->message = 'Unauthorized';
break;
case 403:
$response->code = 403;
$response->message = 'Unauthorized';
break;
case 404:
$response->code = 404;
$response->message = 'Not Found';
break;
case 405:
$response->code = 405;
$response->message = 'Unauthorized';
break;
case 422:
$response->code = 422;
$response->message = '??';
break;
default:
$response->code = 500;
$response->message = '??';
break;
}
}
So it will look something like this:
if($e instanceof \Illuminate\Http\Exception\HttpResponseException){
return response()->json([
'code' => $e->getStatusCode(),
'message' => 'Server error'
], $e->getStatusCode());
}
Hopefully this works for you.

How to return Laravel exception into JSON response

I want customize my Laravel exception handler to return some JSON response, but I get empty result, with 500 http error.
I try it like this
public function register()
{
$this->renderable(function (Throwable $e) {
$status = $e->getCode();
$message = $e->getMessage();
$data = $e->getTrace();
return response()->json(['status' => $status, 'message' => $message, 'data' => $data], $status ?? 400);
});
}
Is this the correct way to do it?

How to show json encoded array in Sweet alert message

I'm using Laravel 8 and Sweet Alert and I wanted to show the error messages that were caught by error Exception as Sweet Alert error popup message.
Basically here is my Controller method:
try{
...
}catch(\Exception $e){
// Alert::error('Error Title', 'Error Message');
return json_encode(['status' => '500', 'msg' => __('message.error-server')]);
}
So as you can see I have json encoded an associative array that holds the information of the error message but I don't want to return it. In fact I have to show it as Alert::error(...).
So how can I do that?
UPDATE 1:
I just tested this but not showing me the error as Alert:
public function destroy(User $user)
{
try{
$useradasd->is_active = 0;
$useradasd->is_deleted = 1;
$useradasd->remover_id = Auth::id();
$useradasd->save();
}catch(\Exception $e){
$attributes = ['status' => '500', 'msg' => __('message.error-server')];
$dataAttributes = array_map(function($value, $key) {
return $key.'=>'.$value;
}, array_values($attributes), array_keys($attributes));
$associativeString = implode(', ', $dataAttributes);
Alert::error($associativeString);
}
Alert::success('Removed', 'That user is deleted');
return back();
}
UPDATE 2:
I just tried this, but does not catch the error exception and show me the Alert::success(...) instead.
public function destroy(User $user)
{
try{
$useradasd->is_active = 0;
$useradasd->is_deleted = 1;
$useradasd->remover_id = Auth::id();
$useradasd->save();
}catch(\Exception $e){
$attributes = ['status' => '500', 'msg' => __('message.error-server')];
$dataAttributes = array_map(function($value, $key) {
return $key.'=>'.$value;
}, array_values($attributes), array_keys($attributes));
$associativeString = implode(', ', $dataAttributes);
Alert::error('Error',$associativeString);
}
Alert::success('Removed', 'That user is deleted');
return back();
}
UPDATE #3:
I can finally get the error:
But I wanted to show $attributes['status'] which is 500 as Error Title and the body of that error contains $attributes['msg']. How can I do that?
You can do this:
$attributes = ['status' => '500', 'msg' => __('message.error-server')
$dataAttributes = array_map(function($value, $key) {
return $key.'=>'.$value;
}, array_values($attributes), array_keys($attributes));
$associativeString = implode(', ', $dataAttributes);
What this does basically is, it will convert the associative array to string first and then you can use the final string i.e.$associativeString in your alert as:
Alert::error($associativeString);
this will output like:
status => 500, msg => Internal Server Error
you can modify return $key.'=>'.$value; inside map to shape the final output the way you want.
UPDATE #1
Looking at the SweetAlert docs you used, I believe it follows the syntax of Alert::[type]([Title],[message]), You can update the alert from this:
Alert::error($associativeString);
to this:
Alert::error('Error',$associativeString);
UPDATE #2
public function destroy(User $user)
{
try{
$useradasd->is_active = 0;
$useradasd->is_deleted = 1;
$useradasd->remover_id = Auth::id();
$useradasd->save();
throw new Exception("Custom Exception from try block");
}catch(\Exception $e){
$attributes = ['status' => '500', 'msg' => $e->getMessage()];
$dataAttributes = array_map(function($value, $key) {
return $key.'=>'.$value;
}, array_values($attributes), array_keys($attributes));
$associativeString = implode(', ', $dataAttributes);
Alert::error('Error',$associativeString);
}
return back();
}
UPDATE #3
You should work on improving your concepts of arrays in php and how they work learn How PHP associative arrays work, now according to your requirement you should not convert the associative array to string as I suggested in my original answer. try this instead:
public function destroy(User $user)
{
try{
$useradasd->is_active = 0;
$useradasd->is_deleted = 1;
$useradasd->remover_id = Auth::id();
$useradasd->save();
throw new Exception("Custom Exception from try block");
}catch(\Exception $e){
$attributes = ['status' => '500', 'msg' => $e->getMessage()];
Alert::error($attributes['status'],$attributes['msg']);
}
return back();
}
the Alert::error() takes two parameters the first one is Title and the second is the message, you just have to fetch the value from related keys of associative array i.e. status and msg in our case.
This Should Work
Alert::error(json_encode(['status' => '500', 'msg' => __('message.error-server')],JSON_PRETTY_PRINT));

try catch statments with in a class and controller

I have a question about try catch bock exceptions. I want to know if I have a class called Image that makes images and in that class is a try catch statement and if there is an error I want my controller that makes the image to return the response, So in my controller I also have a catch statement what I want to know is what I have below correct and going to work when I have an error and if it aint going to work can you show me how my statements should be.
<?php
namespace App\Acme\Imaging;
use Image as Intervention;
class Image
{
public function __construct($input) {
}
public function save() {
try {
$image = Intervention::make(...);
$image->save(...);
} catch(NotReadableException $e) {
return response()->json(['error' => true, 'message' => $e->getMessage()], $e->getCode(), ['Content-Length' =>$e->getMessage()])
}
}
}
public function store(PostRequest $request)
{
try {
$image = new Image;
$image->width = 500;
$image->height = 500;
$image->save();
$post = new Post;
$post->fill($request->all());
$post->created_by = Auth::user()->id;
$post->image = $image;
if($post->save()) {
return response()->json($post, 200, ['Content-Lnegth' => strlen(json_encode($post))]);
}
} catch(Exception $e) {
return response()->json(array('error' => true, 'type' => 'exception', 'message' => $e->getMessage()), $e->getCode(), ['Content-Length' => strlen($e->getMessage())]);
}
}
Since you are not throwing the error, the controller will not catch it. In order to maintain the original error data, You could do something like this...
public function save() {
try {
$image = Intervention::make(...);
$image->save(...);
} catch(NotReadableException $e) {
throw new Exception('Error Saving file: ' . 'message: ' . e->getMessage() . ' code: ' . $e->getCode();
}
}
Then your calling function will enter the catch block and spit out the whole thing as part of it's $e->getMessage()
[...]
} catch( NotReadableException $e ) {
return json_encode( array(
'code' => $e
->response()
->getCode(),
'content-length' => $e
->response()
->getMessage()
) );
}
[...]
To encode something in json, you must use the json_encode() function. Assuming that the instanced NotReadableException is using the response() method to return an object holding the data, it may look something like the above.
response() indicates the current objects scope, you need to target the instanced Exception through the variable you created ($e), however, you have shown no code for that so I can only guess your hierarchy of it.
The below example on a non-extended Exception class looks like this:
try {
throw new Exception( "Example message." );
} catch ( Exception $e ) {
return json_encode( array (
'content-length' => $e
->getMessage()
) );
}
See it working here over at https://3v4l.org/O7WJF.

I want to be able to catch an error if there is one in a form with Validation

Here is the code:
try {
$result = Model_User::update_user($_POST);
// message: save success
Message::add('success', __('Values saved.'));
// redirect and exit
$this->request->redirect('user/profile');
return;
} catch (Exception $e) {
// Get errors for display in view
// Note how the first param is the path to the message file (e.g. /messages/register.php)
Message::add('error', __('Error: Values could not be saved.'));
$errors = $e->errors('register');
$errors = array_merge($errors, (isset($errors['_external']) ? $errors['_external'] : array()));
$view->set('errors', $errors);
// Pass on the old form values
$user->password = '';
$view->set('data', $user);
}
Here is the code of update_user method in Model_User:
public function update_user($fields)
{
$validation = Validation::factory($fields)
->rules('password', $this->_rules['password'])
->rules('password_confirm', $this->_rules['password_confirm'])
->filters('password', $this->_filters['password']);
$this->validate($fields);
$users = CASSANDRA::selectColumnFamily('Users');
if ($users->get_cout($username))
{
return $users->insert($uuid, array(
'username' => $fields['username'],
'password' => $fields['password'],
'email' => $fields['email'],
'modify' => date('YmdHis', time()),
));
}
else
{
return $validation;
}
}
I am now getting this error:
ErrorException [ Fatal Error ]: Call to undefined method ErrorException::errors()
Stuck on this line:
117 $errors = $e->errors('register');
Thanks in advance for any help!
You need to catch a Validation_Exception for handling validation errors.
Only this kind of exception has an errors() method. Your code is throwing some other kind of exception, for which you need to do the error handling yourself.
So, change
} catch (Exception $e) {
to
} catch (Validation_Exception $e) {
$errors = $e->errors('register');
...
} catch (Exception $e) {
// Do your error handling by hand
}

Categories