how to get exception code in laravel5.5? - php

I want to get the exception code in Hanlder.php . But i get the code , it is 0.
the code follow list :
public function render($request, Exception $exception)
{
if ($exception->getCode() >= 500) {
return response()->json(['error' => 'server error!'], '500');
}
return parent::render($request, $exception);
}
I find the code in the exception , the default value of code is 0.
public function __construct($message = "", $code = 0, $severity = 1, $filename = __FILE__, $lineno = __LINE__, $previous) { }
how can I get the code of exception?
And i am sorry ,my native language is chinese.
Thank you!

You need to check if the exception is an instance of HttpException
// If this exception is an instance of HttpException
if ($this->isHttpException($e)) {
// Grab the HTTP status code from the Exception
$status = $e->getStatusCode();
}

Related

Laravel get error type (E_ERROR, E_WARNING, etc)

I am using Laravel v8. Is it possible to get the actual error type, as per the error constants in PHP? https://www.php.net/manual/en/errorfunc.constants.php
I am trying to distinguish between fatal and non-fatal errors.
I am not using any custom error handler - just the one built in with Laravel.
I have tried the following in \app\Exceptions\Handler.php:
public function render($request, Throwable $e)
{
$error = error_get_last();
$type = $error['type']; // returns int or null
if ($type == 1) {
// do stuff here
}
return parent::render($request, $e);
}
But it seems error_get_last() is always returning null.
Answering my own question here. Since I am only really interested in finding out if an error was a fatal/non-fatal, the following works perfectly:
public function render($request, Throwable $e)
{
$fatal = $e instanceof \Error; // (returns boolean)
if ($fatal) {
// do stuff here
}
return parent::render($request, $e);
}

php how do I set different types of throw errors

In JavaScript this is how I create throw errors if the parameter of a function is a invalid type.
function myFunction(num)
if (typeof(num) !== 'number') {
throw TypeError('num cannot be' + num);
}
}
How do I do this on PHP? I know there is a throw command but how do you set the error type. In the JavaScript example above I set it to be a TypeError, how do you set the error type for a PHP throw error and what are the error types in PHP?
function myFunction($num)
if (gettype($num) !== 'boolean') {
throw new Exception('$num cannot be ' , $num);;
}
}
PHP has exception classes much like JavaScript does.
function myFunction($num)
if (!is_bool($num)) {
throw new InvalidArgumentException('$num cannot be ' . $num);;
}
}
You can try create you custom exception exemple
final class CustomException extends \DomainException
{
public function __construct()
{
$this->message = 'My Custom Message';
$this->code = 400;
}
}
and use:
throw new CustomException();
or use generic exception
throw new \Exception('message', 400);
Exception have methods getMessage() and getCode()

Show Exception message when passing invalid argument type

I have a function
<?php
public function setStatusToReadyToShip(array $order_item_ids, $delivery_type, $shipping_provider = '', $tracking_number = '')
{
//code
}
Now I want the caller to call this method by providing $order_item_ids in array format.
One way i could do is to check is_array($order_item_ids) and send the error to the caller. But i am to utilize Type Hinting. How would i send the user the error response when using type hinting. As currently it crashes the application and says
exception 'ErrorException' with message 'Argument 1 passed to Class::SetStatusToReadyToShip() must be of the type array, integer given
I am not familiar with the try catch stuff that much. I tried placing try-catch inside this function so that it does not crash the application but the same output received.
Thanks
It is Catchable fatal error with constant E_RECOVERABLE_ERROR
There are 2 methods to solve this problem (at least two).
Create your own exception handler and set it as main error handler.
Make type validation in your function, and throw exception from it:
function setStatusToReadyToShip($order_item_ids, $delivery_type, $shipping_provider = '', $tracking_number = '')
{
if (!is_array($order_item_ids)) {
throw new InvalidArgumentException('First parameter of function '.__FUNCTION__.' must be array');
}
// your code
}
and than catch it
try {
setStatusToReadyToShip(5, 6);
} catch(InvalidArgumentException $e) {
var_dump($e->getMessage());
}
<?php
class YourClass {
public static function _init() {
set_error_handler('YourClass::_typeHintHandler');
}
public static function _typeHintHandler($errorCode, $errorMessage) {
throw new InvalidArgumentException($errorMessage);
}
public function setStatusToReadyToShip(array $order_item_ids, $delivery_type, $shipping_provider = '', $tracking_number = '')
{
}
}
YourClass::_init();
$yo = new YourClass();
try {
$yo->setStatusToReadyToShip("test");
}catch(Exception $e) {
print $e->getMessage();
}

Laravel check for constraint violation

