MVC na prática – entenda de uma vez por todas como isso funciona

UPDATE: Tem vídeo lá no final da página. Clique aqui para ir pra lá.

Olá.

O post de hoje é uma sugestão do nosso leitor Tiago Cardoso.

Vamos aprender de uma vez por todas como funciona o MVC na prática, e ver como isso pode facilitar bastante a manutenção de sites/sistemas e também aumentar a produtividade no desenvolvimento de novas aplicações.

Antes, vamos dar apenas uma relembrada no que é MVC.

M – MODEL – É a camada que vai interagir com seu banco de dados. Aqui você vai fazer as requisições e inserções em suas tabelas. Também é o local onde você irá fazer a lógica de negócios funcionar, exemplo: verificar o usuário/senha em um banco de dados e entregar a resposta pronta ao controller.

V – VIEW – É a camada visual, ou seja, é o que o seu usuário vai ver. Tem bastante HTML e pouco PHP.

C – CONTROLLER – Responsável pelas requisições do site. É como se fosse um intermediário entre o Model e a View. Tecnicamente você até pode fazer consultas ao banco de dados daqui, mas se você quiser seguir o padrão MVC, aconselho não fazer isto, e deixar a parte de banco de dados lá para o Model.

O ideal é sempre deixar os CONTROLLER o mais simples possível, sem dar-lhes muita responsabilidade. Lembre-se de não fazer um controller com um monte de métodos, pois assim ele ficará gigante e difícil de entender.

O ideal é você separar tudo em vários outros controllers com seus métodos. Ao separar sua aplicação, a manutenção futura ficará muito mais fácil de prestar.

A proposta do post de hoje é desenvolvermos uma aplicação bem simples, porém, que faça com que as 3 camadas, MVC se interajam.

Para isto, vamos criar um CRUD básico. CRUD é basicamente o que todo relacionamento com um banco de dados deve fazer, significa: CREATE, READ, UPDATE e DELETE.

Para não ficar tão abstrato, vamos criar uma aplicação que tem uma utilidade nas nossas vidas. Vamos fazer uma pequena agenda, onde basicamente o usuário vai inserir a descrição do compromisso e a data do evento. Bem simples.

Criando nossa Agenda

O primeiro passo é criarmos nosso banco de dados e a tabela. Crie um banco de dados qualquer e depois crie uma tabela. Se quiser, copie o código abaixo que cria nossa tabela:

 

Em seguida, configure o CodeIgniter para acessar seu bancos de dados. Se você não lembra ou não sabe como fazer isto, veja este post.

Depois, vamos configurar o CodeIgniter para trazer algumas bibliotecas e helpers que vamos utilizar durante o projeto. Precisamos carregar a biblioteca database e o helper url.

Para isto, acesse o arquivo: application/config/autoload.php e configure como segue abaixo:

Linha 55 deixe assim:

Linha 67

Para ver se tudo está funcionando, recarregue seu CodeIgniter no navegador e veja se não surge nenhum erro.

Vamos criar agora uma página inicial que terá os links de navegação da nossa agenda. Serão basicamente 3 links:

Home – Leva até a página incial.

Novo Compromisso – Traz uma página com um formulário para inserir os dados na agenda

Listar Compromissos – Traz uma página que irá listar todos os compromissos cadastrados. Nesta tela também deverá haver em cada registro 2 links. Um para Editar e outro para Excluir

Ao clicar em Editar, uma nova tela surgirá com um formulário preenchido com os dados daquele registro, e no final um botão Salvar.

Aqui eu vou utilizar a própria estrutura de páginas e views do CodeIgniter, para evitar de ficar criando muita coisa. Então, na view welcome_message.php substitua o bloco de código como segue abaixo:

 

Repare que eu utilizei a função anchor() do CodeIgniter para criar meus links. Esta é uma função bem legal, pois ela cria os links internos já com o endereço base do site.

Após colocar código acima e recarregar sua página no navegador, você deverá ver algo parecido com isto:

