Ir para conteúdo

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

felipe_zmm

Iniciante em OO

Recommended Posts

Enrico, estou lendo e para resolver o problema me passou pela cabeça a seguinte abordagem:

 

1 - Para verificar se um login e senha digitados são válidos eu instancio um objeto Usuario e seto suas propriedades login e senha.

 

2 - Instancio UsuarioMapper e injeto no método validarUsuario de ControleLogin.

 

3 - O método utiliza o Mapper para fazer a verificação no banco de dados e retorna o resultado.

 

Fiz uma salada maior ainda ou meu pensamento está correto ? Dessa forma acho que eu teria cada objeto responsável por uma única tarefa se comunicando com os outros.

Compartilhar este post


Link para o post
Compartilhar em outros sites

1 - Sim, mas o VO (Usuario) ele é apenas para armazenar o dado.

 

2 e 3 - Persistência e validação são coisas diferentes. E não seria nem validação no caso, mas sim autenticação.

Compartilhar este post


Link para o post
Compartilhar em outros sites

1 - Sim, mas o VO (Usuario) ele é apenas para armazenar o dado.

 

Mas é exatamente isso que eu estaria fazendo:

 

$login = $_POST['login'];
$senha = $_POST['senha'];

$usuario = new Usuario();
$usuario->setLogin($login);
$usuario->setSenha($senha);

 

 

 

2 e 3 - Persistência e validação são coisas diferentes. E não seria nem validação no caso, mas sim autenticação.

 

Sei que são coisas diferentes, mas se for assim então eu não posso ter um método find() no mapper ?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Pode, mas o validador deve apenas validar, não acessar banco ou outra coisa.

 

Passemos a chamá-lo de autenticador então, já que é a palavra que melhor se aplica ao que o método faz. Mas ele não se conecta ao banco, quem conecta é o objeto PDO que é injetado no Mapper, que por sua vez será injetado no método. Alguma forma de conferir as informações do usuário na fonte de dados ele precisa ter, do contrário não há forma de autenticá-lo.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Mas aí começa um erro: a falta de abstração. O autenticador deve ser flexível, não depender de um db, você criaria adaptadores que seguiriam um contrato (interface).

Compartilhar este post


Link para o post
Compartilhar em outros sites

Mas aí começa um erro: a falta de abstração. O autenticador deve ser flexível, não depender de um db, você criaria adaptadores que seguiriam um contrato (interface).

 

Mas então o erro não começaria aqui, e sim no Mapper que também recebe um PDO no seu construtor. Veja bem, eu entendo o seu argumento, só não enxergo como resolveria isso por enquanto. Talvez a resposta seja aqueles patterns de factory que eu ainda não compreendo bem.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Estude patterns, principalmente os de GOF. Enxergar uma abstração é algo muito complexo e que você precisa de muita prática para isso. Uma forma de começar a entender bem o design de um código orientado a objetos é estudando design patterns e vendo suas estruturas.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Tudo que eu faço nos últimos dias é ler patterns, estudar patterns e praticar patterns.

 

O problema está na divergência de informações que eu encontro por aí. No começo deste tópico eu citei que estava lendo o famoso livro "PHP - Programando com Orientação a Objetos" do Pablo Dall'Oglio. Se tudo que eu ando lendo na internet está correto, eu gastei um tempo absurdo lendo esse livro e aprendendo conceitos errados.

 

Um exemplo são os patterns Table Data Gateway e Row Data Gateway. Aqui mesmo no fórum existe um tópico do Henrique Barcelos que explica e exemplifica os dois, e segundo ele não existe RDG sem TDG. No livro está exatamente o contrário, além de usar um RDG sem TDG ele instancia PDO dentro da classe RDG. Onde estaria o desacoplamento nisso ? E o dependency injection ?

 

Isso é o que mais está me frustrando nessa tentativa de aprender a programar OO da forma correta. Se eu não posso confiar em absolutamente nada que leio, nem em um livro até bem conceituado, vou seguir em frente como ?

 

No mais, Enrico, agradeço toda sua atenção e paciência. Talvez minhas dúvidas pareçam bobas pra quem já entende, mas realmente é difícil porque tenho encontrado muitas divergências.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Não, não existe RDG sem TDG, são patterns que se complementam, mas não, eu não iria com a sede ao pote nos padrões P of EAA, veria os de GOF primeiro.

 

Patterns existem para resolver problemas, e você só usa um quando tem um problema. Em PHP, há pouco material sobre patterns, em Java há muito, mas muito mesmo, eu penso que vídeos, por serem mais dinâmicos, ensinam melhor, veja esses vídeos sobre GOF (em java, infelizmente em inglês):

 

