Ir para conteúdo

POWERED BY:

Arquivado

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

Cabral Desenvolvedor

VO, DTO, Model, DAO

Recommended Posts

Sim, ambos só existem em conjunto...

Na verdade, até pode haver o TDG sem o RDG, mas nunca vi fazerem isso...

Como assim só existem em conjunto? Eu pensava até agora que eles eram aplicados de forma separado,ou seja,posso usar um RDG quanto o TDG, sem a junção dos dois.

Agora eu fiquei confuso, além de estar estudando o conceito errado!

 

Veja só como está meu sistema atualmente.

 

GatewayDataTransfer

<?

final class GatewayDataTransfer extends FConnection implements IGateway{

final public function crud($cond, FCrud $crud, array $data){
	switch(strtolower($cond)):
		case 'insert':
			return parent::execQuery($crud->insert($data));
			break;

		case 'update':
			return parent::execQuery($crud->update($data));
			break;

		case 'delete':
			return parent::execQuery($crud->delete($data));
			break;

		case 'select_all':
			return parent::fetchAll($crud->selectAll($data));
			break;

		case 'select_one':
			return parent::fetchOne($crud->selectOne($data));
			break;

		default:
			MessageHelper::getErrorException('Operação inválida.');
			break;
	endswitch;
}

}

?>

 

UserGateway

<?

final class UserGateway extends Model{

private static $table = 'users';

public static function dataSelectAll($start,$limit){
	$data = array(	
                       "table" => self::$table,
		"fields" => array("*"),
		"start" => $start,
                       "limit" => $limit,
		"orderBy" => "nome",
		"direction" => "ASC"
       );

	return parent::getGateway()->crud('SELECT_ALL', new FCrud(), $data);
}

public static function dataSelectOne(UserBean $bean){
	$data = array(	
                       "table" => self::$table,
		"fields" => array("*"),
		"where" => "idUser = " .$bean->getId()
       );

	return parent::getGateway()->crud('SELECT_ONE', new FCrud(), $data);
}

public static function dataInsert(UserBean $bean){
	$data = array(
		"table" => self::$table,
		"values" => array(
			"nome" => $bean->getNome(),
			"email" => $bean->getEmail()
		));

	parent::getGateway()->crud('INSERT', new FCrud(), $data);
}

public static function dataUpdate(UserBean $bean){
	$data = array(
		"table" => self::$table,
		"values" => array(
			"nome" => $bean->getNome(),
			"email" => $bean->getEmail()
		),
		"where" => "idUser = " .$bean->getId()
	);

	parent::getGateway()->crud('UPDATE', new FCrud(), $data);
}

public static function dataDelete(UserBean $bean){
	$data = array(
		"table" => self::$table,
		"where" => "idUser = " .$bean->getId()
	);

	parent::getGateway()->crud('DELETE', new FCrud(), $data);
}

}

?>

 

UserController

<?

class User extends Controller{

private static $bean;

function __construct(){
	$this->_title = 'Usuarios';
	self::$bean = parent::getBean('UserBean');	
}

public static function run(){
	return parent::setRun();
}

public function index(){
	$users = UserGateway::dataSelectAll(0,10);

	$i = 0;
	while($i <= count($users)):
		$data['data'] = $users;
		$i++;
	endwhile;

	parent::_show(new View('index', $data));
}

public function select(){
	self::$bean->setId(28);
	$data = UserGateway::dataSelectOne(self::$bean);
	parent::_show(new View('select', $data));	
}

public function insert(){
	self::$bean->setNome('Guilherme Pereira Nogueira');
	self::$bean->setEmail('guilherme.std1@gmail.com');
	UserGateway::dataInsert(self::$bean);
	parent::_show(new View('insert', null));
}

public function update(){
	self::$bean->setId(27);
	self::$bean->setNome('Guilherme');
	self::$bean->setEmail('guilherme.std1@gmail.com');
	UserGateway::dataUpdate(self::$bean);
	parent::_show(new View('update', null));
}

public function delete(){
	self::$bean->setId(27);
	UserGateway::dataDelete(self::$bean);
	parent::_show(new View('delete', null));
}

}

?>

 

Sei que coloquei uma montueira de código, mas analisa bem e me diz: Eu tentei implementar um Gateway Data Transfer,pois pelo que li deste padrão,ele faz uma composição de objeto no Model, porém isto também pode parecer um Table Data Gateway, não? Veja que, no meu UserGateway, eu faço uma composição. O que tem de errado aí, o que pode melhorar? Ao seu ver, minha implementação está muito amarrada? Não coloquei outras classes por que não precisa, só quis ser mais objetivo neste post.