I was curious if there is a way we can check if there is a constraint violation error when delete or insert a record into the database.
The exception thrown is called 'QueryException' but this can be a wide range of errors. Would be nice if we can check in the exception what the specific error is.
You are looking for the 23000 Error code (Integrity Constraint Violation). If you take a look at QueryException class, it extends from PDOException, so you can access to $errorInfo variable.
To catch this error, you may try:
try {
// ...
} catch (\Illuminate\Database\QueryException $e) {
var_dump($e->errorInfo);
}
// Example output from MySQL
array (size=3)
0 => string '23000' (length=5)
1 => int 1452
2 => string 'Cannot add or update a child row: a foreign key constraint fails (...)'
To be more specific (Duplicate entry, not null, add/update child row, delete parent row...), it depends on each DBMS:
PostgreSQL and SQL server follow the SQL standard's conventions for SQLSTATE code, so you may return the first value from the array $e->errorInfo[0] or call $e->getCode() directly
MySQL, MariaDB and SQLite do not strictly obey the rules, so you need to return the second value from the array $e->errorInfo[1]
For laravel, handling errors is easy, just add this code in your "app/start/global.php" file ( or create a service provider):
App::error(function(\Illuminate\Database\QueryException $exception)
{
$error = $exception->errorInfo;
// add your business logic
});
first put this in your controller
use Exception;
second handle the error by using try catch like this example
try{ //here trying to update email and phone in db which are unique values
DB::table('users')
->where('role_id',1)
->update($edit);
return redirect("admin/update_profile")
->with('update','update');
}catch(Exception $e){
//if email or phone exist before in db redirect with error messages
return redirect()->back()->with('phone_email','phone_email_exist before');
}
New updates here without need to use try catch you can easily do that in validation rules as the following code blew
public function update(Request $request, $id)
{
$profile = request()->all();
$rules = [
'name' => 'required|unique:users,id,'.$id,
'email' => 'required|email|unique:users,id,'.$id,
'phone' => 'required|unique:users,id,'.$id,
];
$validator = Validator::make($profile,$rules);
if ($validator->fails()){
return redirect()->back()->withInput($profile)->withErrors($validator);
}else{
if(!empty($profile['password'])){
$save['password'] = bcrypt($profile['password']);
}
$save['name'] = $profile['name'];
$save['email'] = $profile['email'];
$save['phone'] = $profile['phone'];
$save['remember_token'] = $profile['_token'];
$save['updated_at'] = Carbon::now();
DB::table('users')->where('id',$id)->update($save);
return redirect()->back()->with('update','update');
}
}
where id related to record which you edit.
You may also try
try {
...
} catch ( \Exception $e) {
var_dump($e->errorInfo );
}
then look for error code.
This catches all exception including QueryException
If you are using Laravel version 5 and want global exception handling of specific cases you should put your code in the report method of the /app/Exception/Handler.php file. Here is an example of how we do it in one of our micro services:
public function render($request, Exception $e)
{
$response = app()->make(\App\Support\Response::class);
$details = $this->details($e);
$shouldRenderHttp = $details['statusCode'] >= 500 && config('app.env') !== 'production';
if($shouldRenderHttp) {
return parent::render($request, $e);
}
return $response->setStatusCode($details['statusCode'])->withMessage($details['message']);
}
protected function details(Exception $e) : array
{
// We will give Error 500 if we cannot detect the error from the exception
$statusCode = 500;
$message = $e->getMessage();
if (method_exists($e, 'getStatusCode')) { // Not all Exceptions have a http status code
$statusCode = $e->getStatusCode();
}
if($e instanceof ModelNotFoundException) {
$statusCode = 404;
}
else if($e instanceof QueryException) {
$statusCode = 406;
$integrityConstraintViolation = 1451;
if ($e->errorInfo[1] == $integrityConstraintViolation) {
$message = "Cannot proceed with query, it is referenced by other records in the database.";
\Log::info($e->errorInfo[2]);
}
else {
$message = 'Could not execute query: ' . $e->errorInfo[2];
\Log::error($message);
}
}
elseif ($e instanceof NotFoundHttpException) {
$message = "Url does not exist.";
}
return compact('statusCode', 'message');
}
The Response class we use is a simple wrapper of Symfony\Component\HttpFoundation\Response as HttpResponse which returns HTTP responses in a way that better suits us.
Have a look at the documentation, it is straightforward.
You can add the following code in app/start/global.php file in order to print the exception
App::error(function(QueryException $exception)
{
print_r($exception->getMessage());
});
check this part in the documentation

How to change exception message of Exception object?

