![]() |
|
Snippets |
|
[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.