Compartilhar este post


Link para o post
Compartilhar em outros sites
Como assim só existem em conjunto? Eu pensava até agora que eles eram aplicados de forma separado,ou seja,posso usar um RDG quanto o TDG, sem a junção dos dois.

Pode existir um TDG sem um RDG, mas o oposto não é verdade.

Por quê?

Porque um RDG faz uso de um objeto TDG para acessar o banco de dados.

Se você colocar a função de persistência dentro do RDG ele já não é mais um RDG, é um Active Record.

 

Observe que se eu retirar o RDG do exemplo, eu ainda posso utilizar o TDG, retornando somente arrays...

 

Algumas observações sobre o seu código:

GatewayDataTransfer é final, logo, você não precisa declarar os métodos como finais...

 

Outra coisa:

case 'insert':
                               return parent::execQuery($crud->insert($data));
                               break;

                       case 'update':
                               return parent::execQuery($crud->update($data));
                               break;

                       case 'delete':
                               return parent::execQuery($crud->delete($data));
                               break;

                       case 'select_all':
                               return parent::fetchAll($crud->selectAll($data));
                               break;

                       case 'select_one':
                               return parent::fetchOne($crud->selectOne($data));
                               break;

                       default:
                               MessageHelper::getErrorException('Operação inválida.');
                               break;

Tem certeza que essas são as únicas operações possíveis sobre o banco de dados?

Caso apareça mais alguma você terá que ir e editar esse switch... Por isso, sua implementação está "amarrada".

 

UserGateway é o que eu sou totalmente contra. As operações sobre o banco de dados são basicamente as mesmas para qualquer tabela. O que muda é somente a estrutura da mesma.

Se você usa MVC, precisa de 1 Model, 1 ou mais Controllers e algumas Views para cada entidade. Além disso, agora tem que se preocupar com um Gateway específico para cada uma?

 

No meu exemplo, eu faço uma descrição manual da tabela, mas é possível fazer isso automaticamente. No MySQL existe o comando DESCRIBE que retorna todas as informações que você precisa sobre qualquer elemento do banco, inclusive tabelas. Em outros SGBDs é um pouco mais complicado, precisamos consultar as "meta-tabelas" selecionando alguns campos, mas também é possível.

 

[...] pois pelo que li deste padrão,ele faz uma composição de objeto no Model, [...]

final class UserGateway extends Model

Composição, mas você está utilizando herança... :ermm:

 

É algo que muita gente confunde. Uma tabela NÃO É um Model, ela FAZ PARTE de um. O Model agrega muito mais coisas, como a lógica do negócio, validação, etc...

No meu mundinho perfeito, eu faria algo assim:

 

class UserModel extends AbstractModel {
private $dal;
public function __construct(DataAccessLayer $dal) {
   	$this->dal = $dal;
}
}

class DbTable implements DataAcessLayer {
}

class DbXML implements DataAccessLayer {
}

class TextFileFacade implements DataAccessLayer {
}

 

Ou seja, meu Model receberia uma camada de acesso a dados. Hoje pode ser uma tabela no banco de dados, amanhã eu posso mudar para o banco de dados baseado em XML, ou, para exemplos simples, um simples arquivo de texto.

Para alterar isso, basta eu alternar entre as instâncias que eu passo ao Model na hora de instanciá-lo:

$model1 = new UserModel(new DbTable('usuarios'));
$model2 = new UserModel(new DbXML('/path/to/usuarios.xml'));
$model3  = new UserModel(new TextFileFacade('/path/to/usuarios.txt'));

 

A dificuldade de trazer isso pra realidade é: como implementar consultas complexas tão poderosas quando um SELECT SQL em arquivos de texto? Bem complicado.

Ou seja, teria que limitar por baixo a funcionalidade e meu Model poderia fazer apenas operações básicas de CRUD, mas isso é impraticável, precisamos da complexidade.

 

É possível abstrair as consultas SQL, transformá-las em objetos (Ex.: Zend_Db_Select) e tentar expandir esse conceito para as demais camadas, entretanto, traduzir comandos SQL em operações sobre arquivos não é exatamente trivial...

 

Por últmo, em UserController eu não entendi porque a propriedade $bean é estática...

Pensando melhor, não é nem o Controller que lida com isso, é o Model que é responsável por criar e alterar Beans.

