Skip to content
This repository has been archived by the owner on Nov 9, 2017. It is now read-only.

Commit

Permalink
[event_dispatcher] splitted the first chapter to create a new Recipes…
Browse files Browse the repository at this point in the history
… chapter with one new recipe (refs #6744)

git-svn-id: http://svn.symfony-project.com/components/event_dispatcher/trunk@19857 ee427ae8-e902-0410-961c-c3ed070cd9f9
  • Loading branch information
fabien committed Jul 3, 2009
1 parent eaf545e commit 7f12f75
Show file tree
Hide file tree
Showing 2 changed files with 190 additions and 137 deletions.
137 changes: 0 additions & 137 deletions doc/01-Event-Dispatcher.markdown
Expand Up @@ -207,140 +207,3 @@ The notifier can get the filtered value by calling the

[php]
$ret = $event->getReturnValue();

Recipes
-------

This section lists some common usage of the event dispatcher.

### Doing something before or after a Method Call

If you want to do something just before, or just after a method is
called, you can notify respectively an event at the beginning or at
the end of the method:

[php]
class Foo
{
// ...

public function send($foo, $bar)
{
// do something before the method
$event = new sfEvent($this, 'foo.do_before_send', array('foo' => $foo, 'bar' => $bar));
$this->dispatcher->notify($event);

// the real method implementation is here
// $ret = ...;

// do something after the method
$event = new sfEvent($this, 'foo.do_after_send', array('ret' => $ret));
$this->dispatcher->notify($event);

return $ret;
}
}

### Adding Methods to a Class

To allow multiple classes to add methods to another one, you can
define the magic `__call()` method in the class you want to be
extended like this:

[php]
class Foo
{
// ...

public function __call($method, $arguments)
{
// create an event named 'foo.method_is_not_found'
// and pass the method name and the arguments passed to this method
$event = new sfEvent($this, 'foo.method_is_not_found', array('method' => $method, 'arguments' => $arguments));

// calls all listeners until one is able implements the $method
$this->dispatcher->notifyUntil($event);

// no listener was able to proces the event? The method does not exist
if (!$event->isProcessed())
{
throw new sfException(sprintf('Call to undefined method %s::%s.', get_class($this), $method));
}

// return the listener returned value
return $event->getReturnValue();
}
}

Then, create a class that will host the listener:

[php]
class Bar
{
public function addBarMethodToFoo(sfEvent $event)
{
// we only want to respond to the calls to the 'bar' method
if ('bar' != $event['method'])
{
// let the opportunity to another listener to take care of this unknown method
return false;
}

// the subject object (the foo instance)
$foo = $event->getSubject();

// the bar method arguments
$arguments = $event['parameters'];

// do something
// ...

// set the return value
$event->setReturnValue($someValue);

// tell the world that you have processed the event
return true;
}
}

Eventually, add the new `bar` method to the `Foo` class:

[php]
$dispatcher->connect('foo.method_is_not_found', array($bar, 'addBarMethodToFoo'));

### Modifying Arguments

If you want to allow third party classes to modify arguments passed
to a method just before that method is executed, add a `filter`
event at the beginning of the method:

[php]
class Foo
{
// ...

public function render($template, $arguments = array())
{
// filter the arguments
$event = new sfEvent($this, 'foo.filter_arguments');
$this->dispatcher->filter($event, $arguments);

// get the filtered arguments
$arguments = $event->getReturnValue();

// the method starts here
}
}

And here is an example of a filter:

[php]
class Bar
{
public function filterFooArguments(sfEvent $event, $arguments)
{
$arguments['processed'] = true;

return $arguments;
}
}
190 changes: 190 additions & 0 deletions doc/02-Recipes.markdown
@@ -0,0 +1,190 @@
Recipes
=======

This chapter lists common usages of the event dispatcher.

Passing along the Event Dispatcher Object
-----------------------------------------

If you have a look at the `sfEventDispatcher` class, you will notice
that the class does not act as a Singleton (there is no
`getInstance()` static method). That's on purpose as you might want
to have several concurrent event dispatchers in a single PHP
request. But it also means that you need a way to pass the
dispatcher to the objects that need to connect or notify events.

The best practice is to inject the event dispatcher object into your
objects, aka dependency injection.

You can use constructor injection:

[php]
class Foo
{
protected $dispatcher = null;

public function __construct(sfEventDispatcher $dispatcher)
{
$this->dispatcher = $dispatcher;
}
}

Or setter injection:

[php]
class Foo
{
protected $dispatcher = null;

public function setEventDispatcher(sfEventDispatcher $dispatcher)
{
$this->dispatcher = $dispatcher;
}
}

Choosing between the two is really a matter of taste. I tend to
prefer the constructor injection as the objects are fully
initialized at construction time. But when you have a long list of
dependencies, using setter injection can be the way to go,
especially for optional dependencies.

>**TIP**
>If you use dependency injection like we did in the two examples above,
>you can then easily use the Symfony Dependency Injection container to
>elegantly manages these objects.
Doing something before or after a Method Call
---------------------------------------------

If you want to do something just before, or just after a method is
called, you can notify respectively an event at the beginning or at
the end of the method:

[php]
class Foo
{
// ...

public function send($foo, $bar)
{
// do something before the method
$event = new sfEvent($this, 'foo.do_before_send', array('foo' => $foo, 'bar' => $bar));
$this->dispatcher->notify($event);

// the real method implementation is here
// $ret = ...;

// do something after the method
$event = new sfEvent($this, 'foo.do_after_send', array('ret' => $ret));
$this->dispatcher->notify($event);

return $ret;
}
}

Adding Methods to a Class
-------------------------

To allow multiple classes to add methods to another one, you can
define the magic `__call()` method in the class you want to be
extended like this:

[php]
class Foo
{
// ...

public function __call($method, $arguments)
{
// create an event named 'foo.method_is_not_found'
// and pass the method name and the arguments passed to this method
$event = new sfEvent($this, 'foo.method_is_not_found', array('method' => $method, 'arguments' => $arguments));

// calls all listeners until one is able implements the $method
$this->dispatcher->notifyUntil($event);

// no listener was able to proces the event? The method does not exist
if (!$event->isProcessed())
{
throw new sfException(sprintf('Call to undefined method %s::%s.', get_class($this), $method));
}

// return the listener returned value
return $event->getReturnValue();
}
}

Then, create a class that will host the listener:

[php]
class Bar
{
public function addBarMethodToFoo(sfEvent $event)
{
// we only want to respond to the calls to the 'bar' method
if ('bar' != $event['method'])
{
// let the opportunity to another listener to take care of this unknown method
return false;
}

// the subject object (the foo instance)
$foo = $event->getSubject();

// the bar method arguments
$arguments = $event['parameters'];

// do something
// ...

// set the return value
$event->setReturnValue($someValue);

// tell the world that you have processed the event
return true;
}
}

Eventually, add the new `bar` method to the `Foo` class:

[php]
$dispatcher->connect('foo.method_is_not_found', array($bar, 'addBarMethodToFoo'));


Modifying Arguments
-------------------

If you want to allow third party classes to modify arguments passed
to a method just before that method is executed, add a `filter`
event at the beginning of the method:

[php]
class Foo
{
// ...

public function render($template, $arguments = array())
{
// filter the arguments
$event = new sfEvent($this, 'foo.filter_arguments');
$this->dispatcher->filter($event, $arguments);

// get the filtered arguments
$arguments = $event->getReturnValue();

// the method starts here
}
}

And here is an example of a filter:

[php]
class Bar
{
public function filterFooArguments(sfEvent $event, $arguments)
{
$arguments['processed'] = true;

return $arguments;
}
}

0 comments on commit 7f12f75

Please sign in to comment.