[symfony-users] Re: Using sfEvent in propel objects. NOT behaviors
Hi, Using the sfContext instance in the model layer is a very often discussed topic in the last days. The latest one is this: http://groups.google.com/group/symfony-users/browse_thread/thread/75b9b1df4398b195?hl=en Fetching the context in the model is a very bad practise and you should find another way :) One solution might be that you could bind the currently existing dispatcher from your task to the model. The model checks if a dispatcher exists and fires events afterwards. Yeah, it's just another hack, but maybe better than the sfContext way (i do not like behaviours either, so i am open for every possible way). quick hacked: --- class MyModel { public function bindDispatcher( $dispatcher ) { $this->dispatcher = $dispatcher; } public function save() { $this->fireEvent( 'MyModel.pre_save', .); $tmp = parent::save(); $this->fireEvent( 'MyModel.post_save', .); } protected function fireEvent( $event, ) { if( $this->dispatcher ) { $dispatcher->notify($event, ); } } } --- Main problem: When you do not bind the dispatcher to the model, no event will be fired!!! Frank Am 26.06.2009 um 21:17 schrieb JoeZ: > > I just wanted to use the symfony 1.2 events extension mechanism with a > propel object. > > I know there are several other ways, like propel behaviors and so, but > I just don't want to use such a heavy machinery for what I want to do. > > I want an event to be fired when the method "setDesync()" of the > "recurringInvoice" propel object is called. This way, the app can take > some counter-measure when a recurring invoice goes out of sync for > some reason. > > In the docs, they introduce the "dispatcher" object like this: > > ... > class sfRestRequest > { > protected $dispatcher = null; > > public function __construct(sfEventDispatcher $dispatcher) > { >$this->dispatcher = $dispatcher; > } > > > } > > like if the $dispatcher is supposed to be automatically passed to the > class constructor. > well, maybe all the classes which inherits from sfRequest have that, > but it didn't work for my propel object, I guess the constructor > doesn't get any $dispatcher object passed to it by default. > > So I got it through the sfContext singleton: > > class RecurringInvoice extends BaseRecurringInvoice > ... > protected $dispatcher = null; > ... > > public function __construct() > { > $this->dispatcher = sfContext::getInstance()->getEventDispatcher(); > parent::__construct(); > } > > ... > ... > public function setDesync($v) > { > if($v) > { >$this->dispatcher->notify(new sfEvent > ($this,'recurring_invoice.desynchronized',array('id'=>$this->getId > (; > } > parent::setDesync($v); > > } > > it compiles at least. I didn't tested it yet, but when I used this > propel object inside a custom symfony task I was doing: > > class CheckJobsTask extends sfPropelBaseTask > { > . > . > public function execute($arguments = array(), $options = array()) > { > ... > (all usual stuff to access database objects, etc ...) > ... > $this->inv = new RecurringInvoice(); > > > } > > I got the infamious "the default context doesn't exists" error. > > I guessed it was because of the sfContext::getInstance call at the > propel object constructor, so I created the sfContext singleton within > the task: > > public function execute($arguments = array(), $options = array()) > { > ... > ... >$configuration = ProjectConfiguration::getApplicationConfiguration > ($options['application'], $options['env'], true); >sfContext::createInstance($configuration); > ... > $this->inv = new RecurringInvoice(); > ... > > } > > and it worked!!! > > but the thing is. I already now all the tasks are able to throw > events. that means the have some kind of access to the dispatcher , so > what I want to do is to access the dispatcher from the propel object > without having to make a call to the sfContext singleton, just using > something that allow me to integrate it within a task seamlessly . > > txs in advance. > > > --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups "symfony users" group. To post to this group, send email to symfony-users@googlegroups.com To unsubscribe from this group, send email to symfony-users+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/symfony-users?hl=en -~--~~~~--~~--~--~---
[symfony-users] Re: Using sfEvent in propel objects. NOT behaviors
Frank. You've got your point. The whole point of using this event for me is not to care about where is within the app code the invocation of the "setDesync(true)" method, but to just let it happen wherever it happens, and have some listener to act accordingly. In my understanding, what you say is to add a bindDispatcher() method to the propel object, and take care of calling it every time we use the object, or , at least, every time we use the object and it "may" fire the event we're interested in. Something like this: actions.class.php .. .. public execute() { $myObject = new myObject(); $myObject->bindDispatcher(sfContext::getInstance()->getDispatcher ()); ... } what I didn't like about your approach is the need of calling this "bindDispatcher" method every time the object is instantiated. As I told before, I just want to sit back and let the system capture the events for me. So I came out with this (I'm not yet sure it will work. I can tell you it compiles). class MyModel { protected function getDispatcher() { if($this->dispatcher) { return $this->dispatcher; } else { try { $configuration = sfProjectConfiguration::getActive(); $this->dispatcher = $configuration->getEventDispatcher(); return $this->dispatcher; } catch(RuntimeException $ex) { return null; } } } public function save() { $this->fireEvent( 'MyModel.pre_save', .); $tmp = parent::save(); $this->fireEvent( 'MyModel.post_save', .); } protected function fireEvent( $event, ) { if( $this->getDispatcher() ) { $this->getDispatcher()->notify($event, ); } } } } what's the point then?? If there is no active configuration, I'm screwed again. well, what I'm thinking is that the usual place to hook an event listener to is precisely the sfApplicationConfiguration class of the app. If there is no application, even if the event was fired, nobody would be there to capture it!! so It's more or less same ol'same ol. I've seen you around in the newsgroups talking about this, so I'm VERY interested in your opinion. On Jun 26, 4:40 pm, Frank Stelzer wrote: > Hi, > Using the sfContext instance in the model layer is a very often > discussed topic in the last days. The latest one is this: > > http://groups.google.com/group/symfony-users/browse_thread/thread/75b... > > Fetching the context in the model is a very bad practise and you > should find another way :) > > One solution might be that you could bind the currently existing > dispatcher from your task to the model. The model checks if a > dispatcher exists and fires events afterwards. > Yeah, it's just another hack, but maybe better than the sfContext way > (i do not like behaviours either, so i am open for every possible way). > > quick hacked: > --- > class MyModel > { > public function bindDispatcher( $dispatcher ) > { > $this->dispatcher = $dispatcher; > } > > public function save() > { > $this->fireEvent( 'MyModel.pre_save', .); > $tmp = parent::save(); > $this->fireEvent( 'MyModel.post_save', .); > } > > protected function fireEvent( $event, ) > { > if( $this->dispatcher ) > { > $dispatcher->notify($event, ); > } > } > > } > > --- > > Main problem: When you do not bind the dispatcher to the model, no > event will be fired!!! > > Frank > > Am 26.06.2009 um 21:17 schrieb JoeZ: > > > > > I just wanted to use the symfony 1.2 events extension mechanism with a > > propel object. > > > I know there are several other ways, like propel behaviors and so, but > > I just don't want to use such a heavy machinery for what I want to do. > > > I want an event to be fired when the method "setDesync()" of the > > "recurringInvoice" propel object is called. This way, the app can take > > some counter-measure when a recurring invoice goes out of sync for > > some reason. > > > In the docs, they introduce the "dispatcher" object like this: > > > ... > > class sfRestRequest > > { > > protected $dispatcher = null; > > > public function __construct(sfEventDispatcher $dispatcher) > > { > > $this->dispatcher = $dispatcher; > > } > > > > > } > > > like if the $dispatcher is supposed to be automatically passed to the > > class constructor. > > well, maybe all the classes which inherits from sfRequest have that, > > but it didn't work for my propel object, I guess the constructor > > doesn't get any $dispatcher object passed to it by default. > > > So I got it through the sfContext singleton: > > > class RecurringInvoice extends BaseRecurringInvoice > > ... > > protected $dispatcher = null; > > ... > > > public function __construct() > > { > > $this->dispatcher = sfContext::getInstance()->getEventDispatcher(); > > parent::__construct(); > > } > > > ... > > ... > > public function setDesync($v) > > { > > if($v) > >
[symfony-users] Re: Using sfEvent in propel objects. NOT behaviors
Hi Joe, On Thu, Jul 2, 2009 at 11:23 PM, JoeZ wrote: > So I came out with this (I'm not yet sure it will work. I can tell you > it compiles). You should never let your model rely on the context or on the configuration. Further more, you should try to avoid calling Singletons in the model, because your model will become very unflexible and erroneous then. I recently wrote a blog post about exactly this topic, if you are interested: http://webmozarts.com/2009/07/01/why-sfcontextgetinstance-is-bad/ If I was you, I would just use a setter like ->setEventDispatcher() to store the dispatcher in the object. When you try to fire the event, you check whether the dispatcher has been set. If it does not exist, you either 1. Throw an exception because the event MUST be fired, or 2. Don't fire the event Of course, you will then have to call ->setEventDispatcher() manually, but that'll result in a much better application design than "magically" accessing any objects from inside. FYI, you should not use sfContext::getInstance() in the action either. The action does already have a reference to the context: public executeWhatever() { $myObject = new myObject(); $myObject->setEventDispatcher($this->context->getEventDispatcher()); } Bernhard --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups "symfony users" group. To post to this group, send email to symfony-users@googlegroups.com To unsubscribe from this group, send email to symfony-users+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/symfony-users?hl=en -~--~~~~--~~--~--~---