-1

I am using Symfony and i have created custom ExceptionListener to handle error.

class ExceptionListener
{
    protected $templating;
    protected $kernel;

    public function __construct(EngineInterface $templating, $kernel)
    {
        $this->templating = $templating;
        $this->kernel = $kernel;
    }

    public function onKernelException(GetResponseForExceptionEvent $event)
    {

            // exception object
            $exception = $event->getException();

            // new Response object
            $response = new Response();




          $response->setContent(
            // create you custom template AcmeFooBundle:Exception:exception.html.twig
                $this->templating->render(
                    'Exception/exception.html.twig',
                    array('exception' => $exception)
                )
            );

            // HttpExceptionInterface is a special type of exception
            // that holds status code and header details
            if ($exception instanceof HttpExceptionInterface) {
                $response->setStatusCode($exception->getStatusCode());
                $response->headers->replace($exception->getHeaders());

            } else {
                 $this->container->get('monolog.logger.db')->info('something happened 34', [
        'foo' => 'bar'
    ]);

                $response->setStatusCode(500);

            }
            if($exception instanceof FatalThrowableError){
                return  $this->templating->render(
                    'Exception/exception.html.twig'

                );

            }

            // set the new $response object to the $event
            $event->setResponse($response);

    }
}

and in service

 kernel.listener.acme_foo_exception_listener:
        class: AppBundle\Listener\ExceptionListener
        arguments: [@templating, @kernel]
        tags:
            - { name: kernel.event_listener, event: kernel.exception, method: onKernelException }

My aim is to when symfony throws exception i need to log error in database so i have created Logger event as per below link and it works fine when i called in controller but this event doesn't work when i called inside ExceptionListener.

I got following error

Notice: Undefined property: AppBundle\Listener\ExceptionListener::$container in

can any one help me how i can pass container inside Listener

scott
  • 3,112
  • 19
  • 52
  • 90
  • I suspect you copy/pasted your code from somewhere? Take a look at the docs for [dependency injection](https://symfony.com/doc/current/service_container.html). Then look at your code. You will perhaps notice that the constructor receives a $templating object. How the heck did that get in there? The @templating part of the service definition might offer some clue. So now I also need the logger (not the complete container). Could I do something similar to what was done for templating. And you might also ask why $kernel is being injected. – Cerad Feb 08 '18 at 15:11
  • @Cerad.i followed tutoral since i aM NEW TO SYMFONY. – scott Feb 08 '18 at 15:11
  • @vision: SF 2.x is deprecated. If you’re starting a new Symfony project, use either the latest 4.x branch or 3.4 LTS. – lxg Feb 08 '18 at 15:14
  • @lxg.ya its old project so i cant upgrate right now – scott Feb 08 '18 at 15:14

2 Answers2

1

Like the error says, you are trying to access a property that does not exist:

 $this->container->get('monolog.logger.db')->info('something happened 34', [
    'foo' => 'bar'
]);

The container property is never declared nor assigned. If you want to access your logging service inject it in your service definition, like you did with the templating and kernel services. Updated service definition:

    kernel.listener.acme_foo_exception_listener:
        class: AppBundle\Listener\ExceptionListener
        arguments: [@templating, @kernel, @monolog.logger.db]
        tags:
        - { name: kernel.event_listener, event: kernel.exception, method: onKernelException }

And update your class constructor to accept the log service as the third argument.

geoforce
  • 373
  • 2
  • 8
  • @geoforce.thanks for the answer.can you provide me code since m new to symfony – scott Feb 08 '18 at 15:13
  • @geoforce.Thanks for the update .is i have to pass MonologDBHandler $monologDBHandler in cosntructor – scott Feb 08 '18 at 15:22
  • i got following error,Fatal error: Uncaught Symfony\Component\Debug\Exception\FatalThrowableError: Type error: Argument 3 passed to AppBundle\Listener\ExceptionListener::__construct() must be an instance of AppBundle\Util\MonologDBHandler, instance of Symfony\Bridge\Monolog\Logger given, called in – scott Feb 08 '18 at 15:28
  • in my config i have following monolog: channels: ['db'] handlers: db: channels: ['db'] type: service id: monolog.db_handler – scott Feb 08 '18 at 15:29
  • and you configured the monolog.db_handler service as well? – geoforce Feb 08 '18 at 15:32
  • @geoforce.ya as per tutorial i configured . i dont know much about it.sorry for that – scott Feb 08 '18 at 15:33
  • can you show the monolog.db_handler service definition? – geoforce Feb 08 '18 at 15:36
  • try to change the constructor argument of your class type to Symfony\Bridge\Monolog\Logger. I assume monolog uses it as an interface to your custom handler – geoforce Feb 08 '18 at 15:39
  • @geoforcw.now i got Fatal error: Uncaught Symfony\Component\Debug\Exception\FatalThrowableError: Type error: Argument 3 passed to AppBundle\Listener\ExceptionListener::__construct() must be an instance of Symfony\Bridge\Monolog\Logger, instance of AppBundle\Util\MonologDBHandler given – scott Feb 08 '18 at 15:44
1

As said by geoforce your service doesn't know about the container. Quick fix for this by changing the service arguments:

arguments: [@templating, @container]

While changing the listener constructor to:

public function __construct(EngineInterface $templating, ContainerInterface $container)
{
    $this->container = $container;
    // ...

This should work, but injecting the entire container is quite an overkill and should definitely be done differently. Inject just what you need:

arguments: [@templating, '@monolog.logger.db']

And your constructor:

public function __construct(EngineInterface $templating, 
LoggerInterface $logger)
{
    $this->logger = $logger;
    // ...

Log with $this->logger->info(...).

Since you've said that you're new to Symfony, I'd heavily recommend reading the DI component (http://symfony.com/doc/current/components/dependency_injection.html) docs. Understanding what DI does and how it works is mandatory to work with MVC frameworks like Symfony.

nehalist
  • 1,434
  • 18
  • 45
  • @nehalist.thank you now it works fine.thank you so much .i have only one query can i change channel db to all if so how i can access monolog.logger.db as per your tutorial – scott Feb 08 '18 at 17:28
  • If you've injected the 'monolog.logger.db' service `$this->logger` is equivalent to `$this->container->get('monolog.logger.db')`, which means this is already your db channel logger. – nehalist Feb 08 '18 at 18:12
  • @nehalist.now i understood properly how logs working .thanks a lot – scott Feb 08 '18 at 18:33
  • @nehalist.if i enable dev mode i am getting error https://stackoverflow.com/questions/48723304/symfony-throwing-servicecircularreferenceexception – scott Feb 10 '18 at 17:08