Lembre-se que não há a maneira correta de programar, eu pouco sei e todos pouco sabem, você nunca perde tempo aprendendo, mesmo que algo errado, pois você aprende o que não fazer, a questão de criar instâncias no próprio objeto ela quase sempre é um perigo, e é justamente isso que leva ao estado global: quando uma instância é criada, o estado (valor armazenado pelas propriedades) é o padrão, se você usa um estado global não, então perde-se todo o controle usando isso. E além de claro, a testabilidade (mesmo que não saiba sobre unit tests, lembre dessa palavrinha).

 

Vai seguir em frente errando, pois é errando que se aprende, você vai realmente ver o problema que violações de conceitos (aparentemente teórico e inútil) tornando-se um problema.

 

A minha dica: tente aprender OO em Java, principalmente pela tipagem forte, as coisas ficarão mais claras.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Sem problema quanto aos vídeos em inglês, vou assistir.

 

Sobre os testes unitários eu já ouvir falar bastante do PHPUnit, mas não sei exatamente o que ele faz.

 

Mas talvez eu esteja com um medo de errar excessivo mesmo, querendo fazer tudo certo logo de cara e isso obviamente não vai acontecer. É uma característica minha mesmo, ser perfeccionista e não querer errar.

 

Vou buscar material sobre Java.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Como tinham me sugerido, coloquei as operações de sessão em uma classe:

 

    class Sessao
    { 
        public function __construct($regenerar = false)
        {
            session_start();
            
            if ($regenerar == true)
            {
                $this->regenerar();   
            }
        }
        
        public function getId()
        {
            return session_id();
        }
        
        public function destruirSessao()
        {
            $this->limparSessao();
            session_destroy();
        }
        
        private function limparSessao()
        {
            $_SESSION = array();
        }
        
        public function regenerar()
        {
            session_regenerate_id(true);
        }
        
        public function setarValor($nome, $valor)
        {
            $_SESSION[$nome] = $valor;
        }
        
        public function valorSetado($nome)
        {
            if (isset($_SESSION[$nome]))
            {
                return true;
            }
            
            return false;
        }
    }

 

Utilizando na classe ControleLogin:

 

    class ControleLogin
    {
        private $sessao;
        private $pdo;
        private $login;
        private $senha;
        
        public function __construct(Sessao $sessao, PDO $pdo = null)
        {
            $this->sessao = $sessao;
            
            if ($pdo != null)
            {
                $this->pdo = $pdo;
            }
        }
        
        public function autenticarLogin($login, $senha, $tabela)
        {   
            $this->login = $login;
            $this->senha = $this->gerarHash($senha);
            
            $qry = "SELECT COUNT(id) FROM {$tabela} "
                 . "WHERE login = :login AND senha = :senha AND status = '1'";
                 
            $stmt = $this->pdo->prepare($qry);
            $stmt->bindParam(':login', $this->login);
            $stmt->bindParam(':senha', $this->senha);
            $stmt->execute();
                
            if ($stmt->fetchColumn() == 1)
            {    
                $this->sessao->setarValor('login', $this->login);
                $this->sessao->setarValor('validado', 1);
                
                return true;
            }
        }
        
        public function logout()
        {
            $this->sessao->destruirSessao();  
        }
        
        public function usuarioLogado()
        {   
            return ($this->sessao->valorSetado('login')) && ($this->sessao->valorSetado('validado'));
        }
        
        private function gerarHash($senha)
        {
            return sha1($senha);
        }
    }

 

Dessa forma está correto ? A única coisa que eu imagino que ainda viole o SRP seria esse método gerarHash.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Bem, evoluiu. Novamente, o PDO como nulo, mata, pois ele acaba com uma palavrinha essencial da OO: confiança, se você quebra ela, você quebra a OO.

 

Eu posso instanciar a classe ControleLogin sem o PDO, até aí tudo bem, mas se eu for executar o método autenticarLogin sem passar o PDO no construct, hein? Já era, vc quebrou a confiança.

 

Quando ao SRP, acho que não há mais problemas. Esse gerar hash é algo interno e não chegaria a considerar uma violação ao SRP.

 

Mas como eu disse, você continua com a falta de uma abstração: a autenticação depende do PDO, depende de banco de dados. Considere abstrair isso: veja Factory Method e Abstract Factory, padrões para construção de objetos.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Bem, evoluiu. Novamente, o PDO como nulo, mata, pois ele acaba com uma palavrinha essencial da OO: confiança, se você quebra ela, você quebra a OO.

 

Eu posso instanciar a classe ControleLogin sem o PDO, até aí tudo bem, mas se eu for executar o método autenticarLogin sem passar o PDO no construct, hein? Já era, vc quebrou a confiança.

 

