Code snippets for symfony 1.x

Navigation

Refine Tags

Snippets tagged "doctrine event"

How to trigger an event from a Model Class

[UPDATE]

I've found a cleaner way to deal with it :

sfProjectConfiguration::getActive()->getEventDispatcher()->notify(new sfEvent($this, 'foo.bar'))
 

The old version of this snippet is now useless, you don't need to read it.

[/UPDATE]

This snippet is not a tutorial on symfony events, but you can find some documentation in the book and or in this good tutorial.

The event dispatcher is a very powerfull tool, but you might meet the same issue than me if you want to use it from a Model Class.

Let's take the classic Author/Article project sample.

When an article is added, it might be interesting to trigger an "article.new" event. This event coud be listened by different actors.

Like for instance :

The most obvious place to trigger the event is the Article save() method. Here is the code for Doctrine (the logic is exactly the same for Propel):

Article.class.php

public function save(Doctrine_Connection $conn = null)
{
  if ($this->isNew())
  {
    // Let's trigger the event
    sfContext::getInstance()->getEventDispatcher()->notify(new sfEvent($this, 'article.new'));
  }
  return parent::save($conn);
}
 

Unfortunatly, this code won't work. If you try the "symfony doctrine:build-all-reload" command, here is the error that will be displayed :

Cli

sfException: The "default" context does not exist.
 

Why ? Because symfony tasks don't initialise the sfContext class. And for the moment (symfony version 1.2.4) I don't think there's a clean way to access to the dispatcher object from a Doctrine Class.

Here is my solution : let's build a (very) little singleton class that will provide the dispatcher ressource everywhere in the project, and even when sfContext is not avaible

yourProjectRoot/lib/Fedex.class.php

class Fedex
{
  static protected $instance;
  protected $dispatcher;
  /**
   * The singleton logic http://en.wikipedia.org/wiki/Singleton_pattern#PHP_5
   */
  static public function getInstance()
  {
    if (!self::$instance instanceof self)
    {
      self::$instance = new self;
    }
    return self::$instance;
  }
 
  public function setEventDispatcher(sfEventDispatcher $dispatcher)
  {
    $this->dispatcher = $dispatcher;
  }
 
  public function getEventDispatcher()
  {
    return $this->dispatcher;
  }
}
 

Of course, you first have to give to the Fedex class a link the delivery ressource. Let's do it with the very first class called by the script of the project :

yourProjectRoot/config/ProjectConfiguration.class.php

public function setup()
{
  // add after all your setup stuffs
 
  require_once(dirname(__FILE__).'/../lib/Fedex.class.php');
  Fedex::getInstance()->setEventDispatcher($this->dispatcher);
}
 

That's it, you're done. The Fedex class will deliver the dispatcher ressource everywhere in your project through Fedex::getInstance()->getEventDispatcher() And it works even when the sfContext class is not avaible

Article.class.php

public function save(Doctrine_Connection $conn = null)
{
  if ($this->isNew())
  {
    Fedex::getInstance()->getEventDispatcher()->notify(new sfEvent($this, 'article.new'));
  }
  return parent::save($conn);
}
 

The important thing is that this little class doesn't modify any part of the symfony event system. It just provide you an alternative way to access to it.

by Éric Rogé on 2009-02-23, tagged doctrine  event  orm 
(5 comments)