Print da página inicial da agenda

Repare que estamos direcionando os links para Novo Compromisso e Listar Compromissos para um único controller, o agenda, onde vamos centralizar todas as funções que tem relação com a agenda. E dentro deste controller nós criaremos as funções respectivas.

Vamos agora criar o controller agenda que irá chamar uma view onde existe um formulário de inserção de dados. Repare que eu não vou chamar esta função de novo_compromisso e sim de formulario pois a intenção aqui não é ter um formulário para inserir um compromisso e outro para editar. O que vamos fazer é sempre chamar este mesmo formulário tanto para novos registros quanto para edições. Veremos isto mais para frente.

Crie um arquivo chamado agenda.php e salve dentro da pasta: application/controllers e coloque dentro dele o seguinte conteúdo:

 

Repare que aqui vamos usar mais um helper do CodeIgniter. Será o helper form que nos ajuda a criar formulários. Este helper você pode carregá-lo tanto aqui, antes de chamar a view, quanto no autoload.php, lá dentro da pasta application/config. Porém, eu achei mais conveniente chamarmos aqui, pois não vamos utilizar este helper a todo momento, mas somente quando formos inserir ou editar um registro. Na listagem de compromissos, por exemplo, não precisaremos do helper form, pois é somente uma tabela. Então, acho inútil deixar o helper carregado na memória ocupando recursos do servidor à toa.

Agora vamos criar a view que a função formulario() está chamando.

Para isto, crie um arquivo chamado formulario.php dentro da pasta: application/views e coloque o seguinte conteúdo:

 

Este código ficou gigante porque eu copiei todo o conteúdo do welcome_message.php e alterei somente o que eu precisava. O certo seria eu criar um arquivo de estilos e importar, mas não é o foco aqui do nosso post, por isso, ficou assim mesmo.

Veja que para a criação do nosso formulário, estamos usando as funções do helper form . A vantagem é que, pelo menos no caso do form_open ele já cria para gente a tag de abertura do form já com tudo preenchido. Com relação aos INPUTS, fica a seu critério utilizar o helper ou não. Mas para fins didáticos, estou utilizando aqui.

Se tudo deu certo, a página deverá ficar com esta cara:

Print da tela de novo compromisso

Repare no action do formulário que o usuário será direcionado para a função salvar que está dentro do controller agenda. É neste função que vamos criar os códigos para carregarmos nosso model e inserir os dados recebidos.

Mas antes de criarmos nossa função salvar(), vamos criar finalmente nosso MODEL, que será responsável por conversar com nosso banco de dados.

Crie o arquivo model_agenda.php dentro da pasta application/models e coloque o seguinte conteúdo:

 

O que o model vai fazer é receber tudo o que foi enviado via POST e inserir direto na tabela. Como os nomes dos campos no formulário são exatamente os mesmos da tabela, então basta inserirmos diretos os valores.

Agora, vamos criar o controller salvar() que irá receber a requisição e irá se comunicar com o model.

Abra o controller agenda.php e crie nova função. Veja o código abaixo:

 

O que acontece aqui: Repare que para utilizar um model, você precisa carregá-lo antes. Assim como as libraries e helpers, você pode pedir para o CodeIgniter carregar automaticamente seu model caso você vá utilizar a todo momento. Para isto, basta informar no nome do seu model no arquivo autoload.php. A parte de models fica no final do arquivo.

Uma vez carregado o model, para utilizarmos as funções dentro dele, basta utilizarmos a seguinte sintaxe:

$this->model_agenda->salvar_dados();

Neste caso estamos utilizando a função salvar_dados() que está dentro do model. Se fosse outra função, como veremos mais adiante, basta mudar o nome.

Veja que lá no arquivo do model_agenda, ele retorna true ou false dependendo do que ocorrer, então eu verifico e chamo uma view de sucesso ou de erro dependendo do retorno. Esta parte eu vou deixar para você criar. Mas crie as views, senão vai dar erro. Ou então só mude o load da view para um echo.

