Ir para conteúdo

Arquivado

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

William Bruno

Reconstruindo um framework

Recommended Posts

Boas Galera !!

 

Andei repensando aqui, e após reler alguns dos meus livros de php, e ter adquirido mais um sobre OO, acho que estou pronto, para rever todos meus conceitos, e mexer no meu sisteminha ^_^

 

Parece loucura, mas tenho num mini-fw caseiro, que me atende bem, apesar de tudo, agora comecei a notar falhas nele, então vou remodelar tudo.

 

Acredito que nesse caso, preciso convencionar várias coisas, e ai gostaria de opiniões acerca disto.

Dentro do administrativo, se eu quiser ver aquela listagem de cadastros, para edição, a url fica:

?ctrl=produto&ac=view, ?ctrl=categoria&ac=view

 

se for para ver um registro em específico:

?ctrl=categoria&ac=view&id=14

 

E mesma coisa qndo estiver na área pública do site, porém, para melhor aproveitar, agora meus controladores são as próprias classes, para ver todos as linhas do banco de dados:

?produto, ?categoria

 

e ai para ver uma em específico:

?produto=7, ?categoria=14

 

Me pareceu bem interessante esta idéia, pois cada nova 'área' do site, como noticias, artigos, eu só vou precisar colocar na URL:

?noticia, ?artigo, e se for ver um em específico, adiciono o id..

 

logo, tenho as classes:

Ctrl, Produto, Categoria

 

A class 'Ctrl', seria para definir as ações de INSERT|UPDATE ou DELETE, na área administrativa.

Que tal até aqui ?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Eu sei que não sou expert no assunto, mas até onde entendo essa classe Ctrl ou deveria não existir ou deveria ser pai das suas models não?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Então... as minhas Models mesmo, não participam diretamente das ações de INSERT|UPDATE|DELETE.

 

quem participa disso, é uma DAO concreta, que apartir de um VO (cada tabela possui um VO concreto), consegue formar essas operações básicas.

 

o DAO é apenas uma parte da Model.

As classes Model de verdade, estão livres dessas operações chatas de banco de dados, que usamos nos paineis administrativos !

 

a class Ctrl, serve para isso. Pois como convencionei:

 

?class=____&ação=____&id__

 

se eu não tivesse a Ctrl, no painel eu teria que fazer:

 

?categoria=15&ac=view

 

ai me seria mostrado um form para edição da categoria 15... e nisso, eu teria que jogar de novo, na class pai as operações chatas do CRUD.

Acho que consegui abstrair elas.

Compartilhar este post


Link para o post
Compartilhar em outros sites

@William Bruno

 

Já escrevi este mesmo resumo sobre as classes DAO e VO aqui no fórum, mas não custa mostrar novamente.

 

Tudo depende da necessidade da sua aplicação.

 

Conhecemos DAO por Data Access Object, ou seja, Objeto de Acesso a Informações.

 

Antes de entrarmos na questão das classes DAO, deixe-me lhe apresentar um (talvez novo) conceito, o de Value Object.

 

O propósito de um Value Object é representar uma entidade de negócio. Em sua forma mais simplificada, um VO é uma classe de mapeamento de informação que reflete a entidade tal qual ela foi modelada e existe na base de dados. O propósito principal de um VO é armazenar informação em qualquer um dos seus trajetos: banco de dados > usuário, usuario > banco de dados.

 

Geralmente se utilizam os VO's para tratar das operações básicas de CRUD em sua forma mais crua.

 

Leia mais sobre o padrão VO: Padrões de Projeto - Value Object (Erico Renato Oliveira de Almeida).

 

Agora sim, falemos de Data Access Object.

 

Um DAO atua como um mediador entre a base de dados e os Value Objects. Teoricamente, uma classe Base DAO sabe especificamente como se comunicar com a base de dados. A Base DAO sabe com qual base de dados se está interagindo, que tipo de base de dados ela é, esteja ela trapalhando com mysql, mssql, pg e etc. A Base DAO é, essencialmente, a camada Model do esquema MVC.

 

