Symfony2 Custom Events

Craig Blanchette on Google+ on October 26th 2012

First, you'll want to create your own custom event. You can easily do this by extending the Event class that comes with the EventDispatcher component. Once we've done this, you can add your own methods to the event that are useful to your implementation. For this example, we're going to make a Sitemap.xml generator by dispatching a custom event to all sitemap listeners. 


src/Acme/Bundle/ExampleBundle/Event/SitemapEvent.php
  1. namespace Acme\Bundle\ExampleBundle\Event;
  2.  
  3. use Symfony\Component\EventDispatcher\Event;
  4.  
  5. class SitemapEvent extends Event
  6. {
  7. private $pages = array();
  8.  
  9. public function addPage($path, $modified)
  10. {
  11. $this->pages[] = array(
  12. 'path' => $path,
  13. 'modified' => $modified
  14. );
  15. }
  16.  
  17. public function getPages()
  18. {
  19. return $this->pages;
  20. }
  21. }


Next, create the services that will be notified of this event. You can "tag" your services with the "kernel.event_listener" tag in order to tell Symfony that this service is an event listener. Use the event attribute to specify the event you are listening for, and optionally you can specify the method to call on this event. 


app/config/services.xml
  1. <services>
  2. <service id="acme.blog" class="Acme\Bundle\ExampleBundle\Blog">
  3. <tag name="kernel.event_listener" event="acme.events.sitemap" method="onSitemapEvent" />
  4. </service>
  5. </services>


Now create the actual service. We'll just pretend we have a blog service that contains multiple posts. In your implementation you will probably want to use the Routing component to generate your URL's instead of just hardcoding /blog/slug-name like below (or even better, just return a route and parameters and let the CrawlerController generate the URL with the Routing component.)


src/Acme/Bundle/ExampleBundle/Blog.php
  1. namespace Acme\Bundle\ExampleBundle;
  2. use Acme\Bundle\ExampleBundle\Event\SitemapEvent;
  3.  
  4. class Blog
  5. {
  6.  
  7. // Inject your services to the constructor etc..
  8.  
  9. public function onSitemapEvent(SitemapEvent $event) {
  10.  
  11. // Get blog posts..
  12.  
  13. foreach ($posts as $post) {
  14. $slug = sprintf('/blog/%s', $post->getSlug());
  15. $event->addPage($slug, $post->getLastModified());
  16. }
  17. }
  18. }


Finally, we can dispatch the event to all listeners. The resulting event object will contain any pages. You can tag as many services as you need to. 


src/Acme/Bundle/ExampleBundle/Controller/CrawlerController.php
  1. namespace Acme\Bundle\ExampleBundle\Controller;
  2.  
  3. use Symfony\Bundle\FrameworkBundle\Controller\Controller;
  4. use Acme\Bundle\ExampleBundle\Event\SitemapEvent;
  5.  
  6. class CrawlerController extends Controller
  7. {
  8. public function sitemapAction()
  9. {
  10. $event = new SitemapEvent();
  11. $dispatcher = $this->get('event_dispatcher');
  12. $dispatcher->dispatch('acme.events.sitemap', $event);
  13.  
  14. // Render sitemap.xml
  15. return $this->render('AcmeExampleBundle:Crawler:sitemap.xml.twig', array(
  16. 'pages' => $event->getPages(),
  17. ));
  18. }
  19. }