I was trying to explain the mediator pattern to a new developer, and ended up writing a simple event mediator. Thoughts?
EventMediator
class EventMediator {
private $events = array();
public function attach($event, Closure $callback) {
if(!is_string($event)) throw new \InvalidArgumentException();
$event = strtolower(trim($event));
if(!isset($this->events[$event])) $this->events[$event] = array();
$this->events[$event][] = $callback;
return $this;
}
public function trigger($event, $data = null) {
if(!is_string($event)) throw new \InvalidArgumentException();
$event = strtolower(trim($event));
if(!isset($this->events[$event])) return false;
foreach($this->events[$event] as $callback) $callback($event, $data);
return true;
}
public function getEvents() { return $this->events; }
}
EventfulTrait
trait EventfulTrait {
private $eventMediator;
public function attachEventMediator(EventMediator $eventMediator) {
$this->eventMediator = $eventMediator;
return $this;
}
public function detachEventMediator() {
$this->eventMediator = null;
return $this;
}
public function getEventMediator() {
return $this->eventMediator;
}
public function attachEvent($name, $callback) {
if(!is_null($this->eventMediator)) $this->eventMediator->attach($name, $callback);
return $this;
}
public function triggerEvent($name, $data = null) {
if(!is_null($this->eventMediator)) return $this->eventMediator->trigger($name, $data);
return false;
}
}
Example
require "EventMediator.php";
require "EventfulTrait.php";
class Log {
public function write($message) {
echo "{$message}\n";
}
}
class Eventful {
use EventfulTrait;
private $log;
public function __construct() { $this->log = new Log(); }
public function attachLoadEvent() {
$self = $this;
$log = $this->log;
$this->attachEvent(
"load", function() use($self, $log) {
$self->runOutOfNames();
$log->write("log message");
}
);
}
public function doSomething() {
$this->triggerEvent("load");
$this->triggerEvent("event1");
}
public function doSomethingElse() {
$this->triggerEvent("load");
$this->triggerEvent("event1");
$this->triggerEvent("event2");
}
public function runOutOfNames() { echo "load\n"; }
}
$eventMediator = new EventMediator();
$eventMediator->attach("event1", function() { echo "event1\n"; });
$eventMediator->attach("event2", function() { echo "event2\n"; });
$eventMediator->attach("done", function() { echo "done\n"; });
$eventful = new Eventful();
$eventful->attachEventMediator($eventMediator);
$eventful->attachLoadEvent();
$eventful->doSomething();
$eventful->doSomethingElse();
$eventMediator->trigger("load");
$eventMediator->trigger("done");
This will echo:
load
log message
event1
load
log message
event1
event2
load
log message
done