A utilização de uma classe DAO se dá, justamente, no momento em que necessitamos de algo diferente de um objeto do tipo Value Object.

 

Digamos que você precise listar os clientes por estado e cidade. Um VO não seria o encarregado de fazer tal listagem, mas sim um DAO:

 

class ClienteDAO extends BaseDAO {
	public function getListaClientesPorCidadeEstado( $cidade , $estado ) {
		$sql = " SELECT * FROM cliente WHERE cidade = '{$cidade}' AND estado = '{$estado}' ";
		// Aqui você manipula as transações da maneira que achar mais conveniente...
	}
}

Na verdade, os Data Access Object representam a Model da estrutura MVC, mas é claro que se encaixam no conceito de persistência.

 

Veja bem, as classes DAO representam uma camada própria e formam um pacote de acesso de dados, algumas vezes sob o pacote do modelo, algumas vezes sob um pacote independente e outras (raras) vezes sob o pacote de controladores. O mais comum é mesmo que o pacote de DAO fique subordinado ao Modelo, mas sem extendê-lo. Assim temos uma separação e relativa independência da camada de acesso dados e do Domínio.O principio é que para cada Modelo, temos um DAO correspondente. Toda interação e configuração com o Banco de dados, ou com o framework de persistência, ficam nas camadas dos DAO, AR, VO e BO, dependendo, mais uma vez, da necessidade da aplicação.

 

Dessa forma, temos a possibilidade de manipular as operações básicas de CRUD com VO's, BO's ou AR's, e os DAO ficam à disposição para programarmos métodos mais específicos, como getListaClientesPorEstadoCidadeBairro.

Compartilhar este post


Link para o post
Compartilhar em outros sites

O propósito de um Value Object é representar uma entidade de negócio. Em sua forma mais simplificada, um VO é uma classe de mapeamento de informação que reflete a entidade tal qual ela foi modelada e existe na base de dados. O propósito principal de um VO é armazenar informação em qualquer um dos seus trajetos: banco de dados > usuário, usuario > banco de dados.

 

Geralmente se utilizam os VO's para tratar das operações básicas de CRUD em sua forma mais crua.

 

Leia mais sobre o padrão VO: Padrões de Projeto - Value Object (Erico Renato Oliveira de Almeida).

tá... até 'concordo', mas não acho que seja 'só isso', ou não seja 'isso tudo'.

 

Veja, um VO, é um objeto meio que para mapear uma entidade.

A tabela `cliente`, tem a class ClienteVO(), e essa classe, representa com exatidão, a tabela `cliente`..

 

Queria discutir um pouco mais do que o conceitos sobre os padrões, mas tudo bem.. vou expor minha opinião também.

 

A Base DAO é, essencialmente, a camada Model do esquema MVC.

não só isso, digamos que a camada Model, usa o DAO.

E este por isso, se torna uma parte da Model, mas não é(ou não deveria), ser a Model em si.

 

No fim do teu texto, você diz algo que chega mais perto 'da verdade', enfim.. vamos lá.

 

 

Digamos que você precise listar os clientes por estado e cidade. Um VO não seria o encarregado de fazer tal listagem, mas sim um DAO:

 

class ClienteDAO extends BaseDAO {
	public function getListaClientesPorCidadeEstado( $cidade , $estado ) {
		$sql = " SELECT * FROM cliente WHERE cidade = '{$cidade}' AND estado = '{$estado}' ";
		// Aqui você manipula as transações da maneira que achar mais conveniente...
	}
}
ai dessa modelagem eu discordo totalmente..

pesquise sobre FluentInterface, você vai ver as maravilhas que isso pode fazer! ^_^

 

 

 

