Neste post, vamos abordar a implementação da arquitetura MVC, com um exemplo prático, em PHP do clássico programa Hello World, para iniciantes.
Em artigo anterior, expliquei os conceitos básicos da arquitetura de projetos de software MVC (MODEL — VIEW — CONTROLLER). Agora, o objetivo é mesclar a teoria com a prática.
O que é a arquitetura MVC?
Embora possamos traduzir “model, view, controller” para “modelo, visão, controlador”, vou optar, neste post por mantê-los na forma original, para enriquecer um pouco o vocabulário do artigo.
A implementação original do MVC, na linguagem Smalltalk-80, com algumas variações, contém conceitos que se descrevem assim:
MODEL
Na sua forma mais simples, o MODEL armazena dados que serão acessados pelo VIEW e escritos pelo CONTROLLER.
É a parte mais complexa do sistema e contém toda a lógica específica da aplicação e é onde as entidades de domínio (domain entities), relativas aos conceitos do mundo real são armazenadas — tais como “um usuário” ou “uma ordem”).
É a parte da aplicação que recebe dados e os processa.
Além disto, lida com todos os acessos e armazenamento de dados — e não tem conhecimento dos CONTROLLERS ou VIEWS que fazem uso dele (o MODEL).
MODELS são aqueles componentes do sistema que realmente fazem o trabalho.
Por exemplo, no PHP, o MODEL pode representar um “usuário”, no sistema.
Ele pode tomar conta de todas as operações relacionadas aos usuários — gravando registros, recuperando-os, validando-os etc.
O que o MODEL NÃO É:
- um simples ponto de acesso a dados;
- uma classe chamada “model” que representa uma tabela dentro do banco de dados.
O VIEW
O view contém toda a lógica do display.
No PHP, esta é a parte da aplicação que gera o HTML.
Tem acesso direto ao MODEL e pode inquiri-lo para obter seus dados.
O VIEW pode criar callbacks para seu CONTROLLER — como um botão que, ao ser clicado, inicia uma ação).
No MVC, o VIEW interpela o MODEL para obter dados, diretamente.
Para evitar erros de interpretação, o VIEW NÃO É:
- ausente de lógica;
- receptor de dados do CONTROLLER.
O QUE É CALLBACK
Literalmente, callback quer dizer “chame de volta”.
Em computação, é uma porção de código executável, passado como parâmetro a outra porção de código.
Quando apropriado, a callback pode ser invocada e executada.
O CONTROLLER
O CONTROLLER recebe as entradas do usuário e atualiza o MODEL onde requerido.
Quando não houver interação humana direta, não há necessidade do CONTROLLER.
Em função disto, é importante que se diga, que não se trata de um mediador ou passagem entre qualquer uma das duas outras entidades.
O CONTROLLER acessa o MODEL, mas não contém qualquer lógica de display — tudo o que ele faz é responder às entradas do usuário.
CONTROLLERS são usados para enviar mensagens ao MODEL e prover uma interface entre este e os VIEWS associados a ele (p. ex., teclado, mouse etc.)
Cada VIEW deve ser pensado como sendo associado a um CONTROLLER cada qual com seu próprio MODEL. Mas este último, podendo ter muitos pares de VIEW/CONTROLLER.
Cada CONTROLLER está ligado a uma única instância de um VIEW e a uma única instância de um MODEL.
Coisas que o CONTROLLER NÃO É:
- encarregado de instanciar o MODEL ou o VIEW — ele os enxerga, mas a flexibilidade é reduzida nas implementações que o forçam a selecionar qual VIEW ou MODEL está sendo usado;
- uma passagem ou mediador entre o MODEL e o VIEW;
- local onde os VIEWS são inicializados com base no estado de um MODEL. O CONTROLLER está ligado a uma única classe VIEW (embora possa ser atribuído a múltiplas instâncias) e responde a ações relacionadas.
Uma lista de produtos constituiria uma única VIEW.
O fluxo do programa
O fluxo típico de um programa sob os padrões MVC, segue estes passos:
- Inicialização do MODEL, do VIEW e do CONTROLLER.
- O VIEW obtém dados do MODEL e é exibido ao usuário.
- O usuário interage com o VIEW (clicando em algo, por exemplo), o que dispara uma ação do CONTROLLER.
- O CONTROLLER atualiza o MODEL, de alguma forma.
- O VIEW é renovado para exibir os dados atualizados do MODEL.
Hello World!
Já vimos um bom tanto de teoria.
Faz sentido ver como tudo isto se aplica à “vida real”, em uma pequena aplicação PHP.
Me acompanhe!
class Model { public $text; public function __construct() { $this->text = 'Hello world!'; } } class View private $model; private $controller; public function __construct(Controller $controller, Model $model) { $this->controller = $controller; $this->model = $model; } public function output() { return '<h1>' . $this->model->text .'</h1>'; } } class Controller { private $model; public function __construct(Model $model) { $this->model = $model; } } // aqui inicia a triade $model = new Model(); // eh importante que o CONTROLLER e o VIEW compartilhem o MODEL $controller = new Controller($model); $view = new View($controller, $model); echo $view->output();
Os aplicativos “hello world!” não costumam ter interação com o usuário — pelo menos, este aqui, não tem.
Portanto, como ele só exibe dados, o CONTROLLER não faz nada aqui.
Interação do usuário
Se você ficou frustrado pelo fato de o CONTROLLER não ter sido relevante no exemplo anterior, vamos usar outra abordagem que preveja este tipo de interação.
Interação com o usuário é o primeiro problema da arquitetura MVC, na web — não há como criar uma callback pro CONTROLLER diretamente.
Além disto, toda a página tem que ser recarregada — o que ainda não é um grande problema, mas precisamos adicionar código que direcione a ação de volta ao CONTROLLER certo.
No nosso próximo exemplo, vamos adicionar ao código anterior algumas linhas que fazem com que a string “Hello world” seja seja substituída por “Texto Atualizado”, quando clicada.
Primeiro adicione um link pro VIEW. Você pode fazer isto adicionando uma callback ao CONTROLLER a partir do VIEW.
Em aplicações GUI, o CONTROLLER poderia ser apenas outro objeto na memória e a callback poderia ser uma simples chamada de função.
Na web, isto não é uma opção — uma requisição HTTP é a única maneira de acessar o CONTROLLER.
class View { private $model; private $controller; public function __construct(Controller $controller, Model $model) { $this->controller = $controller; $this->model = $model; } public function output() { return '<a href="mvc.php?action=textclicked">' . $this->model->text . '</a>'; } }
Na segunda requisição (callback), todos os componentes precisam ser reinicializados. Algum código precisa ser adicionado para direcionar a ação de volta ao CONTROLLER. Veja como:
$model = new Model(); //Eh importante que o CONTROLLER e o VIEW compartilhem o MODEL $controller = new Controller($model); $view = new View($controller, $model); if (isset($_GET['action'])) $controller->{$_GET['action']}(); echo $view->output();
Tudo o que este código faz é chamar a ação do CONTROLLER — especificada por $_GET['action']
, baseado na interação do usuário.
Enfim, uma ação do CONTROLLER, que lide com o evento, precisa ser adicionada ao código:
class Controller { private $model; public function __construct(Model $model) { $this->model = $model; } public function textClicked() { $this->model->text = 'Texto Atualizado'; } }
Agora, quando a página for visitada, ela vai dizer “Hello World” e, quando o link for clicado, o texto muda para “Texto Atualizado”.
Pegue o código completo abaixo:
<?php class Model { public $text; public function __construct() { $this->text = 'Hello world!'; } } class View { private $model; private $controller; public function __construct(Controller $controller, Model $model) { $this->controller = $controller; $this->model = $model; } public function output() { return '<a href="mvc.php?action=textclicked">' . $this->model->text . '</a>'; } } class Controller { private $model; public function __construct(Model $model) { $this->model = $model; } public function textClicked() { $this->model->text = 'Texto Atualizado'; } } $model = new Model(); //It is important that the controller and the view share the model $controller = new Controller($model); $view = new View($controller, $model); if (isset($_GET['action'])) $controller->{$_GET['action']}(); echo $view->output(); ?>
Leia mais sobre o assunto
Outros textos sobre a arquitetura MVC, neste site.
Outros textos sobre programação PHP, neste site.
http://www.siliconinfo.com/open-source-web-application/mvc-development.html
https://coderwall.com/p/l-a79g
https://r.je/mvc-in-php.html
Wikipedia
Leia mais sobre as definições usadas neste texto:
http://pt.wikipedia.org/wiki/Callback
5 replies on “PHP, MVC e hello world!”
Sou iniciante. Queria saber por que os parâmetros do construtor tem essa semântica:
Controller $controller
Pesquisei na internet mas não achei nenhuma explicação.
Ali ele esta restringido o parâmetro recebido somente para a classe especificada, isto é, obrigatoriamente esta forçando que o parâmetro recebido deva ser um objeto oriundo da classe especificada.
Elias achei um ótimo artigo, mas se o seu ponto de vista estiver correto, me parece que quase todos MVCs PHP estão trabalhando na contra-mão. Estou realmente confuso quanto a isto. Então me vem a duvida, como isto funcionaria em um sistema de rotas? Eu teria que criar uma quarta “entidade” além do mvc só para as rotas? Pois ao meu ver pelo que entendi no laravel (Route::resource(”, ‘DemoController’);) e no cakephp (Router::connect (‘/’, array(‘controller’=>’categories’, ‘action’=>’index’));) as rotas sempre acessam controllers, o que tecnicamente sempre obrigaria o controller a “chamar” os models e views (mesmo que não diretamente). Se puder me tirar esta duvida. Grato
Este artigo não é (de forma alguma) definitivo. Ainda há muito o que acrescentar.
Sobre routing, especificamente, há muito mais a ser escrito, com certeza.
Obrigado pela resposta tão rápida Elias.