Ir para conteúdo
Fórum Script Brasil
  • 0

MVC com transformações demais


Ensjo (Emerson Costa)

Pergunta

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

$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());

echo <<<HTML
<html>
<head>
<script type="text/javascript" src="ObjetoDaAplicacao.js"></script>
<script type="text/javascript" src="Pessoa.js"></script>
<script type="text/javascript" src="Modelo.js"></script>
<script type="text/javascript" src="ModeloPessoa.js"></script>
<script type="text/javascript" src="Visao.js"></script>
<script type="text/javascript" src="VisaoPessoa.js"></script>
<script type="text/javascript" src="Controlador.js"></script>
<script type="text/javascript" src="ControladorPessoa.js"></script>
<script type="text/javascript">
controlador = new ControladorPessoa();
modelo = new ModeloPessoa({$tojs});
visao = new VisaoPessoa();
</script>
</head>
<body onload="controlador.iniciar()">
<form id="visualizador">
<input type="text" id="cpf" onchange="controlador.atualizarCpf()" />
<input type="text" id="nome" onchange="controlador.atualizarNome()" />
<button onclick="controlador.botaoSalvar()">Salvar</button>
</form>
<!-- Formulário invisível para envio de dados. -->
<form id="emissor" action="{$_SERVER['SCRIPT_NAME']}" method="POST"
style="display: none;">
</form>
</body>
</html>
HTML;
}
}[/codebox]

TransferObject.php

[codebox]class TransferObject() {
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

ObjetoDaAplicacao = function() {};
// ...

Pessoa = function(to) {
this.cpf = null;
this.nome = null;
if (to) this.importarTO(to);
};
Pessoa.prototype = new ObjetoDaAplicacao(); // Herança.
// ...
Pessoa.prototype.importarTO = function(to) {
this.setCpf(to.cpf);
this.setNome(to.nome);
};
Pessoa.prototype.exportarTO = function() {
return {
"cpf": this.getCpf(),
"nome": this.getNome()
};
};[/codebox]

Modelo.js + ModeloPessoa.js

[codebox]Modelo = function() {};
// ...

ModeloPessoa = function(to) {
this.pessoa = new Pessoa(to);
};
ModeloPessoa.prototype = new Modelo(); // Herança.
// ...

Visao.js + VisaoPessoa.js

Visao = function() {};
// ...

VisaoPessoa = function() {};
VisaoPessoa.prototype = new Visao(); // Herança.
// ...
VisaoPessoa.prototype.exibirCpf = function() {
document.getElementById("cpf").value = modelo.pessoa.getCpf();
};
VisaoPessoa.prototype.exibirNome = function() {
document.getElementById("nome").value = modelo.pessoa.getNome();
};[/codebox]

Controlador.js + ControladorPessoa.js

[codebox]Controlador = function() {};
// ...
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);
};

Editado por Ensjo (Emerson Costa)
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.

Visitante
Responder esta pergunta...

×   Você colou conteúdo com formatação.   Remover formatação

  Apenas 75 emoticons são permitidos.

×   Seu link foi incorporado automaticamente.   Exibir como um link em vez disso

×   Seu conteúdo anterior foi restaurado.   Limpar Editor

×   Você não pode colar imagens diretamente. Carregar ou inserir imagens do URL.



  • Estatísticas dos Fóruns

    • Tópicos
      152,3k
    • Posts
      652,5k
×
×
  • Criar Novo...