O mais comum é mesmo que o pacote de DAO fique subordinado ao Modelo, mas sem extendê-lo. Assim temos uma separação e relativa independência da camada de acesso dados e do Domínio.

legal, esse trecho ficou bacana!

 

O principio é que para cada Modelo, temos um DAO correspondente.

Aqui eu discordo completamente!

putz véio, acredite eu já trabalhei assim, não vale apena..

 

Acabei duplicando código, ou usando herança qndo não deveria..

na verdade, a mágica que descobri, é usar uma única classe DAO, para todas as tabelas do banco!

Putz! perfeito!

 

E não, num tô misturando nada... não tô deixando de tornar independente as partes do meu sistema, apenas estou delegando de forma correta as coisas como elas devem ser. Pois uso uma DAO para as operações básicas do painel de controle: INSERT - UPDATE - DELETE - SELECT (com um pouco de FluentInterface, pois ainda estou aprimorando), e pronto cara!

Continuarei tendo uma Model para cada tabela, de forma independente da minha unica e exclusiva DAO, que não tá nem ai pra qual tabela ela vai trabalhar..

já que aplicando ao extremo o conceito de VO, eu consigo que a minha DAO, faça o CRUD de todas minhas tabelas 'pesadas' (as entidades, e não as de relacionamento)

 

a camada de Controladores sempre foi a 'mais dificil' para mim.. mas com esse esquema de uma unica DAO, ficou tudo tão mais lindo! ^^

a interface da minha DAO, ficou:

class DAO
{
	private $table, $fields, $statement;
	private $type, $sql;
	
	public $num_rows = 0;
	
	public function __construct( $table ){}

	final public function save( ValueObject $vo ){}
	final public function del( ValueObject $vo ){}
	final private function execute( $debug=false ){}


	final public function select( ValueObject $vo )	{}
	final private function update( ValueObject $vo )	{}
	final private function insert( ValueObject $vo )	{}
	final private function delete( ValueObject $vo )	{}
	
	
	public function byId( $id ){}
	final public function query( $sql ){}
	final private function __toString(){}
}
ainda estou melhorando a visibilidade dessa class, mas a idéia é essa.. apartir do ValueObject fornecido, essa única DAO, se vira e faz o CRUD das entidades da minha aplicação.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Estou agora apenas como telespectador da discussão então, para que eu não fique completamente à deriva William, como você usa essa sua classe DAO e como está o seu ValueObject?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Andei repensando aqui, e após reler alguns dos meus livros de php, e ter adquirido mais um sobre OO, acho que estou pronto, para rever todos meus conceitos, e mexer no meu sisteminha

 

Lamento a demora, Bruno, a correria por aqui está cabulosa.

 

Acredito que nesse caso, preciso convencionar várias coisas

 

http://forum.imasters.com.br/public/style_emoticons/default/joia.gif

 

Convenção é a base de tudo.

 

a camada de Controladores sempre foi a 'mais dificil' para mim..

 

Ok, vamos facilitar tudo então.

 

Toda aplicação, seja ela desktop, de terminal ou web, baseia-se em entrada e saída (input/output ou só IO)

 

No caso de uma aplicação web, o usuário fará a entrada em seu sistema através da interface de usuário ou UI, essa interface em MVC chamamos de View.

 

A View é um conjunto de elementos visuais que, juntos, permitem que um usuário interaja com sua aplicação.

 

Você já viu alguma aplicação (qualquer uma) que tenha 2 ou mais Views ao mesmo tempo ??

 

A View é uma camada única, você sempre terá 1 única saída para o usuário e, através dessa saída (UI) o usuário enviará requisições para sua aplicação.

 

Quando uma aplicação chega à sua aplicação, você poderá tratá-la de uma forma específica ou, de várias formas conjuntas e, também, poderá utilizar N acesso à dados distintos para compor a resposta.

 

Imagem Postada

