I'd like to know what went wrong is it.
I want to use own Exception in try catch but I can't catch it.
Or maybe I catch it but is not what I want.
My php version is 7.4.30, laravel is 6.20.44.
Here is my code , I write a api to find a product , it's a get method.
api route
Route::get('/product/{id}', 'ProductCategoryController#find');
Execption
<?php
namespace App\Exceptions;
use Exception;
class ProductException extends Exception
{
public function render()
{
return response()->json([
'status' => 404,
'message' => 'product not found',
], 404);
}
}
Service
public static function find($id)
{
$product = ProductCategory::find($id);
if (!$product) {
throw new ProductException('ProductException', 400);
}
}
Controller
public function find($id)
{
return $this->ProductCategoryService->find($id);
try {
return $this->ProductCategoryService->find($id);
} catch (ProductException $e) {
return response()->json(['message' => $e->getMessage(), 'code' => $e->getCode()], 400);
}
}
I want to know my controller just use
return $this->ProductCategoryService->find($id);
I can get my onw exception response like this
When I commented off change to use try catch i will get
Why try catch catch exception is catch I throw parameters not catch
public function render()
{
return response()->json([
'status' => 404,
'message' => 'product not found',
], 404);
}
I want to know how it happened? and how to fix it
Thanks
Related
I have a pretty complex Laravel application who creates a one to one polymorphic relationship in a middleware if it does not exists. The fact is that I am unable to retrieve the relationship in the same request (create in middleware, then pass it and retrieve it), I have an error 500 when I try to do this. BUT, if I a make an other request I can retrieve it... When I look into my database, I have the userable_id and type defined, I have no idea where this can probably occur.
My middleware look like this:
public function handle(Request $request, Closure $next): mixed
{
if (!Storage::disk('cecurity')->exists(config('coffre_fort.ssl_certificate.name')) ||
!config('coffre_fort.reverse_proxy.username') ||
!config('coffre_fort.reverse_proxy.password') ||
!config('coffre_fort.encryption_key')) {
return response()->json([
'error' => 'Cecurity is not configured correctly.',
], 500);
} elseif (!Auth::user()) {
return response()->json([
'error' => 'You are not authenticated.',
], 401);
}
if (!Auth::user()->cecurityAccount) {
try {
$userType = Auth::user()::class;
/** #phpstan-ignore-next-line */
if ($userType == "App\Models\Admin") {
$this->cecurityRepository->createAdminUser(Auth::user());
} else {
// It enter in this function for creating relationship
$this->cecurityRepository->createFullCustomer(Auth::user());
}
} catch (Exception $e) {
return response()->json([
'error' => $e->getMessage(),
], 500);
}
} elseif (!$this->cecurityRepository->checkConnection()) {
$this->cecurityRepository->connect(
Auth::user()->cecurityAccount->cecurity_user_id,
openssl_decrypt(
Auth::user()->cecurityAccount->password,
'AES-256-CBC',
config('coffre_fort.encryption_key'),
0,
(int) Auth::user()->cecurityAccount->encryption_iv
),
Auth::user()->cecurityAccount->coffre_id
);
}
return $next($request);
}
Then it creates the relationship as this (in the createFulCustomer() function):
$user = new Cecurity;
$user->userable_id = $customer->id_customer;
$user->userable_type = Customer::class;
And then pass the middleware to go to listFiles() function in a controller:
public function listFiles(ListFilesRequest $request): mixed
{
try {
return $this->cecurityRepository->listFiles(
$request->get('nbRowByPage'),
$request->get('pageIndex'),
);
} catch (\Exception $e) {
return response()->json([
'message' => $e->getMessage()
], 500);
}
}
Just after the middleware has passed, my database is completed (Cecurity table related):
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);
I am using AuthBasic for API authentication in a Laravel project,
I have this problem: when the API request authentication is invalid instead of displaying the JSON response it returns the 401 default blade view template.
Here is the code:
app\Http\Middleware\AuthBasic.php
public function handle($request, Closure $next)
{
if (Auth::onceBasic()) {
return response()->json(["message", "Authentication Required!"], 401);
} else {
return $next($request);
}
}
Found the Solution:
app\Exceptions\Handler.php
public function render($request, Exception $exception)
{
if ($request->is('api/*') || $request->wantsJson())
{
$json = [
'success' => false,
'error' => [
'code' => $exception->getCode(),
'message' => $exception->getMessage(),
],
];
return response()->json($json, 401);
}
return parent::render($request, $exception);
}
Remove the 401 or change it to 200 from this line:
return response()->json(["message", "Authentication Required!"], 401);
See the reference, the second parameter is defining the http code to send the browser. [401] in you case.
https://laravel.com/api/5.7/Illuminate/Routing/ResponseFactory.html#method_json
This will fix your problem, probably!
public function handle($request, Closure $next)
{
$result = Auth::onceBasic();
if($result === 401)
return response()->json(["message", "Authentication Required!"]);
else
return $next($request);
}
So here is a half Solution for this problem:
vendor\laravel\framework\src\Illuminate\Auth\SessionGuard.php
public function onceBasic($field = 'email', $extraConditions = [])
{
$credentials = $this->basicCredentials($this->getRequest(), $field);
if (! $this->once(array_merge($credentials, $extraConditions))) {
//return $this->failedBasicResponse();
return response()->json(["Message" => "Authentication Required!"], 401);
}
}
So Instead of returning the Failed Basic Response it will return the JSON Message, but I don't want to make changes in Laravel Core Files, because in case of update they will get lost !
So Any Idea ?
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 have a webservice module configured with json strategy. I am making a login functionality where if the user is not logged return an error.
To test if the user is logged have an event dispatch on Module class
class Module {
public function onBootstrap(MvcEvent $e) {
(...)
$eventManager->attach(MvcEvent::EVENT_DISPATCH, array($this, 'mvcPreDispatch'), 1000);
}
public function mvcPreDispatch(MvcEvent $e) {
$authService = $e->getApplication()->getServiceManager()->get('auth');
if($authService->isAuthenticated()) {
return true;
}
$model = new JsonModel(array(
'errors' => array(
'httpCode' => $e->getResponse()->getStatusCode(),
'title' => $e->getResponse()->getReasonPhrase(),
'message' => 'Login necessário'
)
));
return $model;
}
}
How can I stop the request and display the error message on the screen?
Afaik you need to short circuit the event by returning a Response object or by calling stopPropagation(true) on the event. This will stop all other dispatch listeners from executing and return a response to the client.
You can try something like this:
public function mvcPreDispatch(MvcEvent $e)
{
$authService = $e->getApplication()->getServiceManager()->get('auth');
if($authService->isAuthenticated()) {
return true;
}
$model = new JsonModel(array(
'errors' => array(
'httpCode' => $e->getResponse()->getStatusCode(),
'title' => $e->getResponse()->getReasonPhrase(),
'message' => 'Login necessário'
)
));
$e->setViewModel($model);
$e->stopPropagation(true);
}