From my understanding there can only be one exception handler which will catch all unhandled exceptions. However, is there an elegant way to have a specific exception handler for Controllers A and B, and controllers C, D, etc. would be handled by default exception handler?
I don't think this is possible by default, other than creating a kernel eventlistener. However, you can create something simple yourself.
In a Controller Method, you might could do something like
public function index()
{
try {
// Do normal logic here.
} catch (\Exception $e) {
// Do whatever you want with any exception.
// Or Call your exception handler: MyExceptionHandler::handle()
}
}
You can also create a custom AbstractController so it might be a bit simpler. In which you extend the render function, so you abstract that logic away
Related
How can I catch any exceptions to cover the 100% code coverage report? This only covers the try condition in the code.
Controller
public function getItem()
{
try {
// Some code
return $result;
} catch (Exception $e) {
Log::error($e->getMessage());
throw new Exception ("$e->getMessage ()", 500);
}
}
Test file
public function testGetItem()
{
$this->get('api/getitem')->assertStatus(200);
}
Testing exceptions is easy in PHPUnit, but doesn't work like you'd expect in Laravel thanks to how it handles exceptions.
To test exceptions in Laravel you first need to disable Laravel exception handling - which if you extend the provided TestCase, you can do with the withoutExceptionHandling() method.
From there you can use PHPUnit's expectException() methods. Here's a small example.
use Tests\TestCase;
class ExceptionTest extends TestCase
{
public function testExceptionIsThrownOnFailedRequest()
{
// Disable exception handling for the test.
$this->withoutExceptionHandling();
// Expect a specific exception class.
$this->expectException(\Exception::class);
// Expect a specific exception message.
$this->expectExceptionMessage('Simulate a throw.');
// Expect a specific exception code.
$this->expectExceptionCode(0);
// Code that triggers the exception.
$this->get('/stackoverflow');
}
}
Now when the test is run, it'll disable Laravel's exception handling for this test run, then we set some expectations about what should happen, lastly, we call the code that'll fulfill those expectations, in this case, that's a get() call to route.
Now how the expectations are fulfilled will be up to your application.
Hi devs
I have a simple PHP OO project. I have an exception who appears 2 times.
Something like :
if (!$x) {
throw new Exception("Don't use this class here.");
}
I want to dev a class in order to edit this code like that :
if (!$x) {
throw new ClassUsageException();
}
How to dev the Excpetion class with default Exception message ?
Thanks
I'd advise creating new exception classes sparsly. It is no fun to check a multitude of exceptions left and right. And if you really feel the need, check what kinds of exceptions are already defined and where in that hierarchy your exception will fit and then extend that class, i.e. give the developers a chance to catch a (meaningful) range of exceptions without having to explicitly write one catch-block after the other.
I'm really not sure what you're trying to achieve here with Don't use this class here. but it could be an InvalidArgumentException (or something derived from that exception, if you really must). There are other mechanisms to prevent an instance of a certain class at a specific place though.
You can extend the Exception class
<?php
Class ClassUsageException extends Exception {
public function __construct($msg = "Don't use this class here.", $code = 0) {
parent::__construct($msg, $code); //Construct the parent thus Exception.
}
}
try {
throw new ClassUsageException();
} catch(ClassUsageException $e) {
echo $e->getMessage(); //Returns Don't use this class here.
}
I have an application in which my controllers are broken up into specific groups (API, CMS and front-end), this is already set up using Router groups. My question is how would one go about creating custom error handling for each group.
For example, when an exception occurs in any API controller action I would like to send back json with an error code and message, an exception in the CMS would output a detailed error page, and an exception on the front end would send the user to a generic 404 or 500 error page (as appropriate).
I am aware of how I could do this manually in each controller action, but that might get very repetitive. Ideally, I would want to create one handler for each and automatically use it across the board.
I am also aware of the App\Exceptions\Handler class, but if any of the controller groups could return a ModelNotFoundException, for example, how do I differentiate where the exception came from?
Is there another place that this type of exception handler could be inserted?
If you go to app\Exceptions\Handler.php file (which you mentioned) you can do it what you want.
You could for example define your render function this way:
public function render($request, Exception $e)
{
$trace = $e->getTraceAsString();
if ($e instanceof ModelNotFoundException
&& mb_strpos($trace, 'app\Http\Controllers\WelcomeController')
) {
return response()->json('Exception ' . $e->getMessage());
} elseif ($e instanceof ModelNotFoundException) {
return "General model not found";
}
return parent::render($request, $e);
}
and add to imports use Illuminate\Database\Eloquent\ModelNotFoundException;
and now if you throw ModelNotFoundException in your WelcomeController or you for example run another class' method from your WelcomeController and this method will throw ModelNotFoundException you can track it and return json response. In other cases if exception will be instance of ModelNotFoundException you can render your exception in other way and in all other cases you can use standard exception method to render.
This way you don't need to define anything in your controller, you can do it just in Handler and it it's more complicated you could create separate methods or create new classes to handle specific exceptions in the way you want and run them in this handler.
As well as many other, I'm trying to create my own MVC to improve my knowledge etc. :)
I'd like to ask about handling errors/exceptions in MVC pattern.
Dispatcher is getting information from Router about Route and getting Controller's and method's name from Route. Then dispatcher is trying to create instance of this Controller and execute this method.
Now let's imagine that our method is throwing exception (yes, it is not catched in method because of bad code :)). It could be custom made exception like NotFoundException or ApplicationInternalErrorException or one of SPL excpetions like RuntimeErrorException or InvalidArgumentException. It doesn't matter, really.
Of course, we want Dispatcher catch this exception, log it and respond accordingly exception type: display 404 page if NotFoundException was catched etc.
What is the best practice for doing it? Is Dispatcher a right place for doing it? Maybe the best place is FrontController (but I'm not using this pattern; Dispatcher is creating Controller instance.
Simple code:
class Dispatcher {
public function dispatch() {
$controller = $this->getRouter()->getController();
$method = $this->getRouter()->getMethod();
$args = $this->getRouter()->getArguments();
try {
call_user_func_array(array($controller, $method), array_values($args));
} catch (Exception $e) {
Logger::log($e->__toString);
if ($e instanceof NotFoundPage) {
call_user_func(array('ErrorController', 'notFound'))
} elseif ($e instanceof ...) {
...
} elseif ($e instanceof ...) {
...
} else {
...
}
}
}
}
Is it ok, or it is not a very good practice?
Thank you.
I'm simply using an external file (xml, yaml or anything you like) which contains all the routes for my web application. When a request comes the Router tries to match the request url to one of the routes I have in my file. If there were no match it simply redirects to the 404 page with a 404 header. I think that you don't need try/catch blocks for this.
I took the idea from Symfony.
Working on a symfony application that uses nusoap (is this the best method for integrating soap work with php/symfony?) for taking credit card payments.
I've simplified an example of my code below.
What I'm struggling with is the best way to handle exceptions. The example below only has 1 custom exception (where should my custom exceptions reside within the directory structure of symfony? (lib/exception?)) But what happens when there are several different types of exceptions that handle a specific error? It's not very elegant to have a try/catch block with 20 odd exceptions.
I'm also not sure of where I should be throwing and catching. I need to set some user flashes to alert the user of any problems, so I figure the catching should be done in the actions controller rather than within the class that handles the soap call.
Could anyone please advise where I might be going wrong?
I hate messy code/solutions and want to stick to the DRY principle as much as possible. I think I might also be missing some built in symfony functionality that might help with this but whenever I search I usually find examples that are for symfony 1.2, I'm using 1.4.
Some examples would be great, thanks.
lib/soap_payment.class.php
class SoapPayment
{
public function charge()
{
/*assume options are setup correctly for sake of example*/
try
{
$this->call();
}
catch (SoapPaymentClientFaultException $e)
{
/* should this be caught here? */
}
}
private function call()
{
$this->client->call($this->options);
if ($this->client->hasFault())
{
throw new SoapPaymentClientFaultException();
}
}
}
apps/frontend/payment/actions/actions.class.php
class paymentActions extends sfActions
{
public function executeCreate(sfWebRequest $request)
{
/* check form is valid etc */
$soap_payment = new SoapPayment();
try
{
$soap_payment->charge();
}
catch (SoapPaymentClientFaultException $e)
{
/* or throw/catch here? */
$this->getUser()->setFlash('error', ...);
$this->getLogger()->err(...);
}
/* save form regardless, will set a flag to check if successful or not in try/catch block */
}
}
One not very well known feature of Symfony is that exceptions can manage the content sent in a response. So you could do something like this:
class SoapException extends sfException
{
public function printStackTrace() //called by sfFrontWebController when an sfException is thrown
{
$response = sfContext::getInstance()->getResponse();
if (null === $response)
{
$response = new sfWebResponse(sfContext::getInstance()->getEventDispatcher());
sfContext::getInstance()->setResponse($response);
}
$response->setStatusCode(5xx);
$response->setContent('oh noes'); //probably you want a whole template here that prints the message that was a part of the SoapException
}
}
If you need a cleaner handling of SOAP exceptions, like setting flashes, etc. you'll probably have to catch each exception. One idea here might be to create a generic SoapException class that is extended by more specific SoapExceptions so you don't have to catch a bunch of different types. The above code may be a useful fallback mechanism as well.
Finally, yes, you should place custom exceptions in lib/exception.