Certo, a parte de inserção de dados já está OK. O legal de usar models, é que este model_agenda.php que criamos, poderia ser utilizado por qualquer controller ou função que você criasse, reaproveitando o código várias vezes.

O próximo passo agora é criarmos as telas de apresentação dos compromissos agendados. Então, dentro do nosso controller agenda vamos criar uma nova função que irá chamar a view que irá listar o que temos cadastrado no banco de dados.

Copie o código abaixo e cole dentro do seu controller agenda.php

 

A lógica aqui é mesma da inserção. Basicamente criaremos uma nova função dentro do nosso model model_agenda que irá trazer todos os registros do banco de dados. E chamamos esta função aqui e atribuímos seu retorno à uma variável, que será passada para a view e para montarmos nosso loop que irá mostrar os dados ao usuário.

Dentro do model_agenda.php, crie um nova função chamada retorna_todos_registros() e coloque o seguinte código:

 

É uma consulta bem simples. O que eu faço é simplesmente dar um order by na tabela antes do get e em seguida, atribuo o resultado da consulta a  uma variável $consulta, e depois saio da função retornando o conteúdo de $consulta.

Novamente, esta função dentro deste model, pode ser utilizada várias vezes e em vários lugares dentro do CodeIgniter, sem precisar ficar recriando códigos a torto e a direta.

Vamos criar agora a view listar_compromissos.php que será responsável por mostrar os dados ao usuário.

Crie o arquivo listar_compromissos.php e salve dentro da pasta application/views

Dentro do arquivo, cole o seguinte código. Aqui estou colando só a parte que interessa. A parte de CSS você pode colocar depois, senão, fica muito grande o código.

 

O que eu fiz aqui foi simplesmente dar um loop pelo foreach na variável $consulta, que foi passada via parâmetro lá no controller. E montei uma tabelinha simples para mostrar os dados ao usuário.

Outra coisa que fiz também foi criar a coluna Ação, onde tem os links Editar e Excluir. Repare que utilizei o helper de url anchor para criar os links e dê uma atenção especial ao link Excluir.

Coloquei dentro dele  um parâmetro para chamar uma função javascript no evento onclick. Esta função simplesmente manda uma mensagem ao usuário perguntando se ele realmente quer excluir tal registro. Acho isto importante para links ou botões de exclusão.

Para que esta função funcione, dentro do onclick deve existir um return antes de chamar a função. Assim:

Sem isto, não funciona e ele exclui direto. Se o usuário clicar em Cancelar, a página não é redirecionada, porém, caso confirme, então eu deixo o redirecionamento continuar.

É importante notar também que nos links Editar e Excluir eu chamo as funções dentro do controller agenda que ainda vamos criar daqui a pouco, mas note que é preciso passar o ID do registro em questão, para que possamos buscá-lo ou excluí-lo do banco de dados. Veja no código acima como é feito isto no CodeIgniter.

Se tudo deu certo, sua tela deve ficar parecida com isto:

Print da tela de Compromissos Cadastrados

O próximo passo agora é criamos a parte de Edição dos compromissos. Então, vamos criar uma função dentro do controller agenda que irá fazer isto.

Abra o controller agenda.php e coloque a função abaixo:

Veja que o parâmetro ID pode ser recuperado ao colocarmos a variável $id dentro dos parênteses da função. Isto já é suficiente para recebermos seu valor.

Em seguida, carregamos novamente o helper form, pois ele será utilizado para montar o formulário.

Agora temos  um pequeno problema. Precisamos recuperar somente um registro do banco de dados, e nosso model_agenda.php quando solicitado traz todos os registros. Então aqui ha duas soluções. Você poderia criar uma nova função dentro do model chamada por exemplo: retorna_registro_by_id(), onde você deverá passar o ID do registro antes de continuar, ou então, fazer uma pequena mudança no model_agenda.php para que ele permita trabalhar das duas maneiras, trazendo um registro ou todos.

