Enviar por e-mail
Imprimir
Foto por Image Editor
Padrão Observer ou Observador permite que objetos interessados, observadores, sejam avisados de eventuais mudanças de estado ou eventos de um outro objeto, o observável.
Em um sistema de autenticação o observável é o ato de verificar se o usuário e senha estão corretos e os observadores podem ser persistência da autenticação (cookie ou sessão), geração de logs de acessos e de tentativas, envio de e-mail, entre outros.
Código
Interface do observável
interface Observable {
public function attach(Observer $observer);
public function detach(Observer $observer);
public function notify();
}O objeto observável deve implementar três métodos: attach, detach e notify. O método attach adiciona os observadores e o método detach remove os observadores. Os observadores precisam ser notificados das mudanças de estado ou evento do objeto observável, o método notify é responsável por notificar os observadores das mudanças.
O observável é o ato de verificar se o usuário e senha estão corretos e os observadores podem ser persistência da autenticação (cookie, sessão), geração de logs, envio de e-mail, etc. O padrão Observer torna fácil gerenciar funcionalidades.
class Auth implements Observable {
private $data;
private $observers = array();
public function attach(Observer $observer) {
$this->observers[] = $observer;
}
public function detach(Observer $observer) {
$observers = array();
foreach ($this->observers as $item) {
if ($item === $observer)
continue;
$observers[] = $item;
}
$this->observers = $observers;
}
public function notify() {
foreach ($this->observers as $observer)
$observer->update($this);
}
public function data() {
return $this->data;
}
public function login($username, $password) {
// Tratamento das Strings
$username = str_replace('"', "'", $username);
$password = str_replace('"', "'", $password);
$query = mysql_query("SELECT * FROM usuarios WHERE usuario = '{$username}' AND password = PASSWORD('{$password}')");
if (mysql_num_rows($query))
$this->data = mysql_fetch_object($query);
$this->notify();
return $this->data ? true : false;
}
}A classe Auth é o objeto observável. O atributo $data armazena os dados da autenticação, que, por sua vez, serão utilizados pelos observadores. Esses dados podem ser: nome, e-mail, usuário ou qualquer outro dado que seja necessário. $observers é o Array de objetos observadores, attach adiciona objetos e detach remove objetos.
Notify percorre o array de observadores executando o método update e passando sua instância. Cada observador implementa o método update. Essa chamada de método de objetos distintos é conhecida na programação orientada a objetos por Polimorfismo, a semântica de uma interface é efetivamente separada da implementação que a representa. Um objeto pode implementar a persistência da autênticação por cookie, outro por sessão e outro pode armazenar logs no banco de dados. Os objetos executam diferentes ações.
Data é um método de acesso, retorna o valor do atributo privado $data. Esse método não é parte obrigatória do padrão observer, é uma forma de repassar os dados do observável aos observadores. Se um cookie com nome será gerado, é necessário saber qual nome será usado para gerar o cookie. O nome, assim como outros dados, são gerados por login e acessados por data.
Login é a ação observável, verifica se o usuário e senha existem, notifica os observadores de sua execução e retorna verdadeiro ou falso. Independente de existirem ou não os observadores são acionados, isso é válido tanto para gerar um log de acesso como para gerar um log de tentativa sem sucesso, ou até mesmo iniciar medidas de segurança.
interface Observer {
public function update(Observable $observable);
}A interface define apenas um único método para os observadores, o método update. Esse método recebe por parâmetro um objeto observável e executa sua ação.
class CookiePersist implements Observer {
public function update(Obserable $observable) {
$data = $observable->data();
if ($data)
foreach ($data as $attr => $value)
setcookie($attr, $value, null, '/', '.seudominio.com');
}
}CookiePersist gera cookies com os dados retornados por data do observável. Os cookie só são gerados se dada retornar um valor diferente de falso.
class SessionPersist implements Observer {
public function update(Observable $observable) {
$data = $observable->data();
if ($data)
foreach ($data as $attr => $value)
$_SESSION[$attr] = $value;
}
}SessionPersist gera variáveis de sessão com os dados retornados por data do observável, similar a CookiePersist.
class Log implements Observer {
public function update(Observable $observable) {
$data = $observable->data();
if ($data) {
// gera log de acesso
}
else {
// gera log de tentativa de acesso
}
}
}Log é um modelo para armazenamento de log de autenticação. O log pode ser dividido em: log acesso e log de tentativa. Diferente dos observadores CookiePersist e SessionPersist, Log executa uma ação mesmo que a autenticação tenha falhado.
Em um sistema de autenticação os observadores podem ser selecionados seguindo regras: o usuário externo é limitado a uma sessão e para o usuário interno é gerado cookie.
Esses foram apenas três exemplos de observadores que poderiam ser implementados em um sistema de autenticação. O importante é notar como o padrão Observer lida e separa diferentes recursos, sua forma de pensar em observável e observador. É possível adicionar, alterar e remover funcionalidades sem comprometer o sistema.
Exemplo
<?php
$auth = new Auth();
$auth->attach(new CookiePersist());
if ($auth->login($_POST['usuario'], $_POST['senha'])) {
// dados corretos
}
else {
// usuário e/ou senha inválidos
}
?>
Código fonte
<?php
interface Observable {
public function attach(Observer $observer);
public function detach(Observer $observer);
public function notify();
}
class Auth implements Observable {
private $data;
private $observers = array();
public function attach(Observer $observer) {
$this->observers[] = $observer;
}
public function detach(Observer $observer) {
$observers = array();
foreach ($this->observers as $item) {
if ($item === $observer)
continue;
$observers[] = $item;
}
$this->observers = $observers;
}
public function notify() {
foreach ($this->observers as $observer)
$observer->update($this);
}
public function data() {
return $this->data;
}
public function login($username, $password) {
// Tratamento das Strings
$username = str_replace('"', "'", $username);
$password = str_replace('"', "'", $password);
$query = mysql_query("SELECT * FROM usuarios WHERE usuario = '{$username}' AND password = PASSWORD('{$password}')");
if (mysql_num_rows($query))
$this->data = mysql_fetch_object($query);
$this->notify();
return $this->data ? true : false;
}
}
interface Observer {
public function update(Observable $observable);
}
class CookiePersist implements Observer {
public function update(Obserable $observable) {
$data = $observable->data();
if ($data)
foreach ($data as $attr => $value)
setcookie($attr, $value, null, '/', '.seudominio.com');
}
}
class SessionPersist implements Observer {
public function update(Observable $observable) {
$data = $observable->data();
if ($data)
foreach ($data as $attr => $value)
$_SESSION[$attr] = $value;
}
}
class Log implements Observer {
public function update(Observable $observable) {
$data = $observable->data();
if ($data) {
// gera log de acesso
}
else {
// gera log de tentativa de acesso
}
}
}
?>
Comentar
RSS
RSS
Ótima classe, mas como se faz a proteçao das páginas? No exemplo só tempos como iniciar a autenticação :P
Parabéns e abraços!
Muito obrigado pelo comentário Marcelo. Vou escrever sobre como verificar a autenticação em páginas de acesso restrito.
Mais uma vez obrigado!
Abraços
"Sem comentários" rs
Cara, são sites e blogs que nem o seu que cala a boca de muitos que falam mau do PHP, da sua estrutura e etc.
Esta de parabens!
=)