Mas a certeza que tenho é que ela não pode ser estática. Você nem sempre vai tratar um Bean de cada vez, ou vai?

 

Tente criar uma implementação com base no exemplo que eu dei e vê o que sai...

Compartilhar este post


Link para o post
Compartilhar em outros sites
Tem certeza que essas são as únicas operações possíveis sobre o banco de dados?

Caso apareça mais alguma você terá que ir e editar esse switch... Por isso, sua implementação está "amarrada".

Não, porém não sei por que não pensei nessa possibilidade! :o

Ôoo negócio complicado!

 

 

Composição, mas você está utilizando herança...

Veja bem o código abaixo. Estou usando composição para obter os dados do meu bean.

 

public static function dataInsert(UserBean $bean){
       $data = array(
            "table" => self::$table,
            "values" => array(
                   "nome" => $bean->getNome(),
                   "email" => $bean->getEmail()
             ));

       parent::getGateway()->crud('INSERT', new FCrud(), $data);
}

Tá errado, no conceito do Gateway Data Transfer?

 

É algo que muita gente confunde. Uma tabela NÃO É um Model, ela FAZ PARTE de um. O Model agrega muito mais coisas, como a lógica do negócio, validação, etc...

Sim, uma tabela faz parte do model, mas não é o model. Você me confundiu ainda mais, pois como que validação faz parte do Model? Isso não seria a responsabilidade do meu Controller?

 

Por últmo, em UserController eu não entendi porque a propriedade $bean é estática...

Pensando melhor, não é nem o Controller que lida com isso, é o Model que é responsável por criar e alterar Beans.

Mas a certeza que tenho é que ela não pode ser estática. Você nem sempre vai tratar um Bean de cada vez, ou vai?

Ah, não tenho nenhum motivo assim e nem explicação do que por que usei estático,só usei. Tá, eu fiz isso sem pensar muito, mas isso acontece, vou rever este conceito.

O meu Model pega os valores de um determinado Bean, porém a responsabilidade de setar os valores não é do Controller?

Por que não pode ser estática? Não sei se vou ficar tratando sempre os meus Beans, mas se caso isso ocorra, já está implementado, ou isso é um erro?

 

Tente criar uma implementação com base no exemplo que eu dei e vê o que sai...

Farei isso, sem dúvidas!

 

No mais, preciso de ajuda! :thumbsup:

Compartilhar este post


Link para o post
Compartilhar em outros sites
Sim, uma tabela faz parte do model, mas não é o model. Você me confundiu ainda mais, pois como que validação faz parte do Model? Isso não seria a responsabilidade do meu Controller?

Como diz a minha avó:

De jeeeeito, manêrrrrra!

 

A validade dos dados é uma característica que deve ser garantida pelo modelo, não pelo Controller.

O Controller processa requisições e . É o conceito de "Fat Model, Skinny Controller". Dê uma pesquisada... Alguns são contra, mas não acho os argumentos deles muito válidos.

 

Veja bem o código abaixo. Estou usando composição para obter os dados do meu bean.

 

public static function dataInsert(UserBean $bean){
       $data = array(
            "table" => self::$table,
            "values" => array(
                   "nome" => $bean->getNome(),
                   "email" => $bean->getEmail()
             ));

       parent::getGateway()->crud('INSERT', new FCrud(), $data);
}

Tá errado, no conceito do Gateway Data Transfer?

 

Olha, errado é uma palavra muito forte... O problema maior é que, uma operação de INSERT é essencialmente igual para qualquer tabela, o que varia são os dados. Então pra que criar um método de inserção para cada entidade se eu posso criar um genérico e variar somente os dados.

 

Eu perco um pouco do controle sobre os dados, beleza, mas ao tentar inserir dados que não condizem com a tabela, um erro será lançado, ou seja, não dá pra você fazer besteira, nem se quiser.

 

O meu Model pega os valores de um determinado Bean, porém a responsabilidade de setar os valores não é do Controller?

Por que não pode ser estática? Não sei se vou ficar tratando sempre os meus Beans, mas se caso isso ocorra, já está implementado, ou isso é um erro?

Mas por que o Model precisa guardar instâncias do Bean? Ele age sobre eles, sim, mas ele não POSSUI beans.

 

Note no meu exemplo:

/**
       * Salva os dados em $data no banco de dados.
       * A decisão por inserção ou atualização é feita automaticamente.
       * 
       * @param $data : os dados a inserir ou atualizar
       * @return int : o número de linhas afetadas
       */
       public function save(array $data) {
               if(!array_key_exists($this->idColName, $data)
                       || $data[$this->idColName] === null) {
                       return $this->insert($data);
               } else {
                       return $this->update($data);
               }
       }

 

