Pela primeira vez desenvolvi um sistema usando o padrão Modelo-Visão-Controlador. O modelo é aplicado em dois níveis. No nível da aplicação, a visão é o browser, e o controlador e o modelo rodam no servidor. Mas também uso o MVC no nível do browser, onde o modelo é um objeto contendo os dados sendo operados, a visão é o formulário em que os dados do modelo são exibidos e editados, e o controlador trata os eventos de interface (perda de foco, cliques, etc.)
Também usei o padrão Objeto de Transferência de Dados (Data Transfer Object) para passar as informações de uma camada à outra, e o padrão Objeto de Acesso a Dados (Data Access Object) para isolar o objeto da aplicação do banco de dados.
Com isso meu sistema ficou cheio de transformações de dados, e me pergunto se alguém teria uma sugestão para simplificar as coisas.
Vou tentar descrever abaixo as camadas e o fluxo de dados do sistema.
1. PHP (HTTP)
Preenche o ARRAY $_REQUEST com os dados vindos do navegador (campos de formulário, informações da querystring): informações de controle (qual controlador instanciar, qual método chamar) e dados a serem gravados em objeto(s) no banco de dados.
2. CONTROLADOR DO SERVIDOR
Instancia um OBJETO DE TRANSFERÊNCIA, preenchendo-o com os dados de objeto contidos no ARRAY $_REQUEST.
3. MODELO DO SERVIDOR
Instancia um OBJETO DA APLICAÇÃO, aciona seus métodos e/ou preenche suas propriedades com os valores do OBJETO DE TRANSFERÊNCIA vindo do controlador.
4. OBJETO DA APLICAÇÃO
Instancia um OBJETO DE TRANSFERÊNCIA e preenche-o com seus dados.
5. OBJETO DE ACESSO A DADOS (DAO)
Prepara um COMANDO SQL com os dados do OBJETO DE TRANSFERÊNCIA.
6. PHP (MYSQL)
Retorna um ARRAY $row como resultado da execução do COMANDO SQL.
7. OBJETO DE ACESSO A DADOS (DAO) (2)
Instancia um OBJETO DE TRANSFERÊNCIA e preenche-o com os dados do ARRAY $row.
8. OBJETO DA APLICAÇÃO (2)
Preenche suas propriedades com os dados do OBJETO DE TRANSFERÊNCIA vindos do DAO.
9. MODELO DO SERVIDOR (2)
Entrega o OBJETO DA APLICAÇÃO atualizado para o controlador.
10. CONTROLADOR DO SERVIDOR (2)
Entrega o OBJETO DA APLICAÇÃO para a visão.
11. OBJETO DA APLICAÇÃO (3)
Por solicitação da visão, instancia um OBJETO DE TRANSFERÊNCIA e o converte para string JSON (Javascript Object Notation). (OBJETO DE TRANSFERÊNCIA EM JAVASCRIPT).
12. VISÃO DO SERVIDOR (2)
Injeta o OBJETO DE TRANSFERÊNCIA EM JAVASCRIPT no código do modelo do browser.
var objeto = new Objeto(<?php echo $json ?>);
13. MODELO DO BROWSER
Instancia o OBJETO DA APLICAÇÃO EM JAVASCRIPT com os dados do OBJETO DE TRANSFERÊNCIA EM JAVASCRIPT.
13. VISÃO DO BROWSER
Preenche CAMPOS DE FORMULÁRIO com os dados do OBJETO DA APLICAÇÃO EM JAVASCRIPT.
14. CONTROLADOR DO BROWSER
Controla a interface da aplicação, atualizando os CAMPOS DE FORMULÁRIO (visão) e o OBJETO DA APLICAÇÃO EM JAVASCRIPT (modelo) de acordo com a digitação e outras ações do usuário. Até que o usuário clica em um botão para salvar as alterações.
15. OBJETO DA APLICAÇÃO EM JAVASCRIPT
Por solicitação do controlador do browser, instancia um OBJETO DE TRANSFERÊNCIA EM JAVASCRIPT.
16. CONTROLADOR DO BROWSER (2)
Preenche um segundo formulário invisível (CAMPOS DE FORMULÁRIO INVISÍVEL) com os dados do OBJETO DE TRANSFERÊNCIA EM JAVASCRIPT a serem transmitidos para o servidor, e outras informações. E submete o formulário.
E voltamos ao início do ciclo.
Não está "burocrático" demais? É isso mesmo? Alguma ideia?
(EDIÇÃO EM 15/06/2011):
Para dar uma ideia melhor, eis aqui um esquema reduzido do funcionamento da minha implementação MVC. Os comentários com reticências (// ...) indicam lugares onde poderia/deveria haver mais códigos (outros métodos, por exemplo), mas não são necessários para esta explicação.
index.php
$modulo = $_REQUEST['modulo']; // O controlador a ser instanciado.
$operacao = $_REQUEST['operacao']; // O método do controlador que será executado.
$controlador = Controlador::factory($modulo);
$controlador->$operacao();
Supondo que $modulo = 'Pessoa' e $operacao = 'atualizar', os dois comandos acima equivaleriam a:
$controlador = new ControladorPessoa();
$controlador->atualizar();
Controlador.php + ControladorPessoa.php
abstract class Controlador { // ... static function factory($nomeModulo) { $nomeClasse = "Controlador{$nomeModulo}"; return new $nomeClasse(); } }
class ControladorPessoa extends Controlador { // ... function atualizar() { $to = new TransferObject(); $to->setCampo('cpf', $_REQUEST['cpf']); $to->setCampo('nome', $_REQUEST['nome']);
$modelo = new ModeloPessoa(); $pessoa = $modelo->atualizar($to);
$visao = new VisaoPessoa(); $visao->exibir($pessoa); } }[/codebox]
Modelo.php + ModeloPessoa.php
[codebox]abstract class Modelo { // ... }
class ModeloPessoa extends Modelo { // ... function atualizar(TransferObject $to) { $pessoa = new Pessoa(); $pessoa->abrir($to->getCampo('cpf')); $pessoa->setNome($to->getNome()); $pessoa->atualizar(); return $pessoa; } }
ObjetoDaAplicacao.php + Pessoa.php
abstract class ObjetoDaAplicacao { // ... }
class Pessoa extends ObjetoDaAplicacao { private $cpf; private $nome; // ... function exportarTO() { $to = new TransferObject(); $to->setCampo('cpf', $this->getCpf()); $to->setCampo('nome', $this->getNome()); return $to; } function importarTO(TransferObject $to) { $this->setCpf($to->getCampo('cpf')); $this->setNome($to->getCampo('nome')); } function abrir($cpf) { $dao = new DAOPessoa(); $to = $dao->abrir($cpf); $this->importarTO($to); } abstract function atualizar() { $dao = new DAOPessoa(); $to = $this->exportarTO(); $dao->atualizar($to); } }[/codebox]
DAO.php + DAOPessoa.php
[codebox]abstract class DAO { // ... function executarSQL($sql) { // ... (Conectar, executar comando SQL, desconectar.) return $row; } }
class DAOPessoa extends DAO { // ... function abrir($cpf) { $sql = <<<SQL SELECT * FROM PESSOA WHERE CPF='{$cpf}'; SQL; $row = $this->executarSQL($sql); $to = new TransferObject(); $to->setCampo('cpf', $row['CPF']); $to->setCampo('nome', $row['NOME']); return $to; }
function atualizar(TransferObject $to) { $sql = <<<SQL UPDATE PESSOA SET NOME='{$to->getCampo('nome')}' WHERE CPF='{$to->getCampo('cpf')}'; SQL; $this->executarSQL($sql); } }
Visao.php + VisaoPessoa.php
abstract class Visao { // ... }
class VisaoPessoa extends Visao { function exibir(Pessoa $pessoa) { // Objeto de transferência em JSON para injetar no código Javascript. $tojs = json_encode($pessoa->exportarTO());
Pergunta
Ensjo (Emerson Costa)
Salve a todos.
Pela primeira vez desenvolvi um sistema usando o padrão Modelo-Visão-Controlador. O modelo é aplicado em dois níveis. No nível da aplicação, a visão é o browser, e o controlador e o modelo rodam no servidor. Mas também uso o MVC no nível do browser, onde o modelo é um objeto contendo os dados sendo operados, a visão é o formulário em que os dados do modelo são exibidos e editados, e o controlador trata os eventos de interface (perda de foco, cliques, etc.)
Também usei o padrão Objeto de Transferência de Dados (Data Transfer Object) para passar as informações de uma camada à outra, e o padrão Objeto de Acesso a Dados (Data Access Object) para isolar o objeto da aplicação do banco de dados.
Com isso meu sistema ficou cheio de transformações de dados, e me pergunto se alguém teria uma sugestão para simplificar as coisas.
Vou tentar descrever abaixo as camadas e o fluxo de dados do sistema.
1. PHP (HTTP)
Preenche o ARRAY $_REQUEST com os dados vindos do navegador (campos de formulário, informações da querystring): informações de controle (qual controlador instanciar, qual método chamar) e dados a serem gravados em objeto(s) no banco de dados.
2. CONTROLADOR DO SERVIDOR
Instancia um OBJETO DE TRANSFERÊNCIA, preenchendo-o com os dados de objeto contidos no ARRAY $_REQUEST.
3. MODELO DO SERVIDOR
Instancia um OBJETO DA APLICAÇÃO, aciona seus métodos e/ou preenche suas propriedades com os valores do OBJETO DE TRANSFERÊNCIA vindo do controlador.
4. OBJETO DA APLICAÇÃO
Instancia um OBJETO DE TRANSFERÊNCIA e preenche-o com seus dados.
5. OBJETO DE ACESSO A DADOS (DAO)
Prepara um COMANDO SQL com os dados do OBJETO DE TRANSFERÊNCIA.
6. PHP (MYSQL)
Retorna um ARRAY $row como resultado da execução do COMANDO SQL.
7. OBJETO DE ACESSO A DADOS (DAO) (2)
Instancia um OBJETO DE TRANSFERÊNCIA e preenche-o com os dados do ARRAY $row.
8. OBJETO DA APLICAÇÃO (2)
Preenche suas propriedades com os dados do OBJETO DE TRANSFERÊNCIA vindos do DAO.
9. MODELO DO SERVIDOR (2)
Entrega o OBJETO DA APLICAÇÃO atualizado para o controlador.
10. CONTROLADOR DO SERVIDOR (2)
Entrega o OBJETO DA APLICAÇÃO para a visão.
11. OBJETO DA APLICAÇÃO (3)
Por solicitação da visão, instancia um OBJETO DE TRANSFERÊNCIA e o converte para string JSON (Javascript Object Notation). (OBJETO DE TRANSFERÊNCIA EM JAVASCRIPT).
12. VISÃO DO SERVIDOR (2)
Injeta o OBJETO DE TRANSFERÊNCIA EM JAVASCRIPT no código do modelo do browser.
var objeto = new Objeto(<?php echo $json ?>);
13. MODELO DO BROWSER
Instancia o OBJETO DA APLICAÇÃO EM JAVASCRIPT com os dados do OBJETO DE TRANSFERÊNCIA EM JAVASCRIPT.
13. VISÃO DO BROWSER
Preenche CAMPOS DE FORMULÁRIO com os dados do OBJETO DA APLICAÇÃO EM JAVASCRIPT.
14. CONTROLADOR DO BROWSER
Controla a interface da aplicação, atualizando os CAMPOS DE FORMULÁRIO (visão) e o OBJETO DA APLICAÇÃO EM JAVASCRIPT (modelo) de acordo com a digitação e outras ações do usuário. Até que o usuário clica em um botão para salvar as alterações.
15. OBJETO DA APLICAÇÃO EM JAVASCRIPT
Por solicitação do controlador do browser, instancia um OBJETO DE TRANSFERÊNCIA EM JAVASCRIPT.
16. CONTROLADOR DO BROWSER (2)
Preenche um segundo formulário invisível (CAMPOS DE FORMULÁRIO INVISÍVEL) com os dados do OBJETO DE TRANSFERÊNCIA EM JAVASCRIPT a serem transmitidos para o servidor, e outras informações. E submete o formulário.
E voltamos ao início do ciclo.
Não está "burocrático" demais? É isso mesmo? Alguma ideia?
(EDIÇÃO EM 15/06/2011):
Para dar uma ideia melhor, eis aqui um esquema reduzido do funcionamento da minha implementação MVC. Os comentários com reticências (// ...) indicam lugares onde poderia/deveria haver mais códigos (outros métodos, por exemplo), mas não são necessários para esta explicação.
index.php
Supondo que $modulo = 'Pessoa' e $operacao = 'atualizar', os dois comandos acima equivaleriam a:
$controlador = new ControladorPessoa();
$controlador->atualizar();
Controlador.php + ControladorPessoa.php
Modelo.php + ModeloPessoa.php
// ...
}
class ModeloPessoa extends Modelo {
// ...
function atualizar(TransferObject $to) {
$pessoa = new Pessoa();
$pessoa->abrir($to->getCampo('cpf'));
$pessoa->setNome($to->getNome());
$pessoa->atualizar();
return $pessoa;
}
}
ObjetoDaAplicacao.php + Pessoa.php
DAO.php + DAOPessoa.php
// ...
function executarSQL($sql) {
// ... (Conectar, executar comando SQL, desconectar.)
return $row;
}
}
class DAOPessoa extends DAO {
// ...
function abrir($cpf) {
$sql = <<<SQL
SELECT *
FROM PESSOA
WHERE CPF='{$cpf}';
SQL;
$row = $this->executarSQL($sql);
$to = new TransferObject();
$to->setCampo('cpf', $row['CPF']);
$to->setCampo('nome', $row['NOME']);
return $to;
}
function atualizar(TransferObject $to) {
$sql = <<<SQL
UPDATE PESSOA
SET NOME='{$to->getCampo('nome')}'
WHERE CPF='{$to->getCampo('cpf')}';
SQL;
$this->executarSQL($sql);
}
}
Visao.php + VisaoPessoa.php
TransferObject.php
var $dados = array();
function setCampo($nome, $valor) {
$dados[$nome] = $valor;
}
function getCampo($nome) {
return $dados[$nome];
}
}
Depois disso, eis os arquivos em Javascript citados no Visao.php:
ObjetoDaAplicacao.js + Pessoa.js
Modelo.js + ModeloPessoa.js
// ...
ModeloPessoa = function(to) {
this.pessoa = new Pessoa(to);
};
ModeloPessoa.prototype = new Modelo(); // Herança.
// ...
Visao.js + VisaoPessoa.js
Controlador.js + ControladorPessoa.js
// ...
Controlador.prototype.submeter = function(valores) {
var emissor = document.getElementById("emissor"); // Formulário emissor.
// Insere valores a enviar como elementos TEXTAREA no formulário.
for (var nomeCampo in valores) {
if (valores[nomeCampo] !== null) {
var textArea = document.createElement("textarea");
textArea.setAttribute("name", nomeCampo);
var texto = document.createTextNode(valores[nomeCampo]);
textArea.appendChild(texto);
emissor.appendChild(textArea);
}
}
emissor.submit();
};
ControladorPessoa = function() {};
ControladorPessoa.prototype = new Controlador(); // Herança.
// ...
ControladorPessoa.prototype.iniciar = function() {
visao.exibirCpf();
visao.exibirNome();
document.getElementById("cpf").focus();
};
ControladorPessoa.prototype.atualizarCpf = function() {
modelo.pessoa.setCpf(document.getElementById("cpf").value);
};
ControladorPessoa.prototype.atualizarNome = function() {
modelo.pessoa.setNome(document.getElementById("nome").value);
};
ControladorPessoa.prototype.botaoSalvar = function() {
var to = modelo.pessoa.exportarTO();
valores = {
"modulo": "Pessoa",
"operacao": "atualizar",
"cpf": to["cpf"],
"nome": to["nome"]
};
this.submeter(valores);
};
Link para o comentário
Compartilhar em outros sites
1 resposta a esta questão
Posts Recomendados
Participe da discussão
Você pode postar agora e se registrar depois. Se você já tem uma conta, acesse agora para postar com sua conta.