I want to do some post-processing after sending a response object in my Symfony controller. Problem is, the post-processing requires other methods contained in my controller object. I'd like to do something like this:
public function testAction() {
$dispatcher = new EventDispatcher();
$dispatcher->addListener('kernel.terminate', function (Event $event) {
$controller->get('logger');
$logger->info('hello');
});
return new Response();
}
How can I inject the $controller variable into my kernel.terminate post-processing?
it seems you need only the container in your service. To get the container injected into your event listener I prefer to create a separate EventListener which you have to register in your container see code:
First create event listener class:
<?php
namespace Acme\DemoBundle\Listener;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\DependencyInjection\ContainerInterface;
class RequestListener
{
protected $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function onKernelRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
$logger = $this->container->get('logger')->getToken();
$logger->info('.....');
}
}
As you can see, we have now the service container injected and we are able to use it.
Next you have to register the service and inject the service container:
services:
acme.demo.listener.request:
class: Acme\DemoBundle\Listener\RequestListener
arguments: [ #service_container ]
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
Notice in your case you have to select the event you wanna inject to. In my case I used the kernel.request event. You have to select the kernel.terminate event.
That can also be helpful: http://symfony.com/doc/current/cookbook/service_container/event_listener.html
Related
This is the first time ever I am working with creating custom event dispatcher and subscriber so I am trying to wrap my head around it and I cant seem to find out why my custom event is not being dispatched.
I am following the documentation and in my case I need to dispatch an event as soon as someone registers on the site.
so inside my registerAction() I am trying to dispatch an event like this
$dispatcher = new EventDispatcher();
$event = new RegistrationEvent($user);
$dispatcher->dispatch(RegistrationEvent::NAME, $event);
This is my RegistrationEvent class
namespace AppBundle\Event;
use AppBundle\Entity\User;
use Symfony\Component\EventDispatcher\Event;
class RegistrationEvent extends Event
{
const NAME = 'registration.complete';
protected $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function getUser(){
return $this->user;
}
}
This is my RegistrationSubscriber class
namespace AppBundle\Event;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class RegistrationSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return array(
KernelEvents::RESPONSE => array(
array('onKernelResponsePre', 10),
array('onKernelResponsePost', -10),
),
RegistrationEvent::NAME => 'onRegistration'
);
}
public function onKernelResponsePre(FilterResponseEvent $event)
{
// ...
}
public function onKernelResponsePost(FilterResponseEvent $event)
{
// ...
}
public function onRegistration(RegistrationEvent $event){
var_dump($event);
die;
}
}
After doing this, I was hoping that the registration process would stop at the function onRegistration but that did not happen, I then looked at the Events tab of the profiler and I do not see my Event listed their either.
What am I missing here? A push in right direction will really be appreciated.
Update:
I thought i need to register a service for the custom event so I added the following code inside services.yml
app.successfull_registration_subscriber:
class: AppBundle\Event\RegistrationSubscriber
arguments: ["#doctrine.orm.entity_manager"]
tags:
- { name: kernel.event_subscriber}
Inside the Event tab of profiler I do see my custom event being listed but it still does not dispatch.
By creating your own EventDispatcher instance you dispatch an event that can never be listened to by other listeners (they are not attached to this dispatcher instance). You need to use the event_dispatcher service to notify all listeners you have tagged with the kernel.event_listener and kernel.event_subscriber tags:
// ...
class RegistrationController extends Controller
{
public function registerAction()
{
// ...
$this->get('event_dispatcher')->dispatch(RegistrationEvent::NAME, new RegistrationEvent($user););
}
}
Duplicate of dispatcher doesn't dispatch my event symfony
With auto-wiring, it is now better to inject the EventDispatcherInterface
<?php
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
//...
class DefaultController extends Controller
{
public function display(Request $request, EventDispatcherInterface $dispatcher)
{
//Define your event
$event = new YourEvent($request);
$dispatcher->dispatch(YourEvent::EVENT_TO_DISPATCH, $event);
}
}
I am currently using the Symfony2 event listener to change the controller to a different one based on a users authentication status. I get the listener to set the new controller but it is instantiated without the container parameter (i.e. $this->container returns null).
Is there anyway to pass the container on to the controller I am changing to?
class AuthenticationListener
{
public function onController(FilterControllerEvent $event)
{
$request = $event->getRequest();
$session = $request->getSession();
if (!$session->has('authenticated') || $session->get('authenticated') === false)
{
$controller = $event->getController();
if (!($controller[0] instanceof AuthenticateController) && !($controller[0] instanceof ExceptionController))
{
$event->setController(array(new AuthenticateController(), 'loginAction'));
}
}
}
}
The container is not set, when you create the controller automatically. Call setContainer after constructing the controller. Afterwards you can pass it to the event.
In this case AuthenticationListener its just a class
if you want to use $this->container in this class you must do like this:
class BeforeControllerListener extends ContainerAware
{
...
}
and in config.yml
core.listener.before_controller:
class: App\YourBundle\EventListener\YourListener
tags: [ {name: kernel.event_listener, event: kernel.controller, method: onKernelController}]
calls:
- [ setContainer,[ #service_container ]]
Is there a way on Symfony2 to call a controller function on each page load? At the momment my solution is using an ajax call, but i'll like to solve this all in the backend part. (ofcourse without having to copy the function name on each controller function)
You can create Event Listener and handle KernelEvents::CONTROLLER event with it (before filter), as described here.
Example:
Acme\DemoBundle\EventListener\DemoListener.php
namespace Acme\DemoBundle\EventListener;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
class DemoListener
{
public function onKernelController(FilterControllerEvent $event)
{
$controller = $event->getController();
/*
* $controller passed can be either a class or a Closure.
* This is not usual in Symfony2 but it may happen.
* If it is a class, it comes in array format
*/
if (!is_array($controller)) {
return;
}
$controller[0]->fooBarMethod();
}
}
Acme\DemoBundle\Resources\services.yml
parameters:
acme_demo.event_listener.class: Acme\DemoBundle\EventListener\DemoListener
services:
acme_demo.event_listener:
class: %acme_demo.event_listener.class%
tags:
- { name: kernel.event_listener, event: kernel.controller, method: onKernelController }
I have a program with two bundles. One of them (CommonBundle) dispatches an event "common.add_channel", while a service on the other one (FetcherBundle) was supposed to be listening to it. On the profiler, I can see the event common.add_channel in the "Not Called Listeners" section. I don't get why symfony is not registering my listener.
This is my action, inside CommonBundle\Controller\ChannelController::createAction:
$dispatcher = new EventDispatcher();
$event = new AddChannelEvent($entity);
$dispatcher->dispatch("common.add_channel", $event);
This is my AddChannelEvent:
<?php
namespace Naroga\Reader\CommonBundle\Event;
use Symfony\Component\EventDispatcher\Event;
use Naroga\Reader\CommonBundle\Entity\Channel;
class AddChannelEvent extends Event {
protected $_channel;
public function __construct(Channel $channel) {
$this->_channel = $channel;
}
public function getChannel() {
return $this->_channel;
}
}
This was supposed to be my listener (FetcherService.php):
<?php
namespace Naroga\Reader\FetcherBundle\Service;
class FetcherService {
public function onAddChannel(AddChannelEvent $event) {
die("It's here!");
}
}
And here's where I register my listener (services.yml):
kernel.listener.add_channel:
class: Naroga\Reader\FetcherBundle\Service\FetcherService
tags:
- { name: kernel.event_listener, event: common.add_channel, method: onAddChannel }
What am I doing wrong? Why isn't symfony calling the event listener when I dispatch common.add_channel?
The new event dispatcher doesn't know anything about the listeners set on another dispatcher.
In your controller, you need to access the event_dispatcher service. A Compiler Pass of the Framework Bundle attached all listeners to this dispatcher. To get the service, use the Controller#get() shortcut:
// ...
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class ChannelController extends Controller
{
public function createAction()
{
$dispatcher = $this->get('event_dispatcher');
// ...
}
}
I want to create custom events called user_logged so that i can attach my listeners to those events.
I want to execute few functions whenever user has logged in.
Create a class which extends Symfony\Component\EventDispatcher\Event.
Then, use the event dispatcher service to dispatch the event:
$eventDispatcher = $container->get('event_dispatcher');
$eventDispatcher->dispatch('custom.event.identifier', $event);
You can register your event listener service like so:
tags:
- { name: kernel.event_listener, event: custom.event.identifier, method: onCustomEvent }
This answer is little bit extend answer.
services.yml
custom.event.home_page_event:
class: AppBundle\EventSubscriber\HomePageEventSubscriber
tags:
- { name: kernel.event_listener, event: custom.event.home_page_event, method: onCustomEvent }
AppBundle/EventSubscriber/HomePageEventSubscriber.php
namespace AppBundle\EventSubscriber;
class HomePageEventSubscriber
{
public function onCustomEvent($event)
{
var_dump($event->getCode());
}
}
AppBundle/Event/HomePageEvent.php
namespace AppBundle\Event;
use Symfony\Component\EventDispatcher\Event;
class HomePageEvent extends Event
{
private $code;
public function setCode($code)
{
$this->code = $code;
}
public function getCode()
{
return $this->code;
}
}
anywhere you wish, for example in home page controller
use AppBundle\Event\HomePageEvent;
// ...
$eventDispatcher = $this->get('event_dispatcher');
$event = new HomePageEvent();
$event->setCode(200);
$eventDispatcher->dispatch('custom.event.home_page_event', $event);