Ok... ya tengo un prototipo funcionando.
Para esto he utilizado aquel framework de ActiveRecord que había creado "PHP5DbObject".
El ejemplo que he utilizado: Un torneo (uno muy corto).
En mi BD he creado tres tablas:
Código PHP:
desc cup;
+--------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | | |
| winner | int(11) | YES | | NULL | |
+--------+--------------+------+-----+---------+----------------+
desc game;
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| cup_id | int(11) | NO | | | |
| play_date | datetime | YES | | NULL | |
| team_home | int(11) | YES | | NULL | |
| team_visit | int(11) | YES | | NULL | |
| winner | int(11) | YES | | NULL | |
| result | varchar(255) | YES | | NULL | |
+------------+--------------+------+-----+---------+----------------+
desc listen; // Utilizada por el Messenger
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| event_name | varchar(255) | NO | | | |
| source | varchar(255) | NO | | | |
| interested | varchar(255) | NO | | | |
| params | text | NO | | | |
+------------+--------------+------+-----+---------+----------------+
Luego he creado este par de clases: Cup y Game... cada una extiende de la clase de acceso a DB que PHP5DBObject crea CupDB y GameDB respectivamente.
Código PHP:
class Game extends GameDB {
public function setHomeAsWinnerOf(&$game) {
Messenger::getInstance()->interestedIn('WinnerOfGame', $game, $this, array('setas' => 'home'));
}
public function setVisitorAsWinnerOf(&$game) {
Messenger::getInstance()->interestedIn('WinnerOfGame', $game, $this, array('setas' => 'visitor'));
}
public function setWinnerAs($team) {
if ($team == 'home') $this->winner = $this->team_home;
else $this->winner = $this->team_visit;
print "<hr><strong>The $team team won game " . $this->id . "!!</strong>";
$this->update();
Messenger::getInstance()->notify('WinnerOfGame', $this);
Messenger::getInstance()->notify('LooserOfGame', $this);
}
public function setHomeTeam($team) {
print "Now the home team of game " . $this->id . " is " . $team . "<br>";
$this->team_home = $team;
$this->update();
}
public function setVisitorTeam($team) {
print "Now the visitor team of game " . $this->id . " is " . $team . "<br>";
$this->team_visitor = $team;
$this->update();
}
public function listener($event, &$source, $params = array()) {
switch($event) {
case 'WinnerOfGame':
print "Game id: " . $this->id . " is being notified of a winner.<br>";
print "It's the result of game: " . $source->id . " and it's team " . $source->getWinner() . "<br>";
print "Params : <pre>" . print_r($params, true) . "</pre>";
if ($params['setas'] == 'home') $this->setHomeTeam($source->winner);
else $this->setVisitorTeam($source->winner);
}
}
}
class Cup extends CupDB {
public function setFinal(&$game) {
Messenger::getInstance()->interestedIn('WinnerOfGame', $game, $this, array(''));
}
public function listener($event, &$source, $params = array()) {
switch($event) {
case 'WinnerOfGame':
print "Cup id: " . $this->id . " is being notified of a winner.<br>";
print "It's the result of game: " . $source->id . " and it's team " . $source->getWinner() . "<br>";
print "Params : <pre>" . print_r($params, true) . "</pre><br>";
$this->winner = $source->winner;
print "<H1>Congratulations team " . $this->winner . ". Yuo Won the <em>" . $this->name . "</em></h1>";
$this->update();
}
}
}
Y finalmente mi clase Messenger. Esta clase aprovecha las bondades de PHP5DBObject para cargar la instancia del objeto que debe ser notificado con el método PHP5DBObject::factory($class_name, $id);
Código PHP:
class Messenger {
protected static $instance = null;
public static function &getInstance() {
if (!is_object(self::$instance)) {
self::$instance = new Messenger();
}
return self::$instance;
}
function __construct() {
if (is_object(self::$instance)) throw new Exception(__CLASS__ . ' is singleton. You shouldn\'t call it directly but using the static method ' . __CLASS__ . '::getInstance()');
}
function notify($event_name, &$source) {
print "<hr>";
print "Notifying of event $event_name by " . get_class($source) . '@' . http_build_query($source->getArrayId()) . "<br>";
$listeners = Listen::browse('event_name=? AND source=?', array($event_name, get_class($source) . '@' . http_build_query($source->getArrayId())));
if (count($listeners) == 0) {
print "Who cares... :P <br>";
return;
}
foreach($listeners as $listener) {
list($class, $id) = split('@', $listener->interested, 2);
parse_str($listener->params, $params);
parse_str($id, $array_id);
$null = null;
$obj =& PHP5DBObject::factory($class, $array_id, $null);
$obj->listener($event_name, $source, $params);
}
}
function interestedIn($event_name, &$source, &$interested, $params = array()) {
$l = new Listen();
$l->event_name = $event_name;
$l->source = get_class($source) . '@' . http_build_query($source->getArrayId());
$l->interested = get_class($interested) . '@' . http_build_query($interested->getArrayId());
if (count($params) == 0) $l->params = '';
else $l->params = http_build_query($params);
$l->create();
}
}
Hecho todo esto, Este es el php que ejecuto.... que pico en varias partes para que se vea su funcionamiento:
Código PHP:
// Incluimos lo necesario
$cup = new Cup();
$cup->setName("TEST Cup");
$cup->create();
$game1 = new Game();
$game1->setCup($cup);
$game1->setPlay_date('2008-03-20');
$game1->setTeam_home(1);
$game1->setTeam_visit(2);
$game1->create();
$game2 = new Game();
$game2->setCup($cup);
$game2->setPlay_date('2008-03-20');
$game2->setTeam_home(3);
$game2->setTeam_visit(4);
$game2->create();
$game3 = new Game();
$game3->setCup($cup);
$game3->setPlay_date('2008-03-21');
$game3->create();
$id = $game3->id;
Esta primera fase es de inicialización. La BD está así en este punto:
Código PHP:
select * from game;
+----+--------+---------------------+-----------+------------+--------+--------+
| id | cup_id | play_date | team_home | team_visit | winner | result |
+----+--------+---------------------+-----------+------------+--------+--------+
| 1 | 1 | 2008-03-20 00:00:00 | 1 | 2 | NULL | NULL |
| 2 | 1 | 2008-03-20 00:00:00 | 3 | 4 | NULL | NULL |
| 3 | 1 | 2008-03-21 00:00:00 | NULL | NULL | NULL | NULL |
+----+--------+---------------------+-----------+------------+--------+--------+
select * from cup
+----+----------+--------+
| id | name | winner |
+----+----------+--------+
| 1 | TEST Cup | NULL |
+----+----------+--------+
Luego establecemos los observers:
Código PHP:
$game3->setHomeAsWinnerOf($game1);
$game3->setVisitorAsWinnerOf($game2);
$cup->setFinal($game3);
Para este punto la tabla "listen" ya tiene cargado a los observers:
Código PHP:
select * from listen
+----+--------------+-----------+------------+---------------+
| id | event_name | source | interested | params |
+----+--------------+-----------+------------+---------------+
| 1 | WinnerOfGame | Game@id=1 | Game@id=3 | setas=home |
| 2 | WinnerOfGame | Game@id=2 | Game@id=3 | setas=visitor |
| 3 | WinnerOfGame | Game@id=3 | Cup@id=1 | 0= |
+----+--------------+-----------+------------+---------------+
y finalmente, Se juega el torneo :)
Esto lo pongo en el siguiente Post. Que aquí se me acabó el espacio.