Como pode ver, a View pode utilizar os dados de uma Model para renderizar a interface de usuário e, da mesma forma, a Controller pode usar uma Model para definir a interface de usuário, validar dados, etc.

 

O fato, é que a View só "monta" a interface de usuário, não é responsabilidade dela trabalhar com acesso à dados, da mesma forma, a Controller só recebe a entrada, valida-a e devolve uma nova saída, não é responsabilidade da Controller lidar com acesso a dados também.

 

A responsabilidade de acesso à dados é exclusivamente da Model.

 

DAO, VO, Table Data Gateway, Row Data Gateway, Active Record, tudo isso são formas que uma Model pode utilizar para acessar os dados, estejam eles em um XML, banco de dados relacional ou em um banco de dados não relacional.

 

Controller:

Um usuário pode enviar uma requisição de várias formas: GET, POST, PUT, DELETE

 

A responsabilidade de um controlador é receber essa requisição e decidir o que fazer com ela.

 

O usuário envia uma requisição POST para seusite.com.br/usuario/cadastro, seu controlador, primeiro, receberá a requisição GET para usuario/cadastro e decidirá como tratar essa requisição.

Quando o controlador decidir como tratá-la ele trabalhará com o POST, contendo os dados do usuário.

Com os dados, o controlador usará uma Model que poderá gravar os dados do usuário em uma base e recuperar informações dessa base.

Com os dados da base de dados, o Controlador os repassa à View que montará a resposta ao usuário.

Com a saída formatada pela View, o Controlador responde a requisição do usuário.

Imagem Postada

 

 

Como pode ver, o foco do MVC é, exatamente, a interface de usuário, como apresentá-la ao usuário, como o usuário interage com ela.

 

Independente da requisição, você terá, sempre, uma resposta; Seja uma tela de erro, um formulário populado com os dados do usuário ou uma listagem de produtos.

 

Ok,

 

Então, o usuário fez uma requisição, vamos recuperá-la:

 

mvc/Request.php

<?php
/**
* Requisição do usuário
*/
class Request {
/**
 * Instância do objeto de requisição
 * @var Request
 */
private static $instance;

/**
 * Constroi o objeto de requisição
 * @param string $base Base da requisição
 */
protected function __construct( $base ){
	$this->base = $base;
}

/**
 * Recupera o método da requisição (ex: GET, POST, PUT, DELETE, etc.)
 * @return string
 */
public function getMethod(){
	return $_SERVER[ 'REQUEST_METHOD' ];
}

/**
 * Recupera a URI
 * @return string
 */
public function getURI(){
	$base = preg_quote( $this->base , '/' );

	return preg_replace( sprintf( '/^%s(.*)/' , $base ) , '$1' , $_SERVER[ 'REQUEST_URI' ] );
}

/**
 * Recupera os dados postados
 * @return ArrayObject
 */
public function getPOSTData(){
	return new ArrayObject( $_POST );
}

/**
 * Recupera a instância de Request
 * @param string $base A base da requisição que será passada ao construtor
 * @return Request
 */
public static function getInstance( $base = '/' ){
	if ( self::$instance == null ){
		self::$instance = new Request( $base );
	}

	return self::$instance;
}
}

 

Agora que temos a requisição do usuário, precisamos definir um Controller:

 

mvc/Controller.php

<?php
/**
* Interface para um controlador
*/
interface Controller {
/**
 * Interpreta a requisição do usuário
 * @param Request $request
 */
public function handle( Request $request );

/**
 * Recupera a resposta
 * @return View
 */
public function getResponse();
}

 

E uma View:

mvc/View.php

<?php
/**
* Interface para definição de uma View
*/
abstract class View {
/**
 * Você terá 1 e apenas 1 resposta, independentemente de ser um erro
 * ou qualquer outra coisa
 * @var View
 */
private static $instance;

/**
 * Garantindo que não seja possível instanciar a View sem utilizar o método getInstance
 */
protected function __construct(){}

/**
 * Recupera a instância da View
 */
public static function getInstance(){
	if ( self::$instance == null ){
		$class = get_called_class();

		self::$instance = new $class();
	}

	return self::$instance;
}

/**
 * Desenha a View
 * @return string
 */
abstract public function draw();
}

 