O objeto Table não possui nenhum dado armazenado na tabela que ele diz respeito. Eu uso arrays para as operações e isso basta. Nada além do estritamente necessário para que as operações ocorram.

 

Aí você pensa assim:

Ah, mas aí eu posso incluir qualquer besteira aí que ele vai inserir...

 

Sim, o objeto Table não tem responsabilidade de saber se o dado é válido ou não, ele simplesmente faz as operações.

Para garantir a integridade dos dados, eu preciso passar dados válidos para a mesma. É aí que entra o Model, que vai fazer toda a lógica do negócio e as validações necessárias antes de acionar Table.

 

Isso é separação de responsabilidades!

Compartilhar este post


Link para o post
Compartilhar em outros sites

Sim, uma tabela faz parte do model, mas não é o model. Você me confundiu ainda mais, pois como que validação faz parte do Model? Isso não seria a responsabilidade do meu Controller?

 

Depende do tipo de validação, validações referentes aos dados enviados pelo usuário, ou seja, validar a requisição, deve ser feita no Controller, como por exemplo verificar se determinada requisição foi feita através de POST, se os dados não estão vazios, prevenir XSS Injection, etc.

 

Agora se essa validação for referente às regras de negócio da tua aplicação, ela deve ser feita na camada de Model. Digamos que você esteja com uma aplicação de e-commerce, e que você não permite novos usuários efetuarem uma compra superior à X Reais, essa validação deve ser efetuada na Model, e não no Controller.

Compartilhar este post


Link para o post
Compartilhar em outros sites
Depende do tipo de validação, validações referentes aos dados enviados pelo usuário, ou seja, validar a requisição, deve ser feita no Controller, como por exemplo verificar se determinada requisição foi feita através de POST, se os dados não estão vazios, prevenir XSS Injection, etc.

 

Perfeito!!! :clap:

 

Eu realmente me referia às validadações dos dados como objetos das regras de negócio...

Compartilhar este post


Link para o post
Compartilhar em outros sites
Olha, errado é uma palavra muito forte... O problema maior é que, uma operação de INSERT é essencialmente igual para qualquer tabela, o que varia são os dados. Então pra que criar um método de inserção para cada entidade se eu posso criar um genérico e variar somente os dados.

Farei isso. Na verdade eu vou é reescrever toda essa estrutura. Ahh cara, quero muito aprender esses padrões, mas estou tendo uma dificuldade enorme. Pensava ser uma coisa, agora já é outra, isso é muito cansativo, não que eu esteja com preguiça, pelo contrário, é um ânimo pra evoluir.

 

Eu perco um pouco do controle sobre os dados, beleza, mas ao tentar inserir dados que não condizem com a tabela, um erro será lançado, ou seja, não dá pra você fazer besteira, nem se quiser.

Se eu não setar os valores no controller, então onde eu farei isso? Pois no meu gateway, estou pegando os dados. A responsabilidade da Model é obter, e não setar, ou falei besteira?

 

Se você colocar a função de persistência dentro do RDG ele já não é mais um RDG, é um Active Record.

Como assim cara? Gosta de pedir um favor, teria como você postar uma UML do TDG e RDG, e explicar de forma bem simples, como se estivesse falando pra uma criança de 7 anos, o funcionamento,responsabilidades e exemplos de código? Se não for te dar trabalho demais, mas é que pesquisei sobre estes padrões, não achei muita coisa a respeito. Peço que tenha paciência, ainda sou iniciante e quero evoluir! :thumbsup:

Compartilhar este post


Link para o post
Compartilhar em outros sites
Farei isso. Na verdade eu vou é reescrever toda essa estrutura. Ahh cara, quero muito aprender esses padrões, mas estou tendo uma dificuldade enorme. Pensava ser uma coisa, agora já é outra, isso é muito cansativo, não que eu esteja com preguiça, pelo contrário, é um ânimo pra evoluir.

Cara, depois dizem que programação está mais pra humanas do que pra exatas... MENTIRA!!!

É assim mesmo, é igual àqueles exercícios de análise combinatória no ensino médio ou cálculo na faculdade: aquela porcaria não faz sentido nenhum, quando o professor resolve, você fala...

Ah tá, entendi...

Aí você vai tentar fazer sozinho em casa e não consegue...

 

