I am trying to implement exception handling in my application. For this Laravel framework has its own mechanism to handle the exception using report and render method. But to implement exception I need to track the source from where the exception has been raised e.g. specific page, route etc. For this I need to pass the url to report and render method but unable to do so. What needs to be done in order to implement this in below report and render function.
public function report(Exception $e)
{
parent::report($e);
}
public function render($request, Exception $e)
{
/* Token mismatch Exception handler start */
if ($e instanceof \Illuminate\Session\TokenMismatchException) {
return response()->view('errors.sessionExpire', [], 500);
}
/* Token mismatch Exception handler start */
return parent::render($request, $e);
}
As you can see from your own example, you have an instance of Request in the argument list. And Request has all request-specific details like current route, URL and so on.
$request->url(); // Current request URL
$request->fullUrl(); // With query parameters
$request->route(); // Get the route closure for this request path
You can also create your own exception classes that accept as many parameters as you wish!
And the less comfortable way already mentioned – you could go through the exception trace.
You need to use Exception::getTrace
var_dump($e->getTrace());
above line will give you all details regarding exception.
public function report(Exception $e){
echo '<pre>'; // add this line
print_r($e->getTrace()); // add this line
parent::report($e);
}
Related
I know why this exception is thrown, this is not the problem, but I am not capable to catch this exception.
This exception is thrown in CORE/src/Http/Middleware/CsrfProtectionMiddleware.php line #286:
if (!$cookie || !is_string($cookie)) {
throw new InvalidCsrfTokenException(__d('cake', 'Missing or incorrect CSRF cookie type.'));
}
When I check the long list of the stack in the CakePHP error window it's clear to me I cannot start to modify the CORE files as with the next CakePHP update/upgrade my modifications are lost.
The only script I can modify and should be easily handled is webroot/index.php. It's also mentioned in the call stack in the first position:
Cake\Http\Server->run ROOT/webroot/index.php:50
And here I am stuck. What ever I tried:
try/catch ( \Exception )
try/catch ( \Cake\Http\Exception\InvalidCsrfTokenException )
Using set_exception_handler()
nothing helps, this means, I always get the below error window. In this window you can see on the left the long call stack of scripts which are called until the exception is thrown. And this are even not all scripts. So it's really nested.
My question:
How can I catch this exception in the most top PHP script webroot/index.php - below this script are another 16 scripts called until the exception is thrown. I don't want to modify the CakePHP core files.
I am running CakePHP 4.1.4
You cannot catch that exception in index.php, as it is already being catched by the error handler middleware, which presents you that nice error screen, which however you'd only see in debug mode, in case that is your concern.
Your first chance to catch that exception would be a custom middleware, which you'd have to place between the error handler middleware and the CSRF protection middleware, something along the lines of this:
// in src/Application.php
public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
{
$middlewareQueue
->add(new ErrorHandlerMiddleware(Configure::read('Error')))
// ...
->add(function (
\Psr\Http\Message\ServerRequestInterface $request,
\Psr\Http\Server\RequestHandlerInterface $handler
) {
try {
// continue with the next middleware
return $handler->handle($request);
} catch (\Cake\Http\Exception\InvalidCsrfTokenException $exception) {
// handle the catched exception
$response = new \Cake\Http\Response();
return $response->withStringBody('Oh noes, CSRF error!');
}
})
// ...
->add(new CsrfProtectionMiddleware([
'httponly' => true,
]));
return $middlewareQueue;
}
So I want to cover all posible and unexpected errors (like 401, 404, 500) with just one view. I want the same view to show up on all possible errors. I came up with a solution - to copy/paste the same code and just name the views with different error codes. But that seems stiff and wrong. Is there a better way of achieving this?
In the file app/Exceptions/Handler.php you can change what happens when an exception is thrown. In particular there's a render method in there that you can use to catch all the exceptions in an application.
public function render($request, Exception $e)
{
// Handle your error here. Perhaps you can show a view
// when a condition is met. Anything that isn't caught
// here will be handled by Laravel with the
// parent::render call below
return parent::render($request, $e);
}
The parent::render($request, $e) is where Laravel would normally show it's exception/oops page. So by overriding this method you can catch all application errors, including 404, 401 etc.
A cleaner way to achieve this effect is by modifying Laravel's exception handler.
Modify App\Exceptions\Handler to catch every error and return your shared custom error page.
/**
* Render an exception into an HTTP response.
*
* #param \Illuminate\Http\Request $request
* #param \Exception $e
* #return \Illuminate\Http\Response
*/
public function render($request, Exception $e)
{
if ($e instanceof NotFoundHttpException) {
return response()->view('errors.custom', [], 404);
}
return parent::render($request, $e);
}
Some customization may be required to fully meet exactly what & how you want data passed to your shared custom view.
Pass the error code to your view on the handler, and display the code on your page, use a switch to handle all the messages depending on the error code.
You can create one unique view (default to 404 error), use try catch in your code to capture other errors and call to this view with parameters so you can change the 404 default error to other error.
I am new in zendframework. I am using apigility for rest services and ApiProblemListner to return the response if any error occures.
I have one function in model and this function just through an exception using php exception to use in catch block
I am using model function as the utility function in controller to catch those Exception. While catching exception I am using as
try{
imageUploade(); // this function in model and throwing exception if any error
}catch(\Exception $e){
return new ApiProblemResponse(new ApiProblem(500 , $e->getMessage()));
}
if imageUploade() throw an exception if the image size is more then I am able to catch the exception in catch block. I tried echo $e->getMessage(); and its printing the exception bt if I use new ApiProblem(500 , $e->getMessage()) it is not retuning the json error response with the 500 message. It is returning nothing. even it is not showing any error.
Seems like it is unable to render the error with this class. I am not sure if any event needs to add.
I have tried to search for documents but unable to find it.
Thanks in advance.
Normally it should work if you return an ApiProblemResponse straight from a controller action.
Are you sure your Api-Problem module is active?
Try once like this:
<?php
Application\Namespace;
use ZF\ApiProblem\ApiProblem;
use ZF\ApiProblem\ApiProblemResponse;
class IndexController
{
/**
* #return ApiProblemResponse
*/
public function indexAction()
{
return new ApiProblemResponse(new ApiProblem(500, 'test'));
}
}
If that doesn't work then I think your Api-Problem module is not running or the exception is never caught.
I have a repository that throws an exception if it can't find a record in the database. Rather than redirect to another page I just want to display a warning alert as the record is not critical to the page but is an "exceptional event".
It's probably best to demonstrate with code:
// FxRateRepositoy
public function getRate(/** args **/)
{
$rate = FxRate::where(.... //query to get the rate
if (!rate)
throw new NonExistentCurrencyException(//message);
return $rate;
}
In my start/global.php I have a handler:
App::error(function(NonExistentCurrencyException $e)
{
Session::flash('alert', $e->getMessage());
return \\ ??
});
What to return? I must return a response or the exception continue uncaught. I want to continue to the intended page but with the alert flashed in the session. Is this possible without having to use try catch blocks in every place this method is called?
Ass an additional question, assuming this exception may be thrown multiple times in one request, what's the best way to accumulate alert messages and display them? I'm thinking something akin to the validation messageBag. Can I just use the global $errors variable or should I create a new, specific messagebag for this purpose?
The problem is that if you return nothing from App::error Laravel will display it's default error page. On the other side you can't return a response because you don't know what response it should be in the error handler.
I suggest you handle it in the controller itself.
You can catch the exception there and flash the message or don't throw an exception at all:
$rate = FxRate::where(.... //query to get the rate
if (!rate){
Session::flash('alert', 'Whoops');
}
Also the findOrFail() and firstOrFail methods might be of use. They throw an ModelNotFoundException if the query yields no results:
try {
$rate = FxRate::where(....)->firstOrFail()
// and so on
} catch (Illuminate\Database\Eloquent\ModelNotFoundException $e){
Session::flash('alert', 'Whoops');
}
As for a messages system, take a look at the laracasts/flash package
Here is the exception I got:
No result was found for query although at least one row was expected.
I am basically getting that exception when a user id is not found in database.
Here is what my route looks like:
localhost/../user/18
and the code in my controller:
public function showAction(User $user){
// ..
}
I know I can use the kernel event exception to handle this, but is there an easier way to catch an exception generated by the ParamConverter?
In some cases it's useful to throw exception manually if object not found. You can tell action skip throw exception if entity not found by adding default value to param.
Example:
public function showUser(User $user = null) {
if (empty($user)) {
throw new CustomExceptionYouWant();
}
...
}
You can create your user ParamConverter by implementing ParamConverterInterface and inside it, create methods you can use as a custom exception or do other processing.
This a good exemple of what you want to create Custom ParamConverter