Para isto, vamos modificar nosso model para que ele faça a seguinte verificação: se ao chamarmos a função retorna_todos_registros() passarmos um ID, então ele acrescenta na consulta SQL uma cláusula WHERE para restringir a pesquisa, caso contrário, traz todos os registros. Veja abaixo como ficará a nova função dentro do model:

Repare que eu coloquei um parêmtro $id que é iniciado no valor zero. Então, antes de fazer a consulta, eu verifico se este valor está igual a zero. Caso esteja, continuo na consulta. Caso não, então eu pego este valor e passo como parâmetro no WHERE da consulta.

Com isto, nós temos uma função que tem duas utilidades. Traz todos os registros se não for passado um ID ou então, retorna somente um registro, caso o ID seja informado.

Voltando a função editar() dentro do nosso controller, os dados retornados pela consulta ao model são armazenados na variável $consulta, e utilizando esta sintaxe:

eu consigo recuperar os campos de somente um registro, sem precisar usar um foreach, que não faz sentido, pois temos somente uma linha sendo retornada aqui.

Fazendo isto para os dois campos, eu atribuo seus valores à duas variáveis que serão repassadas à view formulario, que é a mesma que criamos no início do post.

Mas aqui temos que fazer uma pequena mudança na view formulário.php. Temos que acrescentar os códigos que irão mostrar estes dados ao usuário. Então, dentro dos campos veja as mudanças que fiz:

Coloquei aqui somente os códigos dos campos para facilitar.

Ali eu uso o operador ternário do PHP que simplesmente faz a verificação: se a variável $descricao existir, então mostro seu conteúdo, caso contrário, mostro vazio.

Se não souber como funciona o operador ternário do PHP, clique aqui.

Isso server para que não seja gerado um erro de variável inexistente na página, pois lembre-se que estes campos só existirão quando for clicado em Editar. Como é exatamente a mesma página que é chamada ao inserir um novo compromisso, lá não são passadas variáveis, por isso daria erro.

O próximo passo agora é modificarmos a função salvar_dados() dentro do model_agenda.php para que ele também salve dados editados, e não somente os novos. Ao fazer isto, precisaremos apenar acrescentar um novo campo na view formulário. Este campo será um campo do tipo hidden que irá receber o ID daquele registro. Então, ao postarmos para a nossa função salvar, basta fazermos a seguinte verificação: se o campo $id for vazio, então dê um insert, se não, dê um update.

Abra sua view formulario.php e entre após o botão submit mas antes da tag de fechamento do formulário, acrescente o seguinte campo:

O código $this->uri->segment(3,0) recupera o que existe no 3º segmento na URL. Neste caso ele conta a partir do controller, depois o método e depois o parâmetro.

O zero indica que se ele não encontrar nada, então retorna zero.

Agora na função salvar_dados() dentro do model_agenda.php nós saberemos que se o campo $id vir com um valor igual a zero, indica que é uma inserção de um novo registro, porém, se for diferente de zero, indica uma edição, então devemos fazer um update.

Abra o model_agenda.php e modifique a função salvar_dados() pela que segue abaixo:

Além da mudança do ID tive que fazer mais uma mudança. Como no código original eu estava inserindo na tabela todos os campos que eram postados, tudo dava certo, pois somente dois campos eram postados, descrição e data, e há dois campos no banco de dados.

Neste caso, como acrescentamos um capo hidden no formulário, 3 campos serão postados. E ao dar um insert, será gerado um erro, pois o CodeIgniter não vai achar o campo novo no banco de dados.

Por isso, eu criei a array dados e ali eu tratei as informações que estão vindo via post. E o mais interessante é que esta variável dados serve tanto para o UPDATE quanto para o INSERT, bastando apenas informar o ID na cláusula UPDATE antes de chamá-la.

O último passo agora no nosso projeto é fazer a parte de exclusão.