Pensando em uma página de usuário, podemos fazer o seguinte:

 

User/UserController.php

<?php
require_once 'mvc/Controller.php';
require_once 'User/UserView.php';
require_once 'ErrorView.php';

/**
* Controlador de usuários
*/
class UserController implements Controller {
/**
 * @var View
 */
private $view;

/**
 * Interpreta a requisição do usuário
 * @param Request $request
 */
public function handle( Request $request ){
	if ( $request->getURI() == 'user' ){
		$this->view = UserView::getInstance();
	} else {
		$this->view = ErrorView::getInstance();
	}
}

/**
 * Recupera a resposta
 * @return View
 */
public function getResponse(){
	return $this->view;
}
}

 

User/UserView.php

<?php
require_once 'mvc/View.php';

/**
* Exibição do usuário
* @author neto
*
*/
class UserView extends View {
/**
 * Desenha a página do usuário
 * @return string
 */
public function draw(){
	return '<html><head><title>Página do Usuário</title></head><body><h1>Página do usuário</h1></body></html>';
}
}

 

E uma página de erro:

ErrorView.php

<?php
require_once 'mvc/View.php';

/**
* Página de erro
*/
class ErrorView extends View {
/**
 * Desenha a página de erro
 * @return string
 */
public function draw(){
	return '<html><head><title>Opz.</title></head><body><h1>Opz !!!</h1></body></html>';
}
}

 

Agora, nossa index.php fica assim:

 

<?php
require 'mvc/Request.php';
require 'User/UserController.php';

$controller = new UserController();
$controller->handle( Request::getInstance() );

echo $controller->getResponse()->draw();

 

A UserController espera que a requisição seja em /user

 

Se você passar qualquer coisa que não seja o esperado pela UserController a ErrorView será retornada, caso contrário, a View da página de usuário será exibida.

 

Se tiver compreendido até aqui, continuamos expondo os vários problemas nessa implementação específica e, depois, adicionamos a Model.

 

;)

Compartilhar este post


Link para o post
Compartilhar em outros sites

Como estou de viagem, não vou postar nada muito explicativo até amanhã.

 

Mas segue aí o meu artigo sobre Chain of Responsibility, um pattern muito interessante para tratar as requisições do usuário no caso da nossa recente discussão sobre MVC.

 

Design Patterns e o Desenvolvimento em PHP - Chain of Responsibility

Compartilhar este post


Link para o post
Compartilhar em outros sites

Estou agora apenas como telespectador da discussão então, para que eu não fique completamente à deriva William, como você usa essa sua classe DAO e como está o seu ValueObject?

 

mais ou menos assim:

http://forum.imasters.com.br/index.php?/topic/409112-proposta-de-fluent-interface-dao-phpoo/

 

Oi @João, eu li, reli e estou até agora dissecando cada linha que você escreveu.

-> Não curti jogar, tanto HTML nas classes php... =X

putz.. dessa forma, estamos sendo obrigados a trabalhar com alguma engine de template.. pq não rola fazer:

return '<html><head><title>Página do Usuário</title></head><body><h1>Página do usuário</h1></body></html>';
de jeito nenhum..

 

sou bem 'conhecido', por 'misturar camadas'.. mas fazer isso ai também, é uma forma de misturar..

lógico que 'mais bonita', um pouco mais 'pesada', pois o número de classes, para uma operação que era simples, está crescendo de forma exponencial.

 

Entendo os motivos de isso acontecer, e os benefícios que virão.. mas tá bacana isso.. ir vendo aos poucos, ajuda o entendimento do todo.

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.