In my services.yaml, I'm having this code:
services:
# prepare database
DatabaseProvider:
class: Kepler\Providers\DatabaseProvider
arguments: ['%database.reader.dsn%', '%database.reader.username%', '%database.reader.password%']
ReaderPDO:
class: PDO
factory: ['#DatabaseProvider', generateDatabaseConnection]
WriterPDO:
class: PDO
factory: ['#DatabaseProvider', generateDatabaseConnection]
And DatabaseProvider:generateDatabaseConnection
public function generateDatabaseConnection() {
try {
return new PDO($this->host, $this->username, $this->password);
} catch (Exception $e) {
return new PDO($this->host, $this->username, $this->password);
$_GLOBALS['db_error'] = true;
}
}
So my question is here: There will be cases where the PDO connection is not working/failing. So how I catch this exception and return the general 404 page (This is the page where I don't need any db connection)?
Some basic analysis:
I believe this is failing during symfony booting up
Even if I return null, or return nothing in the catch, the code will keep continue autowiring, which will then fail in Controller that requires DB connection
having a return in a catch block should be considered harmful if it's exactly the same thing to be returned as in the try block.
Setting a global value is really old-school and not really the symfony way. Instead, you would throw a specific exception (or just not catch the PDO one), and add an event listener for the kernel exception that will result from that, where you may look for that specific exception and return the proper error page you want.
If you just want the 404 page, you can throw the NotFoundHttpException or maybe more appropriate the ServiceUnavailableException ...
Related
I have the following exception:
<?php
namespace App\Exception;
class LimitReachedException extends \Exception
{
private ?\DateTime $resumeAt;
...getter/setter..
}
My PHPUnit check for this exception like this:
$this->expectException(LimitReachedException::class);
How can I check that a certain value is stored in the $resumeAt property as well?
Even though PHPUnit has a expectExceptionObject method that allows passing an exception instance, that is just a shortcut to expectExceptionMessage, expectException and expectExceptionCode.
One way to achieve your assertion as of now (current version of PHPUnit being 9.5.27) is to instead of using PHPUnit's methods of expecting that exception is to catch it yourself and then assert the different properties:
function testException () {
$expectedException = null;
try {
$foo->doSomething();
} catch (LimitReachedException $e) {
$expectedException = $e;
}
// Put your assertions outside of the `catch` block, otherwise
// your test won't fail when the exception isn't thrown
// (it will turn risky instead because there are no assertions)
$this->assertInstanceOf(LimitReachedException::class, $expectedException);
$this->assertSame('myExceptionProperty', $expectedException->getProperty());
}
I have a Symfony controller which basically checks if requested parameters are in the request, then passes these parameters to a service. The service use Guzzle to call an API, does some things with the result and then passes it back to the controller in order to display a Json with the response.
I have a noob question about the handling of errors, if the Api I call with Guzzle return an error, what is the best solution ?
Solution 1: Should I log the error using the Logger service injected in my own service and return an error to my controller in order to display it.
Solution 2: Should I throw an Exception in the service, catch it in my controller and use the $this->get("Logger") in the controller in order to log the error in log files
It would be nice if your core logic is itself in a service and not in your controller.
That way, you could use try-catch block inside the service where you call another service and your controller stays clean and neat - you just call the service without catching any exception.
// AppBundle/src/Controller/MainController.php
public function mainAction()
{
// ...
$result = $this->get('my_service')->getResult($parameters);
if (!$result) {
// show an error message, pass it to another service, ignore it or whatever you like
}
}
// AppBundle/src/Service/MyService.php
public function getResult($parameters)
{
try {
$apiResult = $this->apiService->get($parameters);
} catch (ApiException $e)
$this->logger->error('My error message');
$apiResult = null;
}
return $apiResult;
}
Consider also a Solution 3: Throw an exception in a service and catch it in a custom exception listener, where you can log it and take further action (like replacing the Response object, etc.).
I have an event listener hooked to kernel.request event. In the onKernel request method i am making some validations based on the subdomain.
If this validations fail I want to throw some exception like AccessDenied or something.
The problem is when I throw the exception it shows a blank page instead of my custom error page.
If I check my prod.log file I get the following info:
[2013-06-06 11:08:38] request.ERROR: Exception thrown when handling an exception (Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException: This route needs to be accessed with a subdomain) [] []
[2013-06-06 11:16:32] request.ERROR: Uncaught PHP Exception Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException: "This route needs to be accessed with a subdomain" at (...) line 86 [] []
What i am missing?
Thank you for your help
Exceptions are not catched during kernel.request events. You can return a response instead:
class SubdomainSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
'kernel.request' => 'onRequest',
];
}
public function onRequest(GetResponseEvent $event)
{
if (!$subdomainValid) {
$event->setResponse(new Response('Invalid subdomain!', 403));
}
}
}
Although this example is an EventSubscriber it works with a listener, too.
Is there any way in ASP.NET Web API to mark an exception as handled in an ExceptionFilterAttribute?
I want to handle the exception at the method level with an exception filter and stop the propagation to a globally registered exception filter.
Filter used on a controller action:
public class MethodExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Exception is NotImplementedException)
{
context.Response = new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent(context.Exception.Message)
};
// here in MVC you could set context.ExceptionHandled = true;
}
}
}
The globally registered filter:
public class GlobalExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Exception is SomeOtherException)
{
context.Response = new HttpResponseMessage(HttpStatusCode.SomethingElse)
{
Content = new StringContent(context.Exception.Message)
};
}
}
}
Try throwing an HttpResponseException at the end of your local handling. By design, they are not caught by exception filters.
throw new HttpResponseException(context.Response);
Web API 2 is designed with inversion of control in mind. You consider the possibility for the exception to already be handled, rather than interrupting the filter execution after you handle it.
In this sense, attributes deriving from ExceptionFilterAttribute should check if the exception is already handled, which your code already does since is operator returns false for null values. In addition, after you handle the exception, you set context.Exception to null in order to avoid further handling.
To achieve this in your code, you need to replace your comment from MethodExceptionFilterAttribute with context.Exception = null to clear the exception.
It is important to note that it is not a good idea to register more than one global exception filter, due to ordering issues. For information about the execution order of attribute filters in Web API, see the following thread Order of execution with multiple filters in web api.
My page calls a Services layer method that uses a Generic Repository "Find" method. In the services layer method, I do the following:
using (IUnitOfWork unitOfWork = new DBContext())
{
GenericRepository<Operator> operatorRepos = new GenericRepository<Operator>(unitOfWork);
{
try
{
var oper = operatorRepos.Find(o => o.OperatorID == operatorID).Include(o => o.cmn_Address).Single();
return oper;
}
catch (InvalidOperationException exc)
{
//handle exception
}
}
}
The Find method for my repository:
public IQueryable<T> Find(Func<T, bool> predicate)
{
return _objectSet.Where<T>(predicate).AsQueryable();
}
On the page, I try to access the cmn_address Navigation property of the Operator and I get the following error:
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
I realize that this is caused by the using statement to dispose of the context, but I thought the Include method will eager load the cmn_Address object. I don't understand why this doesn't work as I expected.
You are using Func<> instead of Expression<Func<>> in your where condition. That makes it Linq-to-objects. This change is permanent. Calling AsQueryable doesn't make it Linq-to-entities again.