Patrón Observer Práctica

El parón Observer nos permite crear objetos observables que mantienen una lista de observadores y les notifica a éstos de cualquier cambio en su estado, normalmente llamando a uno de sus métodos. En esta práctica se describe este patrón en una función sencilla.

Objetivo: Se desea que cuando el administrador de la aplicación adicione un usuario, a la vez de confirmarle dicha adición, le presente la hora y la cantidad de usuarios que se modificó cuando se agregó dicho usuario.

Para esto, primero debemos crear la clase abstracta de donde heredarían los observables (clases a las cuales se les quiere observar):

//Observable.php
<?php

abstract class Observable{
      protected $observers;
     
      function __construct(){
            $this->observers = array();
      }

      //Para el registro de los objetos observables
      public function registrarObserver($observer){
            //if(!in_array($observer, $this->observers)){
                $this->observers[] = $observer;
            //}
      }

      //Para eliminar de los observables un objeto
      public function deregistrarObserver($observer){
            if(in_array($observer, $this->observers)){
                $key = array_search($observer, $this->observers);
                unset($this->observers[$key]);
            }
      }
     
      //La funcion respectiva cuando se notifica
      abstract public function notificarObservers();

}

?>
Ahora creamos la Interfaz que heredarían los observadores (clases que necesitan saber si en la clase observable se ha modificado algo):

//Observer.php
<?php
interface Observer{
      public function notificar($sender, $params);
}
?>


A continuación creamos las clases específicas, en este caso una clase observable y una clase que actuará de observador.

La clase Observable, en este caso de nuestra aplicación, será la clase que maneja toda la gestión de los usuarios en la base de datos, pues lo que se desea es que en el momento de adicionar en la tabla usuarios de la base de datos, se dé la notificación al objeto observador.

//Userdb.php
<?php
/**
 * -----------------------------------------------------------------
 * Definicion de clase: User
 * Representa la persistencia con los objetos user
 * -----------------------------------------------------------------
 */
require_once("lib/factorydb.lib.php");
require_once("lib/mysql.lib.php");
require_once('modules/user/model/user.php');
require_once("modules/user/model/Observable.php");


class UserDB extends Observable{  /* ß Debe heredar de Observable*/

      /**
       * Conexion con la bd
       */
      private $conn;
      /**
       * Constructor
       *
       */
      function __construct() {
            global $CFG_DBASE_TYPE;
            $this->conn = FactoryDB::getConnection($CFG_DBASE_TYPE);
      }
      /**
       * Metodo para consultar los usuarios registrados en la Base de Datos
       *
       * @param String $condition, condicion para buscar los usuarios.   Si es vacio se toma todos los registros
       * @return vector, un vector de objetos tipo User
       */
      function find($condition) {
            if($condition!='')
            $condition = "Where ".$condition;
            $sql ="SELECT login,passwd,nombres,apellidos,privilegio FROM usuario ".$condition;
            $data = $this->find_process($sql);
            return $data;
      }
      /**
       * Busca registros con paginacion
       *
       * @param string $condition
       * @param string $order
       * @param int $limitInf
       * @param int $sizePag
       * @return vector
       */

      function findPagination($condition,$order,$limitInf,$sizePag){
            if($condition!='')
            $condition = " Where ".$condition;
            $sql="SELECT login, passwd,nombres,apellidos,privilegio FROM usuario ".$condition." ORDER BY ".$order.",login ASC ".$this->conn->limit($sizePag, $limitInf);
            $data = $this->find_process($sql);
            return $data;
      }
      /**
       * Procesa la consulta.  Es invocado por find y por findPagination
       *
       * @param string $sql
       * @return vector
       */

      private function find_process($sql){
            $this->conn->connect();
            $this->conn->setSql($sql);
            $this->conn->consult();
            $response = $this->conn->getResponseSql();
            $data = array();
            for($i=0;$i<$this->conn->getNumReg();$i++){
                  $fila=$this->conn->fetch_row($response,$i);

                  $login = $fila[0];
                  $password = $fila[1];
                  $firstName = $fila[2];
                  $lastName = $fila[3];
                  $privilege = $fila[4];

                  $user = new User();
                  $user->setUser($login,$password,$firstName, $lastName, $privilege);
                  $data[$i] = $user;
            }
            $this->conn->disconnect();
            return $data;

      }
      /**
       * Graba en la base de datos un nuevo usuario
       * @param User $user, usuario
       *
       */
      function save($user){
            $sql= "INSERT INTO usuario (".
                  "login ,".
                  "passwd, ".      
                  "nombres,".
                  "apellidos,".
                  "privilegio".
                  ") ".
                  "VALUES (".
                  "'".$user->getLogin()."', '".$user->getPassword()."','".$user->getFirstName()."', '".$user->getLastName()."', '".$user->getPrivilege()."' );";
            $this->conn->connect();
            $this->conn->setSql($sql);
            $this->conn->update();


$this->notificarObservers();  /* ß Cuando Guardamos en la
 base de datos notificamos al Observador */
      }
      /**
       * Actualiza o modifica los datos del usuario
       *
       * @param User $user, objeto tipo Usuario
       */
      function update($user){
            $sql= "Update usuario SET ".
                  "passwd='".$user->getPassword()."',".
                  "nombres='".$user->getFirstName()."', ".
                  "apellidos='".$user->getLastName()."',".
                  "privilegio='".$user->getPrivilege()."' ".
                  "WHERE login='".$user->getLogin()."'";
            $this->conn->connect();
            $this->conn->setSql($sql);
            $this->conn->update();
      }
      /**
       * Elimina un usuario de la bd
       *
       * @param String $login
       */
      function delete($login){
            $sql= "Delete from usuario ".
                  "WHERE login='".$login."'";
            $this->conn->connect();
            $this->conn->setSql($sql);
            $this->conn->update();
      }
      /**
       * Calcula el total de registros de una consulta de usuarios
       *
       * @param string $condition
       * @return int
       */
      function numRows($condition){
            $this->conn->connect();
            if($condition!='')
            $condition = "Where ".$condition;
            $this->conn->setSql("SELECT count(*) FROM usuario ".$condition);
            $this->conn->consult();
            $response = $this->conn->getResponseSql();

            $fila=$this->conn->fetch_row($response,0);
            $numRows = $fila[0];
            $this->conn->disconnect();
            return $numRows;
      }
     
      //Coloca sus observadores
      //Se implementa la funcion NotificarObservers
      public function notificarObservers(){
            foreach ($this->observers as $observer) {            
                  $observer->notificar($this, 1);
            }
      }
}
?>

Clase específica observadora:

//NumeroUsuarios.php
<?php
require_once("Observer.php");

class NumeroUsuarios implements Observer{
      private $_numusuarios;
   
    public function __construct($num){
        $this->_numusuarios = $num;
    }
   
      public function notificar($sender, $param){
            $this->_numusuarios = $this->_numusuarios+$param;
                                                                                    //Se presenta la fecha
            echo get_class($sender)." envió $this->_numusuarios a las ".date('h:i:s', time())."<br />";
      }
}

?>

Finalmente, para utilizarlo, instanciaremos las clases y registraremos los observadores de esta manera:

En la clase donde se guarda la adición del nuevo usuario registramos a nuestra clase observadora NumeroUsuarios antes de hacer la consulta a la base de datos.

//addUsuariosave_Controller.php

      $numeroRegistros=$userdb->numRows($condition);
      $userdb->registrarObserver(new NumeroUsuarios($numeroRegistros));
$userdb->save($user);    /* ß En este momento se notifica a NumeroUsuarios*/