Muuuuito tempo depois, quando você acha que nem se lembra daquilo, surge um problema e você fala:

Eu já vi isso em algum lugar...

E a solução parece tão natural que é como se você soubesse aquilo desde que nasceu...

você precisava de ver eu, que passei raspando em Cálculo 2 quando fiz, ontem ensinando minha namorada a fazer alguns exercícios...

 

Se eu não setar os valores no controller, então onde eu farei isso? Pois no meu gateway, estou pegando os dados. A responsabilidade da Model é obter, e não setar, ou falei besteira?

Se você obtém os dados lá, porque você já não os seta também? Vai ficar espalhando isso pela aplicação???

 

Entenda:

Controller processa requisições, nada mais...

Tudo o que diz respeito a uma requisição é feito no controller, agora, obtenção e criação de dados é tudo model...

 

Como assim cara? Gosta de pedir um favor, teria como você postar uma UML do TDG e RDG, e explicar de forma bem simples, como se estivesse falando pra uma criança de 7 anos, o funcionamento,responsabilidades e exemplos de código? Se não for te dar trabalho demais, mas é que pesquisei sobre estes padrões, não achei muita coisa a respeito. Peço que tenha paciência, ainda sou iniciante e quero evoluir!

 

activeRecordSketch.gif

 

An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data.

O "diagrama" de um AR é praticamente só isso aí... Ele é meio "auto-suficiente"...

 

Observe o diagrama do meu post-exemplo.

  • Driver: cuida do acesso ao banco de dados.
  • Table: cuida da estrutura de uma tabela do banco de dados e as operações sobre ela efetuadas.
  • Row: representa os dados de uma linha da tabela.

Perceba, são frases curtas, justamente porque são responsabilidades únicas.

 

Agora

Driver + Table + Row + Lógica do Negócio = Active Record

 

O Active Record viola o Princípio da Responsabilidade Única (SRP) pois concentra dentro de um só objeto os dados de uma linha da tabela, informações sobre a tabela, o acesso ao banco de dados e a lógica do negócio.

 

Ou seja, essa parte que eu escrevi está errada:

Se você colocar a função de persistência dentro do RDG ele já não é mais um RDG, é um Active Record.

Não é adicionando a função de persistência ao RDG que o fará virar um Active Record, mas é um caminho para tal...

 

Foi? :grin:

Compartilhar este post


Link para o post
Compartilhar em outros sites

P.S.: curti tanto o resultado da implementação que foi parar no meu blog:

http://henriquebarcelos.in/blog/2012/05/21/design-patterns-table-row-gateway-e-table-data-gateway-na-pratica/

Compartilhar este post


Link para o post
Compartilhar em outros sites
Se você obtém os dados lá, porque você já não os seta também? Vai ficar espalhando isso pela aplicação???

Lá onde, no controller? :ermm:

 

Observe o diagrama do meu post-exemplo.

 

Driver: cuida do acesso ao banco de dados.

Table: cuida da estrutura de uma tabela do banco de dados e as operações sobre ela efetuadas.

Row: representa os dados de uma linha da tabela.

 

Mais pra que e por quê eu faria uma implementação tipo a sua do Row Gateway, já que retorna dados de uma linha da tabela, se no caso o PDO já faz isso pra mim com o objeto fetch()? Até agora a ficha não caiu!

 

Sobre o table, as operações mensionadas, você se fere ao CRUD, entre outras consultas, como exibir campos da tabela e seus tipos?

 

Não é SÓ adicionando a função de persistência ao RDG que o fará virar um Active Record, mas é um caminho para tal...

Mais se não é só isso, o que mais seria pro pattern virar um Actice Record?

Compartilhar este post


Link para o post
Compartilhar em outros sites
Lá onde, no controller?

Não, no Model...

O argumento melhor que posso oferecer é:

Você busca os dados no model, aí você repassa esses dados pro controller setá-los no Bean?

Não seria mais fácil o próprio model criar o Bean e devolvê-lo já com os dados setados

 

Mais pra que e por quê eu faria uma implementação tipo a sua do Row Gateway, já que retorna dados de uma linha da tabela, se no caso o PDO já faz isso pra mim com o objeto fetch()? Até agora a ficha não caiu!

Fetch o meu exemplo também faz... Com fetch você cria arrays ou objetos stdClass. RDG é um pouco mais que isso, não é???

 

Mais se não é só isso, o que mais seria pro pattern virar um Actice Record?

Agora