Vamos então criar uma função excluir() dentro do controller agenda, que irá chamar uma função dentro do model_agenda.php que irá excluir o registro.

Abra o model_agenda.php e acrescente a seguinte função:

Agora, temos que criar também a função excluir dentro do nosso controller agenda. Veja abaixo:

Aqui eu aproveitei aquelas view de sucesso e erro na operação. O ideal é você criar mensagens personalizadas, mas isso eu acho que você já sabe fazer certo?

—-

Bom, este é o final do post de hoje. Ele ficou bem extenso mas acredito que agora você consegue saber o que é MVC e como aplicá-lo.

Abaixo eu deixo o link para que você baixe nosso projeto e teste no seu servidor.

Baixar o Projeto Agenda

Veja abaixo o vídeo onde eu faço o projeto acima:

 

P.S. Eu quero saber quais suas dúvidas sobre o mundo CodeIgniter. Poste nos comentários abaixo dúvidas e sugestões. Quem sabe sua dúvida pode se tornar um próximo post.

Abraços

Fabio

Fábio S. Reszko

Sou Programador PHP desde 2006 e eu acredito sinceramente que programar usando um Framework PHP é a solução para os problemas de códigos desorganizados, difíceis de entender e de dar manutenção no futuro. Se você também acredita nisto, então fique à vontade em explorar meu blog.

  • Diego

    Baixei a ultima versão do CI eo help descrito se chama helpers.

    Apenas uma dica pra quem for realizar o exemplo 😀

  • Pingback: Mini-cadastro de clientes com Modal do BootStrap, JQuery, JQuery Forms, JSon e CodeIgniter()

  • Fabio

    Muito bom o tuto!!! Seria mais legal ainda se colocasse a validação do form nesse exemplo! Abs

  • Olá Fabio, obrigado.

    Em breve vou fazer um post explicando a validação que vem integrada ao CodeIgniter.

    Abraços.

  • Fabio

    Show!!! Tentando add mas não roda…

  • Fabio, não entendi. 😉

  • Fabio

    Xará, já coloquei a validação no form com esse seu crud. O problema é que no editar quando da o erro os parâmetros se perdem… e aí quando informo tudo no form ele insere um registro novo ao invés de atualizar…

    Tem alguma dica pra dar ou tem algo on line pra dar uma olhada?

    No inserir está validando legal…

  • Olá Fabio,

    Bom, existe somente um único parâmetro que informa ao CodeIgniter se ele deve inserir ou atualizar um registro, é o id do registro. Se você fizer um post passando junto o id do registro, então o CodeIgniter vai dar um update. Se você passar um id vazio, então o registro vai ser inserido.

    Quando você recarrega o form após a validação, provavelmente o campo do tipo hidden que guarda o id do registro está vindo vazio. Faça um teste: Abra seu formulário para a edição, e antes de dar submit, aperte CTRL+U para ver o código fonte e procure pelo campo do tipo hidden que fica antes da tag . Repare que ele vai ter um valor. Agora, dê submit e quando seu formulário retornar com os campos preenchidos, aperte novamente CTRL+U pra ver o código e procure de novo pelo campo do tipo hidden. Provavelmente o value dele estará vazio.

    Se for isto mesmo, basta você passar também este valor junto com os valores de validação quando o formulário for recarregado.

    Espero ter ajudado.

    Fábio

  • Fabio

    Vlw pelas dicas! Obg por responder…

    O que acontece é:

    if ($this->form_validation->run() == FALSE) {
    redirect(‘categorias/editar/’ . $this->input->post(id_categoria));
    //$this->load->view(‘categorias_form’, $this->input->post());

    Mas quando agente seta o id pelo post ele nao valida depois q dá o erro sacou?

    Esse é o problema…

    No load aí acima ele chama a validacao mas perde o id e insere o novo registro

    Com o redirec ele fica com o id mas nao chama a validacao.

  • Fabio, o correto não seria você dar um redirect caso a validação falhe, mas sim, chamar novamente o formulário através do comando $this->load->view().
    Dentro de cada campo no formulário, você deve configurar o value com a função set_value() do CodeIgniter.

    Acredito que você deva apenas colocar a função set_value() dentro do campo hidden que armazena o id do registro.

    Dê uma olhada na ajuda do CI: https://ellislab.com/codeigniter/user-guide/libraries/form_validation.html#repopulatingform

    Caso ainda não funcione, poste o HTML do seu form para eu ver, ou se for muito grande, apenas uma parte dele para eu entender.

    Fabio

  • Edson

    Bom dia Fabio.
    Gostaria de lhe pedir uma ajuda por onde começar a estudar esse framework, o CodeIgniter, estudo php já faz algum tempo e sinto falta de ter algum aprendizado em framework, me indicaram o CodeIgniter.
    Tenho algum dificuldade ainda em OO do Php, por isso peço ajuda, com algum link, sugestão de livros, posts, etc.
    Obrigado pela atenção e é muito bom seu material e site.
    Atenciosamente
    Edson Marcos Ferrari

  • Olá Edson.

    Veja este meu conteúdo antes: http://www.phpexpert.com.br e me diga o que acha. Qualquer dúvida basta postar lá de dentro mesmo.

    Abraços

  • Fernando

    Parabéns pelo tutorial, vc explica de uma maneira simples e objetiva, não vi ainda um tutorial na net tão completo quanto o seu ! Obrigado

  • Valeu Fernando.

    Abraços

  • Hiago Borges Pereira Suave

    Bom dia Fabio,

    O tutorial está muito bem explicado e deve estar ajudando muitas pessoas.
    Eu tenho uma dúvida que poderia se tornar um post:

    Queria saber depois de ter sua agenda pronta, mandar um email avisando que o prazo está chegando do compromisso, voce poderia me ajudar?

  • Olá Hiago.
    A ideia para fazer isso pode ser feita assim: você vai criar um arquivo que lê a data do prazo final, e pode estipular notificar o usuário um dia antes por exemplo. Então você faz uma query que traz todos os registros que irão vencer um dia antes da data final do evento. Tendo isto, basta pegar estes registros e enviar por email. Aqui no blog tem até um post onde ensino a enviar uma mensagem por email usando o CI. Pra automatizar isto, você deveria programar um Cron Job no servidor onde está hospedado o seu site para que o cron chame todo dia automaticamente o arquivo que notifica o usuário. Não vou entrar em detalhes pois é muita coisa. Se interessar, tenho um curso de CodeIgniter onde eu ensino a fazer um cadastro de clientes onde há uma agenda que tem a notificação que você mencionou, tudo automático. Se quiser dar uma olhada, acesse aqui: http://www.dicascodeigniter.com.br/apresentacao-phpexpert. Abraços

  • douglas88

    Primeiramente muito obrigado Fábio por seu conteúdo.

    Gostaria de tirar uma dúvida, na hora de carregarmos o Model, o CodeIgniter carrega pelo nome do arquivo , ou pelo Nome da Classe. E seja qual for, ele diferencia maiúsculas de Minusculas ?

  • A partir da versão 3.0 do CI, você deve escrever o nome do arquivo da classe com a primeira letra em maiúscula, assim como também o nome da classe dentro do arquivo. De qualquer modo, o padrão que o CI irá seguir dependerá de como você carregou a classe. Se for assim: $this->load->model(“Clientes_model”); então, você deverá usar assim: $this->Clientes_model->method(), caso carregue assim: $this->load->model(“clientes_model”); deverá usar assim: $this->clientes_model->method(); Eu uso a última opção.
    Abraços

  • douglas88

    Muito obrigado Fábio.

  • douglas88

    Após assistir a seu vídeo, eu reescrevi meu Controller e o meu Modelo com base no que eu entendi, o controle ficou muito mais organizado.