| 210 | | |
|---|
| 211 | | Recipes |
|---|
| 212 | | ------- |
|---|
| 213 | | |
|---|
| 214 | | This section lists some common usage of the event dispatcher. |
|---|
| 215 | | |
|---|
| 216 | | ### Doing something before or after a Method Call |
|---|
| 217 | | |
|---|
| 218 | | If you want to do something just before, or just after a method is |
|---|
| 219 | | called, you can notify respectively an event at the beginning or at |
|---|
| 220 | | the end of the method: |
|---|
| 221 | | |
|---|
| 222 | | [php] |
|---|
| 223 | | class Foo |
|---|
| 224 | | { |
|---|
| 225 | | // ... |
|---|
| 226 | | |
|---|
| 227 | | public function send($foo, $bar) |
|---|
| 228 | | { |
|---|
| 229 | | // do something before the method |
|---|
| 230 | | $event = new sfEvent($this, 'foo.do_before_send', array('foo' => $foo, 'bar' => $bar)); |
|---|
| 231 | | $this->dispatcher->notify($event); |
|---|
| 232 | | |
|---|
| 233 | | // the real method implementation is here |
|---|
| 234 | | // $ret = ...; |
|---|
| 235 | | |
|---|
| 236 | | // do something after the method |
|---|
| 237 | | $event = new sfEvent($this, 'foo.do_after_send', array('ret' => $ret)); |
|---|
| 238 | | $this->dispatcher->notify($event); |
|---|
| 239 | | |
|---|
| 240 | | return $ret; |
|---|
| 241 | | } |
|---|
| 242 | | } |
|---|
| 243 | | |
|---|
| 244 | | ### Adding Methods to a Class |
|---|
| 245 | | |
|---|
| 246 | | To allow multiple classes to add methods to another one, you can |
|---|
| 247 | | define the magic `__call()` method in the class you want to be |
|---|
| 248 | | extended like this: |
|---|
| 249 | | |
|---|
| 250 | | [php] |
|---|
| 251 | | class Foo |
|---|
| 252 | | { |
|---|
| 253 | | // ... |
|---|
| 254 | | |
|---|
| 255 | | public function __call($method, $arguments) |
|---|
| 256 | | { |
|---|
| 257 | | // create an event named 'foo.method_is_not_found' |
|---|
| 258 | | // and pass the method name and the arguments passed to this method |
|---|
| 259 | | $event = new sfEvent($this, 'foo.method_is_not_found', array('method' => $method, 'arguments' => $arguments)); |
|---|
| 260 | | |
|---|
| 261 | | // calls all listeners until one is able implements the $method |
|---|
| 262 | | $this->dispatcher->notifyUntil($event); |
|---|
| 263 | | |
|---|
| 264 | | // no listener was able to proces the event? The method does not exist |
|---|
| 265 | | if (!$event->isProcessed()) |
|---|
| 266 | | { |
|---|
| 267 | | throw new sfException(sprintf('Call to undefined method %s::%s.', get_class($this), $method)); |
|---|
| 268 | | } |
|---|
| 269 | | |
|---|
| 270 | | // return the listener returned value |
|---|
| 271 | | return $event->getReturnValue(); |
|---|
| 272 | | } |
|---|
| 273 | | } |
|---|
| 274 | | |
|---|
| 275 | | Then, create a class that will host the listener: |
|---|
| 276 | | |
|---|
| 277 | | [php] |
|---|
| 278 | | class Bar |
|---|
| 279 | | { |
|---|
| 280 | | public function addBarMethodToFoo(sfEvent $event) |
|---|
| 281 | | { |
|---|
| 282 | | // we only want to respond to the calls to the 'bar' method |
|---|
| 283 | | if ('bar' != $event['method']) |
|---|
| 284 | | { |
|---|
| 285 | | // let the opportunity to another listener to take care of this unknown method |
|---|
| 286 | | return false; |
|---|
| 287 | | } |
|---|
| 288 | | |
|---|
| 289 | | // the subject object (the foo instance) |
|---|
| 290 | | $foo = $event->getSubject(); |
|---|
| 291 | | |
|---|
| 292 | | // the bar method arguments |
|---|
| 293 | | $arguments = $event['parameters']; |
|---|
| 294 | | |
|---|
| 295 | | // do something |
|---|
| 296 | | // ... |
|---|
| 297 | | |
|---|
| 298 | | // set the return value |
|---|
| 299 | | $event->setReturnValue($someValue); |
|---|
| 300 | | |
|---|
| 301 | | // tell the world that you have processed the event |
|---|
| 302 | | return true; |
|---|
| 303 | | } |
|---|
| 304 | | } |
|---|
| 305 | | |
|---|
| 306 | | Eventually, add the new `bar` method to the `Foo` class: |
|---|
| 307 | | |
|---|
| 308 | | [php] |
|---|
| 309 | | $dispatcher->connect('foo.method_is_not_found', array($bar, 'addBarMethodToFoo')); |
|---|
| 310 | | |
|---|
| 311 | | ### Modifying Arguments |
|---|
| 312 | | |
|---|
| 313 | | If you want to allow third party classes to modify arguments passed |
|---|
| 314 | | to a method just before that method is executed, add a `filter` |
|---|
| 315 | | event at the beginning of the method: |
|---|
| 316 | | |
|---|
| 317 | | [php] |
|---|
| 318 | | class Foo |
|---|
| 319 | | { |
|---|
| 320 | | // ... |
|---|
| 321 | | |
|---|
| 322 | | public function render($template, $arguments = array()) |
|---|
| 323 | | { |
|---|
| 324 | | // filter the arguments |
|---|
| 325 | | $event = new sfEvent($this, 'foo.filter_arguments'); |
|---|
| 326 | | $this->dispatcher->filter($event, $arguments); |
|---|
| 327 | | |
|---|
| 328 | | // get the filtered arguments |
|---|
| 329 | | $arguments = $event->getReturnValue(); |
|---|
| 330 | | |
|---|
| 331 | | // the method starts here |
|---|
| 332 | | } |
|---|
| 333 | | } |
|---|
| 334 | | |
|---|
| 335 | | And here is an example of a filter: |
|---|
| 336 | | |
|---|
| 337 | | [php] |
|---|
| 338 | | class Bar |
|---|
| 339 | | { |
|---|
| 340 | | public function filterFooArguments(sfEvent $event, $arguments) |
|---|
| 341 | | { |
|---|
| 342 | | $arguments['processed'] = true; |
|---|
| 343 | | |
|---|
| 344 | | return $arguments; |
|---|
| 345 | | } |
|---|
| 346 | | } |
|---|