Driver + Table + Row + Lógica do Negócio = Active Record

Compartilhar este post


Link para o post
Compartilhar em outros sites

Muita calma nesta hora, acho que estou começando a entender! ^_^

 

Não, no Model...

O argumento melhor que posso oferecer é:

Você busca os dados no model, aí você repassa esses dados pro controller setá-los no Bean?

Não seria mais fácil o próprio model criar o Bean e devolvê-lo já com os dados setados

Então, eu usaria os métodos mágicos __set e __get, no meu model genérico?

 

Fetch o meu exemplo também faz... Com fetch você cria arrays ou objetos stdClass. RDG é um pouco mais que isso, não é???

Até o momento, não sei. Você é quem poderia me responder melhor: Então, é? Afinal das contas, qual outra responsabilidade do RDG a não ser retornar uma linha da minha tabela? Algo me diz qie isso é tão simples, mas estou complicando demais as coisas!

Compartilhar este post


Link para o post
Compartilhar em outros sites
Então, eu usaria os métodos mágicos __set e __get, no meu model genérico?

Não entendi o objetivo aqui...

 

Até o momento, não sei. Você é quem poderia me responder melhor: Então, é? Afinal das contas, qual outra responsabilidade do RDG a não ser retornar uma linha da minha tabela? Algo me diz qie isso é tão simples, mas estou complicando demais as coisas!

RDG não RETORNA nada, ele é uma REPRESENTAÇÃO da linha da tabela. Quem retorna é Table, que utiliza Driver para fazer isso.

O que é RDG afinal?

Simplisticamente falando, o RDG não passa de um "revestimento" OO para um array... A única diferença é que você pode invocar métodos como delete e save, que acionarão Table utilizando os dados contidos em Row.

 

Observe que no meu exemplo tem funcionalidades a mais:

Na hora de fazer uma atualização, eu só altero os campos que foram alterados, deixando o restante como estava antes, por isso mantenho um registro de tudo o que foi modificado.

 

Além disso, também mantenho uma cópia dos dados originais da linha.

Por quê?

Imagine que eu queira atualizar a chave primária daquela entrada da tabela.

Eu tenho algo como:

$user = $table->getById(1);
$user->set('id', 20);
$user->save();

 

Na hora de fazer o update, eu passo os dados de $user para $table.

Aí eu vou montar a query:

UPDATE users SET id = 20 WHERE id = 20
-- Ooops!!!

 

Não vai atualizar nada, concorda?

Eu deveria fazer

UPDATE users SET id = 20 WHERE id = 1

 

Isso só é possível se eu mantiver os dados antigos no objeto.

 

Ou seja, RDG é um pouco mais que um simples array...

Compartilhar este post


Link para o post
Compartilhar em outros sites

Opa, desculpe aí pela demora, andei bastante ocupado esses dias!

 

Não entendi o objetivo aqui...

Você disse anteiormente que..

 

Você busca os dados no model, aí você repassa esses dados pro controller setá-los no Bean?

Não seria mais fácil o próprio model criar o Bean e devolvê-lo já com os dados setados

E diante da sua pergunta, eu respondi fazendo outra pergunta: Eu deveria suar o __set e __get no meu módel genérico?

Eu não entendi 100% o que você ainda quis dizer, poderia ser mais claro por favor?

 

E você não está mais usando aquelas classes Adapter que postou aqui uns tempos atrás?

Quanto tempo levou para montar essa nova estrutura?

Compartilhar este post


Link para o post
Compartilhar em outros sites
E diante da sua pergunta, eu respondi fazendo outra pergunta: Eu deveria suar o __set e __get no meu módel genérico?

Eu não entendi 100% o que você ainda quis dizer, poderia ser mais claro por favor?

Eu não entendi o que você chama de "Model Genérico"...

 

E você não está mais usando aquelas classes Adapter que postou aqui uns tempos atrás?

Quanto tempo levou para montar essa nova estrutura?

No meu "framework" eu utilizo sim, mas como falei no post do exemplo, eu removi isso pra simplificar.

 

Quanto tempo levei???

Bom... eu tinha uma ideia inicial, mas era simples demais pra demonstrar o que eu queria, já estava na metade quando me dei conta disso, aí recomecei... Demorei umas 8h pra terminar tudo...

Compartilhar este post


Link para o post
Compartilhar em outros sites

Pessoal, devido a correria de um projeto aqui, fui acompanhando aos poucos as postagens no tópico, mas adorei a colaboração de vocês! 0/

 