So I catch an exception (instance of Exception class) and what I want to do is change its exception message.
I can get the exception message like this:
$e->getMessage();
But how to set an exception message? This won't work:
$e->setMessage('hello');
For almost every single case under the sun, you should throw a new Exception with the old Exception attached.
try {
dodgyCode();
}
catch(\Exception $oldException) {
throw new MyException('My extra information', 0, $oldException);
}
Every once in a while though, you do actually need to manipulate an Exception in place, because throwing another Exception isn't actually what you want to do.
A good example of this is in Behat FeatureContext when you want to append additional information in an #AfterStep method. After a step has failed, you may wish to take a screenshot, and then add a message to the output as to where that screenshot can be seen.
So in order to change the message of an Exception where you can just replace it, and you can't throw a new Exception, you can use reflection to brute force the parameters value:
$message = " - My appended message";
$reflectionObject = new \ReflectionObject($exception);
$reflectionObjectProp = $reflectionObject->getProperty('message');
$reflectionObjectProp->setAccessible(true);
$reflectionObjectProp->setValue($exception, $exception->getMessage() . $message);
Here's that example the Behat in context:
/**
* Save screen shot on failure
* #AfterStep
* #param AfterStepScope $scope
*/
public function saveScreenShot(AfterStepScope $scope) {
if (!$scope->getTestResult()->isPassed()) {
try {
$screenshot = $this->getSession()->getScreenshot();
if($screenshot) {
$filename = $this->makeFilenameSafe(
date('YmdHis')."_{$scope->getStep()->getText()}"
);
$filename = "{$filename}.png";
$this->saveReport(
$filename,
$screenshot
);
$result = $scope->getTestResult();
if($result instanceof ExceptionResult && $result->hasException()) {
$exception = $result->getException();
$message = "\nScreenshot saved to {$this->getReportLocation($filename)}";
$reflectionObject = new \ReflectionObject($exception);
$reflectionObjectProp = $reflectionObject->getProperty('message');
$reflectionObjectProp->setAccessible(true);
$reflectionObjectProp->setValue($exception, $exception->getMessage() . $message);
}
}
}
catch(UnsupportedDriverActionException $e) {
// Overly specific catch
// Do nothing
}
}
}
Again, you should never do this if you can avoid it.
Source: My old boss
Just do this, it works I tested it.
<?php
class Exception2 extends Exception{
public function setMessage($message){
$this->message = $message;
}
}
$error = new Exception2('blah');
$error->setMessage('changed');
throw $error;
You can't change Exception message.
You can however determine it's class name and code, and throw a new one, of the same class, with same code, but with different message.
You can extend Exception and use the parent::__construct to set your message. This gets around the fact that you cannot override getMessage().
class MyException extends Exception {
function __construct() {
parent::__construct("something failed or malfunctioned.");
}
}
here a generified snippet i'm using.
foreach ($loop as $key => $value)
{
// foo($value);
thow new Special_Exception('error found')
}
catch (Exception $e)
{
$exception_type = get_class($e);
throw new $exception_type("error in $key :: " . $e->getMessage());
}
An ugly hack if you don't know which kind of exception you're handling (that can have its own properties) is to use reflection.
try {
// business code
} catch (\Exception $exception) {
$reflectedObject = new \ReflectionClass(get_class($exception));
$property = $reflectedObject->getProperty('message');
$property->setAccessible(true);
$property->setValue($exception, "new message");
$property->setAccessible(false);
throw $exception;
}
You should use this crap wisely in very specific case when you don't have any other choice.
You can't change the message given by the Exception class. If you wanted a custom message, you would need to check the error code using $e->getCode() and create your own message.
If you really wanted to do this (in the only situation I can think that you might want to do it), you could re-throw the exception:
function throwException() {
throw new Exception( 'Original' );
}
function rethrowException() {
try {
throwException();
} catch( Exception $e ) {
throw new Exception( 'Rethrow - ' . $e->getMessage() );
}
}
try {
rethrowException();
} catch( Exception $e ) {
echo $e->getMessage();
}
The php Exception class has a __toString() method which is the only method within the Exception class that is not final, meaning it can be customised.
class HelloMessage extends Exception {
function __toString() {
return $this->getMessage()." you have an error with code: ".$this->getCode();
}
}
You use it as follows within try-catch block:
try {
if (2 > 0) {
throw new HelloMessage("Hello", 10);
}
} catch (HelloMessage $e) {
echo $e;
}
Output would be:
Hello you have an error with code: 10
You can extend Exception with your own, and put a setter in it
class MyException extends Exception
{
private $myMessage = '';
public function getMessage()
{
if ($this->myMessage === '') {
return parent::getMessage();
} else {
return $this->myMessage;
}
public function setMessage($msg)
{
$this->myMessage = $msg;
}
}
This is an improved version of David Chan's answer. It's a re-throw solution which uses get_class to rethrow the same exception type, and it passes all parameters to the constructor, even in the case of ErrorException, which has six rather than three constructor parameters.
foreach ($loopvar as $key => $value)
{
doSomethingThatMightThrow($value);
}
catch (\Exception $e)
{
$exception_type = get_class($e);
$new_message = "[key '" . $key . "'] " . $e->getMessage();
if ($e instanceof \ErrorException) {
throw new $exception_type($new_message, $e->getCode(), $e->getSeverity(), $e->getFile(), $e->getLine(), $e);
}
throw new $exception_type($new_message, $e->getCode(), $e);
}

Categories