Verdade, não tinha pensado nisso.

 

Mas como eu disse, você continua com a falta de uma abstração: a autenticação depende do PDO, depende de banco de dados. Considere abstrair isso: veja Factory Method e Abstract Factory, padrões para construção de objetos.

 

Vou estudar sim, como eu disse alguns posts atrás já imaginava que a solução estivesse nesses patterns. Mas eles são bem extensos e tenho que pegar um momento com bastante tempo pra entender aquilo, porque de cara achei bem complexo.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Um exemplo são os patterns Table Data Gateway e Row Data Gateway. Aqui mesmo no fórum existe um tópico do Henrique Barcelos que explica e exemplifica os dois, e segundo ele não existe RDG sem TDG. No livro está exatamente o contrário, além de usar um RDG sem TDG ele instancia PDO dentro da classe RDG. Onde estaria o desacoplamento nisso ? E o dependency injection ?

 

Olha, eu nunca cheguei nem perto desse livro do Pablo Dall'oglio, não tenho propriedade nenhuma para dizer, mas já ouvi colegas dizendo que o livro tem bons e maus exemplos e esse COM CERTEZA é um.

 

Sumarizando aqui rapidamente:

Active Record (ou registro ativo): é o famoso Severino, o faz-tudo. Representa os dados, armazena os dados, lida com regras de negócio e validação. Acho que nem preciso explicar o porquê de NÃO utilizá-lo.

 

Data Mapper: é o contrário do Active Record. Sua única responsabilidade é mapear dados de um meio de armazenamento para objetos. Os objetos mapeados("mappees") não têm ideia que são parte de um todo. Segundo a minha visão, é rígido demais para linguagens dinâmicas, como o PHP. A não ser que você tenha um gerador de mappers e mappees, criar data mappers é algo extremamente tedioso.

 

Row Data Gateway: é o meio termo. Ele representa um registro de uma tabela de um SGBD relacional (SQL), entretanto, pode conter mais dados do que um registro na própria tabela (como campos gerados pela consulta). Com este padrão, é possível invocar operações sobre aquele registro, entretanto, ele possui apenas a INTERFACE para fazê-lo, mas a ação de fato é delegada ao Table Data Gateway associado àquele registro. Com isso, não há violação do SRP, mas é verdade que surge um pequeno acoplamento entre o RDG e o TDG, entretanto, isso já é esperado, pois o RDG PRECISA saber que faz parte de um entorno maior, ou seja, uma tabela. Obviamente, este padrão se aplica melhor a aplicações rodando sobre SGBDs relacionais.

Compartilhar este post


Link para o post
Compartilhar em outros sites

O próprio GOF e o P of EAA (clássicos dos patterns) tem patterns "ronc ronc", como Singleton, Registry, Active Record, etc. não há nada 100% e repito, aprender errado é bom pois você aprende o que não fazer.

 

Só uma coisinha: o Active Record não é responsável por validação ou filtro, apenas por persistência, os frameworks que implementam dessa forma, chamando de "model" e promovendo godclasses :skull: .

 

E o Data Mapper é problemático, vide Doctrine2, e além disso viola o bom senso porque por mais que o modelo relacional se pareça com o modelo orientado a objetos (por causa dos relacionamentos) eles não são a mesma coisa, aí entra o problema e usa-se UnityOfWork que vai lotar tudo de métodos. Acho que a decisão mais sábia é RDG/TDG.

Compartilhar este post


Link para o post
Compartilhar em outros sites

O próprio GOF e o P of EAA (clássicos dos patterns) tem patterns "ronc ronc", como Singleton, Registry, Active Record, etc. não há nada 100% e repito, aprender errado é bom pois você aprende o que não fazer.

 

É bom em termos. No meu caso talvez seja útil porque eu resolvi pesquisar mais, buscar outras explicações. Agora imagina o tanto de gente que leu esse livro e está aplicando o pattern da forma errada.

 

Meio triste pensar que um livro tão bem falado como esse possui um erro grotesco desses. Ou o autor não pesquisou o suficiente para abordar o tema ou simplesmente não quis se alongar no tema, criando uma forma própria de utilizar o pattern. Mas então era melhor não ter escrito nada sobre.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Discordo, OO e patterns são coisas abstratas, acadêmicas, não é uma ciência exata e é totalmente discutível, eu não compraria um livro sobre patterns a não ser o que a define, no caso do RDG seria P of EAA.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Tudo bem que seja um assunto discutível, mas pattern significa padrão, modelo, exemplo. Na minha opinião ele deveria então no mínimo ter avisado que se tratava de uma variação do RDG.

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.