A implementação de exemplo do TDG e RDG foi muito boa e muito bem comentada, mas só para esclarecer uma dúvidas a mais:

 

Este TDG e RDG é genérico, ou seja, serve para qualquer tabela certo?

 

Então seria dentro do meu Model que eu instanciaria o TDG e criaria objetos RDG com ele, tudo isso em tempo de execução, sem a necessidade de criar um TDG para cada tabela do meu banco de dados correto?

 

A model serviria apenas para o modelo de negócios e a persistência no banco seria totalmente genérica e manipulada por este TDG e RDG.

 

Em questão da integridade, quando desabilitada, os dados não podem ser salvos, apenas lidos, o que permite retonar um RDG com campos e dados de consultas com JOIN pelo o que entendi.

 

Outra coisa que notei é que o RDG armazena os dados antigos e as alterações e depois compara os mesmos pegando apenas os campos que foram modificados e passando para o update do mesmo no bd.

 

Quando um TDG é criado, é passado como parâmetro no construtor um objeto Driver, mas o mesmo não poderia ser criado dentro do próprio TDG? (Composição). E se fosse utilizado Singleton, seria necessário passar a instância do Singleton também por parâmetro? Ou diretamente dentro do TDG?

 

Alguma observação sobre as questões que fiz acima?

 

Abração

Compartilhar este post


Link para o post
Compartilhar em outros sites
Eu não entendi o que você chama de "Model Genérico"...

Então, este Model genérico seria ele o responsável por instanciar meus Beans, entre outras coisas.

 

Quanto tempo levei???

Bom... eu tinha uma ideia inicial, mas era simples demais pra demonstrar o que eu queria, já estava na metade quando me dei conta disso, aí recomecei... Demorei umas 8h pra terminar tudo...

É, levou pouco tempo! Acho que eu levaria sei lá, 1 semana, até deixar a idéia bem solida e ir para a implementação.

Compartilhar este post


Link para o post
Compartilhar em outros sites
Este TDG e RDG é genérico, ou seja, serve para qualquer tabela certo?

 

Então seria dentro do meu Model que eu instanciaria o TDG e criaria objetos RDG com ele, tudo isso em tempo de execução, sem a necessidade de criar um TDG para cada tabela do meu banco de dados correto?

Sim, correto... É a maneira que eu escolhi... entretanto, é possível obter a estrutura das tabelas no proprio banco de dados.

Com MySQL é muito simples, basta utilizar o comando DESCRIBE. Com outros SGBDs que eu conheço (Oracle, PostgreSQL e SQLite), é necessário consultar as "metatabelas" para obter as estruturas...

 

Quanto a instanciar dentro do model, eu já chego lá...

 

A model serviria apenas para o modelo de negócios e a persistência no banco seria totalmente genérica e manipulada por este TDG e RDG.

Exato, essa é a responsabilidade do Model, nenhuma mais...

 

Em questão da integridade, quando desabilitada, os dados não podem ser salvos, apenas lidos, o que permite retonar um RDG com campos e dados de consultas com JOIN pelo o que entendi.

Sim, no meu exemplo é exatamente isso, mas é possível abordar de outra forma...

Essencialmente, dados vindos de um JOIN são somente para leitura, entretanto, é possível alterar somente os campos específicos da tabela representada pelo objeto Table que criou o objeto Row, optei simplesmente por não fazê-lo, pois não julgo necessário...

 

Outra coisa que notei é que o RDG armazena os dados antigos e as alterações e depois compara os mesmos pegando apenas os campos que foram modificados e passando para o update do mesmo no bd.

Exatamente, é o conceito de UPDATE ON DEMAND, muito difundido nos frameworks em geral. Além de "salvar" um pouco de tempo de acesso ao banco de dados, pense por exemplo no caso da tabela usuarios, onde a senha armazenada é na verdade um hash da senha real...

Se eu fosse utilizar as funções de hash no próprio SGDB, eu teria problemas, pois a cada atualização eu estaria calculando o hash do hash, modificando a senha do usuário...

 

Esse último problema não acontece no exemplo que eu dei pois o cálculo do hash é feito na aplicação, mas é possível fazer isso também direto na query.

Quando um TDG é criado, é passado como parâmetro no construtor um objeto Driver, mas o mesmo não poderia ser criado dentro do próprio TDG? (Composição). E se fosse utilizado Singleton, seria necessário passar a instância do Singleton também por parâmetro? Ou diretamente dentro do TDG?

Boa observação... Eu NÃO RECOMENDO fazer isso.

 

Como eu faria se não quisesse mais utilizar MySQL? Se quiser utilizar PostgreSQL, ou Oracle, ou SQLite, ou qualquer outro SGBD???

Vou ter que ir lá dentro da classe e mexer nela...

Ok, para a maioria dos desenvolvedores PHP não é um grande problema, afinal, é só ir lá e alterar o instanciamento dentro do construtor.

 

Agora vamos pensar em C++ ou Java. Eles possuem há tempos o conceito de bibliotecas (arquivos *.a, *.so, *.dll no caso do C, *.jar no caso do Java), às quais você não tem acesso ao código-fonte, só à API. Você só chama as funções/métodos sem ter ideia nenhuma de como ela é internamente implementada.

O PHP possui algo semelhante, os pacotes PHAR.

 

Imagine que você está desenvolvendo algo que será utilizado por terceiros no futuro, e você faz:

class Table
private $driver;
public function __construct() {
   	$this->driver = new Driver(new MySQLi());
}
}

 

Aí, depois de testar e ver que funciona que é uma beleza, você joga tudo isso num PHAR pra se certificar de que ninguém vai mexer e correr o risco de ferrar com tudo o que você fez... Distribui esse código, seja emprestando para um amigo, ou vendendo... A pessoa que utiliza esse pacote também utiliza MySQL, funciona tudo perfeito até que um dia ela precisa utilizar PostgreSQL. Ela vai revirar a API que você forneceu junto de cima abaixo e não vai encontrar nada sobre como alterar a API de acesso ao SGBD...

 

Esse problema é chamado de Dependência Oculta. Seu código tem uma dependência que só é possível encontrar olhando a estrutura interna.

 

Aí você pensa:

Ah, mas isso aqui só eu vou utilizar, não sei o que é esse tal de PHAR e nem quero saber...

 

Você mesmo pode um dia precisar alterar o SGBD e para tal, terá que mexer numa classe que já está pronta. Isso é péssimo.

 

O conceito bem simples que eu utilizo no exemplo chama-se Injeção de Dependências. Com isso, eu torno todas as dependências de uma determinada classe explícitas, lhes passando as instâncias dos objetos que ela depende no construtor (ou em algum método).

 

Dessa forma, eu posso fazer assim:

$tableMy = new Table('users', new Driver(new MySQLi(...))));
$tablePg = new Table('clients', new Driver(new PgSQL()))); // fictício, só existe API procedural para PostgreSQL no PHP, você teria que criar uma OO, o que não é muito difícil

 

Por que raios eu teria dados em 2 SGBDs? Vai saber... Mas e se um dia tiver? Vai ficar se descabelando? Não é melhor prevenir do que remediar?

 

Quer usar Singleton???

$table = new Table('users', new Driver(API_do_meu_bd()::getInstance()));

Resolvido...

 

Para o Model, funciona do mesmo jeito, o ideal seria ter uma lista das tabelas às quais ele faz referência e isso deveria lhe ser passado.

Entretanto, eu normalmente instancio o Model a partir do Controller e não é responsabilidade deste saber quais tabelas um determinado Model referencia...

É possível criar um "FrontModel" ou um ModelFactory que fizesse esse trabalho, recebendo uma lista de dependências Model x Tabelas e na hora de instanciar o Model as injetasse, mas nunca tentei essa abordagem.

 

Como normalmente o Model é realmente afetado a cada mudança e você raramente vai mudar o nome da tabela, não vejo problema nenhum em instanciar os objetos Table dentro do Model. Mantê-los como atributos de classe ou não também vai da escolha do freguês... Já fiz dos dois jeitos, não sei te dizer qual é melhor... O mais prático é manter atributos, mas não sei se posso dizer que isso é o certo...

 

____________________________________________________________________________________________

 

 

Então, este Model genérico seria ele o responsável por instanciar meus Beans, entre outras coisas.

Você está confundindo, o model não é genérico, a tabela é...

Não tem como o model ser genérico, a lógica de negócio varia para cada entidade...

Mas sim, é no model que você instancia esse tipo de coisa...

Compartilhar este post


Link para o post
Compartilhar em outros sites

Henrique Barcelos

Tá, mais eu uso o Setter no MODEL ou no CONTROLLER? Pois não se reparou bem, eu uso os GETTERS do meu Gateway, sacou? Me desculpe, mas ainda estou confuso. Sei que estou sendo chato, mais eu quero entender.

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.