O MVC (Model, View, Controller) é uma arquitetura que separa as responsabilidades em diferentes camadas, com o objetivo de organizar melhor o código e oferecer uma solução estruturada. Quando bem aplicado, esse padrão se torna escalável e reutilizável. Especificamente, as regras de negócio ficam encapsuladas na camada Modelo (Model). Por outro lado, o Controller direciona o fluxo dos dados, delegando a responsabilidade de execução para quem realmente sabe como fazê-lo. O Controller não deve tomar decisões complexas, embora possa ser responsável por algumas lógicas menores. Pense nele como “aquele que sabe quem deve executar, mas não como fazê-lo”.
A camada Model é responsável por lidar com os dados, incluindo tanto seu armazenamento quanto a lógica associada. Enquanto isso, a View exibe esses dados ao usuário através de relatórios, formulários, listas, e outros formatos de apresentação.
De acordo com a Wikipédia, a interação entre os componentes é a seguinte:
- O Controller envia comandos ao Model para alterar seu estado e também pode alterar a forma como a View exibe os dados.
- O Model armazena dados e notifica o Controller e a View quando há mudanças, permitindo que a View se atualize automaticamente.
- A View gera uma representação visual dos dados armazenados no Model.
(https://pt.wikipedia.org/wiki/MVC – Acesso em 27/06/2018)
Objetivo do Artigo
Neste artigo, vamos criar um pequeno projeto ilustrando como o padrão MVC separa responsabilidades. O foco será um CRUD (Create, Read, Update, Delete) simples. Para a camada Model, utilizaremos apenas uma classe, o que simplifica o projeto, mas na prática há várias classes envolvidas, como as que gerenciam a comunicação com o banco de dados. Este exemplo não incluirá regras de negócios, por isso não adicionaremos uma classe separada para o Model.
Se você nunca utilizou um framework MVC ou não sabe por onde começar, este artigo vai fornecer uma visão clara e objetiva. Além disso, este artigo foi escrito originalmente para PHP 7.1, mas acabou sendo atualizado para ser utilizado com PHP 8.x. Portanto, você encontrar algumas características aplicadas diretamente nessa versão.
O Projeto
Este projeto é uma atualização da agenda de contatos mencionada em um artigo anterior sobre CRUD com PDO, mas desta vez estamos aplicando conceitos de orientação a objetos e MVC. Embora o projeto seja um CRUD, ele incorpora uma arquitetura moderna e organizada.
Requisitos
Para seguir este tutorial, você precisa de um servidor PHP e um banco de dados MySQL. Não abordarei o processo de instalação desses serviços aqui.
Estrutura do Projeto
Comporemos nosso projeto com:
- 4 Classes:
Conexao.php
(Gerenciamento da conexão com o banco de dados)Request.php
(Gerenciamento de requisições)Contato.php
(Model, ou seja, a classe que gerencia os dados)ContatosController.php
(Controller)
- 2 Arquivos de View:
form.php
grade.php
- 1 Arquivo para o Front Controller:
index.php
Etapa 1: Criação do Banco de Dados

Primeiramente, vamos iniciar criando o banco de dados. Então, para isso, inicie o MySQL e siga as instruções:

- Crie o banco de dados:sqlCopiar código
CREATE DATABASE projeto_mvc;
- Selecione o banco de dados:sqlCopiar código
USE projeto_mvc;
- Crie a tabela contatos:sqlCopiar código
CREATE TABLE contatos ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, nome VARCHAR(80) NOT NULL, telefone VARCHAR(20) DEFAULT NULL, email VARCHAR(80) DEFAULT NULL );
Se tudo estiver correto, você verá mensagens como “Query OK” confirmando a execução dos comandos.

Etapa 2: Criação da Classe de Conexão
Agora, vamos criar a classe Conexao, responsável por gerenciar a conexão com o banco de dados, utilizando o padrão Singleton. Dessa maneira, isso garante que a aplicação crie apenas uma instância de conexão durante toda a sua execução.
<?php
class Conexao
{
private static $conexao;
private function __construct() {}
public static function getInstance(): PDO
{
if (is_null(self::$conexao)) {
self::$conexao = new \PDO('mysql:host=localhost;dbname=projeto_mvc', 'root', 'senha');
self::$conexao->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
self::$conexao->exec('SET NAMES utf8mb4');
}
return self::$conexao;
}
}
Etapa 3: Criação da Classe Modelo
A seguir, criamos a classe Contato, que implementa o padrão Active Record simplificado, com métodos para realizar operações CRUD.
Os atributos da classe são dinâmicos e não são declarados explicitamente no Model. Por isso, você não verá um atributo como “nome”, uma vez que, o sistema gera os atributos dinamicamente em um array chamado ‘atributos’. Portanto, para implementar essa funcionalidade, usamos os métodos mágicos _set(), _get() e _isset().
O seguinte código da classe Contato segue a seguir:
<?php
declare(strict_types=1);
/**
* Classe Contato - baseado no modelo Active Record (Simplificado)
*/
class Contato
{
private array $atributos = []; // Armazena os atributos do contato em um array associativo
// Construtor com propriedade promovida no PHP 8.3, aceita um ID opcional
public function __construct(private ?int $id = null) {}
// Define dinamicamente o valor de um atributo
public function __set(string $atributo, mixed $valor): self
{
$this->atributos[$atributo] = $valor;
return $this;
}
// Retorna o valor de um atributo, ou null se não estiver definido
public function __get(string $atributo): mixed
{
return $this->atributos[$atributo] ?? null;
}
// Verifica se um atributo está setado
public function __isset(string $atributo): bool
{
return isset($this->atributos[$atributo]);
}
// Insere ou atualiza o contato no banco de dados
public function save(): int|false
{
$colunas = $this->preparar($this->atributos);
// Insere novo contato ou atualiza o existente
$query = !isset($this->id)
? sprintf('INSERT INTO contatos (%s) VALUES (%s);',
implode(', ', array_keys($colunas)),
implode(', ', array_values($colunas))
)
: sprintf('UPDATE contatos SET %s WHERE id=%d;',
implode(', ', $this->prepareUpdate($colunas)),
$this->id
);
$conexao = Conexao::getInstance();
if ($conexao === null) {
return false;
}
$stmt = $conexao->prepare($query);
$stmt->execute();
return $stmt->rowCount();
}
// Prepara colunas para atualização no formato "coluna=valor"
private function prepareUpdate(array $colunas): array
{
$definir = [];
foreach ($colunas as $key => $value) {
if ($key !== 'id') {
$definir[] = sprintf('%s=%s', $key, $value);
}
}
return $definir;
}
// Escapa e formata os dados para SQL
private function escapar(mixed $dados): string
{
return match (true) {
is_string($dados) && !empty($dados) => "'" . addslashes($dados) . "'",
is_bool($dados) => $dados ? 'TRUE' : 'FALSE',
$dados === '' => 'NULL',
default => (string)$dados
};
}
// Prepara os dados para a consulta SQL
private function preparar(array $dados): array
{
$resultado = [];
foreach ($dados as $k => $v) {
if (is_scalar($v)) {
$resultado[$k] = $this->escapar($v);
}
}
return $resultado;
}
// Retorna todos os contatos do banco de dados ou false se nenhum for encontrado
public static function all(): array|false
{
$conexao = Conexao::getInstance();
if ($conexao === null) {
return false;
}
$stmt = $conexao->prepare('SELECT * FROM contatos;');
$stmt->execute();
$result = [];
while ($rs = $stmt->fetchObject(Contato::class)) {
$result[] = $rs;
}
return count($result) > 0 ? $result : false;
}
// Retorna a contagem total de registros na tabela de contatos
public static function count(): int|false
{
$conexao = Conexao::getInstance();
if ($conexao === null) {
return false;
}
return (int) $conexao->exec('SELECT count(*) FROM contatos;');
}
// Busca um contato pelo seu ID
public static function find(int $id): Contato|false
{
$conexao = Conexao::getInstance();
if ($conexao === null) {
return false;
}
$stmt = $conexao->prepare(sprintf('SELECT * FROM contatos WHERE id=%d;', $id));
$stmt->execute();
return $stmt->rowCount() > 0 ? $stmt->fetchObject(Contato::class) : false;
}
// Exclui um contato pelo seu ID
public static function destroy(int $id): bool
{
$conexao = Conexao::getInstance();
if ($conexao === null) {
return false;
}
return (bool) $conexao->exec(sprintf('DELETE FROM contatos WHERE id=%d;', $id));
}
}
Finalmente, temos a classe de Conexão e a classe Modelo do nosso projeto.
Etapa 4: Criação das Classes Controller e Request
ContatosController.php:
<?php
declare(strict_types=1);
class ContatosController extends Controller
{
// Lista todos os contatos e renderiza a visualização 'grade'
public function listar(): string
{
$contatos = Contato::all();
return $this->view('grade', ['contatos' => $contatos]);
}
// Mostra o formulário para criação de um novo contato
public function criar(): string
{
return $this->view('form');
}
// Mostra o formulário para edição de um contato
public function editar(array $dados): string
{
$id = (int) $dados['id']; // Converte o ID recebido em inteiro
$contato = Contato::find($id); // Busca o contato no banco de dados
return $this->view('form', ['contato' => $contato]);
}
// Salva um novo contato enviado via formulário
public function salvar(): string
{
$contato = new Contato();
$contato->nome = $this->request->nome;
$contato->telefone = $this->request->telefone;
$contato->email = $this->request->email;
// Salva o contato e, se bem-sucedido, retorna à lista de contatos
if ($contato->save()) {
return $this->listar();
}
// Em caso de erro, poderia ser implementada uma mensagem ou redirecionamento
return $this->view('form', ['erro' => 'Erro ao salvar o contato.']);
}
// Atualiza um contato existente com os dados submetidos
public function atualizar(array $dados): string
{
$id = (int) $dados['id'];
$contato = Contato::find($id);
$contato->nome = $this->request->nome;
$contato->telefone = $this->request->telefone;
$contato->email = $this->request->email;
$contato->save();
return $this->listar();
}
// Exclui um contato com base no ID fornecido
public function excluir(array $dados): string
{
$id = (int) $dados['id']; // Converte o ID para inteiro
Contato::destroy($id); // Exclui o contato do banco de dados
return $this->listar();
}
}
Observe como a View interage diretamente com o Model. Além disso, a classe ContatosController estende a classe Controller, o que facilita essa comunicação. Mas, antes de implementarmos a Controller, é necessário criar uma classe simples que gerencie as requisições POST e ofereça suporte ao Controller. Então, crie um arquivo chamado Request.php e adicione o seguinte código:
<?php
declare(strict_types=1);
class Request
{
protected array $request;
// Inicializa a classe armazenando o conteúdo de $_REQUEST
public function __construct()
{
$this->request = $_REQUEST;
}
// Retorna o valor de um parâmetro de $_REQUEST ou false se não existir
public function __get(string $nome): mixed
{
return $this->request[$nome] ?? false;
}
}
Veja como essa pequena classe melhora significativamente a legibilidade do código. Então, mais uma vez, crie um arquivo chamado Controller.php e adicione o seguinte código:
<?php
declare(strict_types=1);
class Controller
{
public Request $request;
// Inicializa o controlador com uma instância da classe Request
public function __construct()
{
$this->request = new Request();
}
// Renderiza uma view e passa as variáveis definidas no array, se fornecido
public function view(string $arquivo, ?array $array = null): void
{
// Se o array de variáveis for passado, cria variáveis dinâmicas
if (!is_null($array)) {
foreach ($array as $var => $value) {
${$var} = $value; // Cria variáveis dinamicamente
}
}
ob_start(); // Inicia o buffer de saída
include "{$arquivo}.php"; // Inclui o arquivo de view
ob_flush(); // Envia o buffer de saída ao navegador
}
}
A classe Controller usa um método simples para se comunicar com a View e já instancia um objeto da classe Request em sua construção. Isso permite que os métodos do Controller acessem facilmente os dados enviados pela requisição. É por isso que os métodos salvar e atualizar funcionam de maneira tão fluida.
Até agora, já temos a Model, o Controller e a classe de conexão prontos. Ainda faltam dois elementos essenciais para que tudo funcione: a View e uma espécie de Dispatcher ou Front Controller, que dará vida ao Controller. Em frameworks modernos, utiliza-se um sistema de rotas baseado na URL. Ao configurar uma rota, você mapeia uma URL para um método específico de um Controller, permitindo passar parâmetros conforme necessário. O roteamento é um tema complexo, por isso não abordaremos neste artigo. Por isso, ele exige um artigo à parte para explorar todos os detalhes.
Criação de Views e Implementação de um Front Controller
A partir de agora, vamos criar as Views e implementar um roteamento básico usando o padrão Front Controller. A principal ideia é ter um único ponto de entrada, o arquivo index.php, que gerencia todas as requisições e delega o controle para os controladores e métodos corretos. Esse padrão facilita a manutenção, melhora a escalabilidade e mantém a aplicação bem organizada.
Explicação do Front Controller
No código a seguir, temos o Front Controller, que age como o ponto único de entrada da aplicação. Ele utiliza o PHP nativo para carregar dinamicamente as classes através do autoloader e um roteador personalizado que lida com as requisições. A principal vantagem dessa abordagem é que toda a lógica de roteamento e controle de fluxo da aplicação passa por esse único arquivo.
<?php
declare(strict_types=1);
error_reporting(E_ALL);
ini_set('display_errors', '1');
// Registra o autoloader para carregar as classes automaticamente
spl_autoload_register(function (string $class): void {
$file = "$class.php";
if (file_exists($file)) {
require_once $file;
}
});
// Inicia a aplicação pelo Front Controller
$router = new Router();
$router->dispatch($_GET);
?>
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="utf-8">
<title>Agenda de Contatos</title>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet">
<!-- Outros links e scripts aqui -->
</head>
<body>
</body>
</html>
Detalhamento da Estrutura do Roteamento
Agora, vamos explorar como o roteamento funciona. A classe Router
que criamos lida com a requisição, verificando se o controlador e método passados na URL são válidos, e chamando-os com os parâmetros fornecidos. Essa abordagem garante que, independentemente de qual página seja acessada, o index.php
será o responsável por encaminhar a requisição corretamente.
<?php
class Router
{
public function dispatch(array $request): void
{
try {
// Se a requisição GET estiver vazia, exibe a página inicial
if (empty($request)) {
$this->renderWelcome();
return;
}
// Verifica se o controlador foi informado e se a classe existe
if (!isset($request['controller']) || !class_exists($request['controller'])) {
throw new Exception('Controller não encontrado!');
}
// Instancia o controlador
$controller = new $request['controller']();
// Verifica se o método foi informado e se existe no controlador
$method = $request['method'] ?? null;
if (!$method || !method_exists($controller, $method)) {
throw new Exception('Método não encontrado!');
}
// Prepara os parâmetros, removendo 'controller' e 'method'
$parameters = $request;
unset($parameters['controller'], $parameters['method']);
// Chama o método do controlador com os parâmetros
call_user_func([$controller, $method], $parameters);
} catch (Exception $e) {
// Exibe a mensagem de erro
$this->renderError($e->getMessage());
}
}
// Exibe a página inicial
private function renderWelcome(): void
{
echo '<h1>Contatos</h1><hr><div class="container">';
echo 'Bem-vindo ao aplicativo MVC Contatos!<br><br>';
echo '<a href="?controller=ContatosController&method=listar" class="btn btn-success">Vamos Começar!</a></div>';
}
// Exibe uma página de erro
private function renderError(string $message): void
{
echo '<div class="alert alert-danger">' . $message . '</div>';
}
}
Funcionamento do Router
- Autoloading de classes: O
spl_autoload_register
é utilizado para carregar dinamicamente as classes necessárias. Isso significa que você pode criar novos controladores sem precisar incluir manualmente os arquivos. - Roteamento: O
Router
verifica se os parâmetroscontroller
emethod
foram passados viaGET
, garantindo que o controlador e o método existam. Caso contrário, o sistema lança uma exceção e exibe uma mensagem de erro. - Renderização de Views: A classe
Router
também cuida de exibir a página de boas-vindas ou mensagens de erro, dependendo do fluxo. Dessa forma, toda a lógica de apresentação e controle está centralizada no Front Controller.
Com essa estrutura, você cria uma aplicação mais escalável e organizada. O Front Controller gerencia todas as requisições e, através do Router, delega o controle aos controladores específicos, chamando o método adequado com base na URL. Esse é o ponto de partida para expandir sua aplicação, adicionando mais controladores, métodos e funcionalidades, conforme necessário.
Arquivos da View
form.php:
<div class="container">
<form action="?controller=ContatosController&<?php echo isset($contato->id) ? "method=atualizar&id={$contato->id}" : "method=salvar"; ?>" method="post" >
<div class="card" style="top:40px">
<div class="card-header">
<span class="card-title">Contatos</span>
</div>
<div class="card-body">
</div>
<div class="form-group form-row">
<label class="col-sm-2 col-form-label text-right">Nome:</label>
<input type="text" class="form-control col-sm-8" name="nome" id="nome" value="<?php
echo isset($contato->nome) ? $contato->nome : null;
?>" />
</div>
<div class="form-group form-row">
<label class="col-sm-2 col-form-label text-right">Telefone:</label>
<input type="text" class="form-control col-sm-8" name="telefone" id="telefone" value="<?php
echo isset($contato->telefone) ? $contato->telefone : null;
?>" />
</div>
<div class="form-group form-row">
<label class="col-sm-2 col-form-label text-right">Email:</label>
<input type="text" class="form-control col-sm-8" name="email" id="email" value="<?php
echo isset($contato->email) ? $contato->email : null;
?>" />
</div>
<div class="card-footer">
<input type="hidden" name="id" id="id" value="<?php echo isset($contato->id) ? $contato->id : null; ?>" />
<button class="btn btn-success" type="submit">Salvar</button>
<button class="btn btn-secondary">Limpar</button>
<a class="btn btn-danger" href="?controller=ContatosController&method=listar">Cancelar</a>
</div>
</div>
</form>
</div>
grade.php:
<h1>Contatos</h1>
<hr>
<div class="container">
<table class="table table-bordered table-striped" style="top:40px;">
<thead>
<tr>
<th>Nome</th>
<th>Telefone</th>
<th>Email</th>
<th><a href="?controller=ContatosController&method=criar" class="btn btn-success btn-sm">Novo</a></th>
</tr>
</thead>
<tbody>
<?php
if ($contatos) {
foreach ($contatos as $contato) {
?>
<tr>
<td><?php echo $contato->nome; ?></td>
<td><?php echo $contato->telefone; ?></td>
<td><?php echo $contato->email; ?></td>
<td>
<a href="?controller=ContatosController&method=editar&id=<?php echo $contato->id; ?>" class="btn btn-primary btn-sm">Editar</a>
<a href="?controller=ContatosController&method=excluir&id=<?php echo $contato->id; ?>" class="btn btn-danger btn-sm">Excluir</a>
</td>
</tr>
<?php
}
} else {
?>
<tr>
<td colspan="5">Nenhum registro encontrado</td>
</tr>
<?php
}
?>
</tbody>
</table>
</div>
Conclusão
Espero que você tenha gostado do artigo e aproveitado para seu aprendizado. Acredito que este material oferece uma base sólida para entender os conceitos fundamentais do MVC. Ao pesquisar sobre esse padrão na internet, notei que muitos artigos detalham demais para iniciantes ou dividem o tema em várias partes. Nos meus artigos, busco abordar um tema do início ao fim, mesmo que isso leve a textos mais longos.
Sua opinião é muito importante para mim, especialmente porque estou planejando cursos mais avançados de PHP no futuro. Portanto, sinta-se à vontade para compartilhar seu feedback.
Este projeto demonstrou de forma simples a interação entre a Model, os Controllers e as respostas enviadas à View. Ele também destacou como o usuário faz solicitações na View, e o Controller as recebe e gerencia as ações de maneira eficiente.Optamos por não abordar o sistema de roteamento para manter o foco, mas se você entendeu o funcionamento deste pequeno aplicativo, estará preparado para desenvolver exercícios práticos e até explorar frameworks mais robustos, como o Laravel.
Embora este artigo não tenha como objetivo ensinar Laravel, ao testar o framework, você perceberá que os conceitos de MVC discutidos aqui são muito familiares. No entanto, vale mencionar que é possível utilizar o Laravel para construir aplicações sem necessariamente seguir o padrão MVC à risca.
Se você estiver primeiro lendo o artigo para entender o projeto e chegou até aqui, aproveite para ver algumas capturas de telas do projeto:




[]’s
Pingback: PHP:: PDO – CRUD COMPLETO | Alexandre Bezerra Barbosa
Excelente sua explicação. Simplesmente fantástico. Será que você poderia criar artigo sobre sistema de rotas para esse crud?
Boa ideia Fábio! Eu tenho alguns artigos prontos mas estou tentando driblar umas limitações horríveis do WordPress para publicar. Espero em breve pública-los. Mas sugestão anotada!
Postei uma série de artigos sobre rotas Fábio!
Estou com um pequeno problema, estou utilizando seu tutorial porém eu organizei nas respectivas pastas que geralmente encontramos no mvc, como Models, Controller e Views.
Apos fazer isso coloquei os arquivos Controller e ContatoController na mesma pasta tudo certinho.
Toda vez que rodo meu projeto agora ele retorna mensagem de que o Controller não pode ser encontrado.
Não estou conseguindo visualizar o problema .
OLá Camilo! Você começou já criando em pastas separadas ou seguiu o artigo e obteve êxito antes, primeiro? O motivo da pergunta é para primeiro termos a certeza de que as classes estão todas ok. Se sim, então o problema vai estar no na função: spl_autoload_register(). Acontece que no artigo, a função não foi implementada da forma para varrer subpastas ou pastas diferentes. Sendo assim, precisamos modificá-la. Mas, embora este artigo ainda esteja utilizando esta função, não recomendo continuar usando-a. O esforço poderá ser grande para manter o código funcional. Então, temos o composer sendo um amigão nessa hora! ele substitui com confiança esse trabalho! É bem provável que em breve eu esteja fazendo uma atualização para mudar isso no artigo. Se você já sabe como fazer, manda bala e comenta aí o resultado. Mas se não, pode me enviar um e-mail que eu te respondo o mais rápido possível! Já tenho “alguns artigos” para colocar no blog, mas uma falha nele está impedindo e então ainda estou trabalhando nisso! Obrigado por acompanhar!
Para concluir, talvez um brinquedo mais evoluído que virá para o blog alguma hora, é este: https://github.com/alxbbarbosa/aplicacao_mvc
Dê uma olhada no código e veja o que você acha. Este é um mini-framework bem didático. Este ainda não estava usando composer, mas tem uma classe para carregar as classes em pastas diferentes.
Abraço!
Boa noite Alexandre,
O caso é o seguinte, respondendo sua pergunta, seguindo este tutorial consegui sim fazer com que tudo funcionasse direitinho, apenas alguns errinhos bobos nada muito grave.
Mas como a intenção é montar uma explicação um pouco mais trabalhada do MVC, de todos os tutoriais que peguei na internet considerei o seu mais prático e mais facil para iniciar um projeto mvc do 0, podendo cada um criar o seu projeto conhecendo-o como um todo.
Problema da maior parte dos projetos encontrados é a complicação e algumas particularidades que a maioria coloca e nao explicam, impossibilitando que as pessoas que seguem o modelo possam entender tudo.
Bom enfim, gostaria se possível, ajudasse a resolver esse pequeno probleminha. Em resumo segui este tuto e fiz tudo rodar na raiz mesmo, depois que analisei o codigo e vi que daria pra iniciar um projeto bacana dividi tudo em suas respectivas pastas de acordo com o que sabemos de mvc, mas ai deu aquele problema que citei e voce especificou, se puder me ajudar agradeço e aguardo.
Mais do que isso Camilo, fique atento porque estou lançando um novo artigo atualizado com roteamento, composer, e muito mais!
modifiquei o spl_autoload_register() para incluir as pastas, mudou um pouco o erro, lhe enviei um email mas nao me respondeu será que pode auxiliar no novo erro ?
Camilo, não recebi o seu e-mail.
Pingback: PHP::Construir um sistema de Rotas para MVC – Terceira parte | Alexandre Bezerra Barbosa
Parabens Alexandre muito bom!!!
Só uma dúvida que me deparei diante desse padrão. Se quisesse por exemplo na saída de um campo qualquer executar uma função no controller para que este requisitasse do model para buscar alguns campos de uma tabela (exemplo tela de vendas buscar dados do cliente digitando seu codigo) como faria seguindo seu padrão MVC. Tô quebrando a cabeça. Se puder ajudar agradeceria. Ou quem puder ajudar!!!!
Olá Fábio! Obrigado por prestigiar o material, dê uma olhada também em como criar o sistema de roteamento, em uma série de artigos aqui, dessa forma será mais fácil tratar o fluxo de dados. Sobre a sua necessidade, se entendi bem, você precisa criar um método no controller para tratar essa ação. Porém a classe modelo desse artigo é bem simples (para não tornar o entendimento completo), então nela você não tem nenhum tipo de filtro para devolver registros com base em critérios. A sugestão, se você espera implementar nesse modelo, é adicionar um filtro opcional como argumento no método all do Modelo. A assinatura do método ficaria assim: public all(array $criteria = [])
Daí, você poderia modificar para receber parâmetros de filtragem assim (por exemplo) : [‘nome’, ‘=’, ‘João’]
E então modificar o método para aceitar (exemplo):
if(count($criteria) > 0) {
$stmt = $conexao->prepare(“SELECT * FROM contatos where ” . implode(‘ ‘, $criteria) . ‘;’);
} else {
$stmt = $conexao->prepare(“SELECT * FROM contatos;”);
}
Esse aí é um caminho! Mas é claro que precisa ser melhor trabalhado, talvez as linhas acima não sejam suficientes. Na view, talvez de grade, você então criaria um form, com input para receber a palavra chave. Daí no controller no método que você adicionasse, poderia chamar algo como: $contatos = Contato::all([‘nome’, ‘like’, $request->search]);
Tente fazer! Se der certo comente aí!
Se você não conseguir me envie um e-mail que eu te mando um exemplo.
Qual seu email?
alxbbarbosa@yahoo.com.br
Uma beleza. Fiz aqui e funcionou redondinho.
Agora vou tentar criar subpastas para os arquivos: Model, Controller e View.
Muito obrigado Alexandre.
Me parece que para este exemplo não precisamos dos includes para jquery e bootstrap.min.js.
Gostei da ideia de colocar três botões nos forms: Salvar, Limpar e Cancelar.
No novo registro é legal, mas no editar o Limpar não funciona.
Mudei esta linha do form.php:
Limpar
Adicionei o type=”reset”, que no Novo registro é bem legal, pois limpa o form.
Ótimo, vou dar uma atenção! Obrigado
Sim, tem razão sobre o arquivo js. Deixei por mera questão de documentação e conveniência. Mas a sua observação é muito válida. Obrigado!
Olá, estou recebendo esse erro,
Warning: call_user_func() expects parameter 1 to be a valid callback, cannot access private method ContatosController::listar() in C:\Dev\Projeto_MVC\index.php on line 34
Alguem pode me ajudar ?
Obg.
Olá Edio, como você definiu a visibilidade na assinatura do método listar em ContatosController? Se estiver private mude para public pois ele está reclamando a falta de acesso! Se não poste o trecho do código que você criou para analisarmos.
abraço
Opa, era isso mesmo.
Agora vou alterar o form conforme o Ribamar fez, o meu também está com problema.
Muito obrigado.
Cara pela primeira vez consegui acompanha e fazer. Em outros tutorial eu sempre me enrolava hora na conexão com banco, hora na lógica. Parabéns, muito bem explicado.
Olá, parabéns pelo post.
Uma dúvida o que é essa sintaxe ${$var}?
Olá Alexandre, obrigado por prestigiar o material. Essa sintaxe se refere a criação de variável dinâmica. Por exemplo, o nome da nova variável será conforme obtido de $var. As chaves determinam um placeholder, só para deixar mais organizado, mas poderia ser assim também: $$var. Eu não gosto de usar desta última maneira apresentada porque se parece a um erro de digitação. Para mim desta forma ${$var} é “concisa”. Abraço!
Valeu pela resposta rápida xará, vivendo e aprendendo hehe.
Valeu pela resposta rápida xará, vivendo e aprendendo hehe
Alexandre, parabéns! Extremamente didático. Como alguns disseram, a distribuição do MVC em pastas seria ideal, mas para o seu propósito, foi muito bom.
Uma dúvida: se imaginarmos mais entidades na base, as funções “escapar” e “preparar” poderiam ser públicas em uma outra classe?
Mais uma vez, parabéns pelo artigo.
Olá Pedro Castro, muito obrigado por prestigiar o material também. Referente a sua dúvida, imagino que neste caso seria melhor tratar em uma abstração separada e herdar. Eu tenho um artigo sobre active record. Ele já está precisando de uma atualização, mas vai responder a sua pergunta com uma base maior. Abraço!
Entendi. Mais uma dúvida: fiz alguns testes e consegui colocar um parâmetro string na função all ( function all(string $criteria=””). E na chamada do all direto está funcionando ok. Como faria para passar esta string pela função listar? Se coloco listar(string $criteria=””), na chamada do index.php apresenta a mensagem de erro “Módulo não encontrado”. Por exemplo, numa base de estados e cidades, ao clicar em um estado na lista de estados, apresentaria a lista de todas as cidades daquele estado.
Desde já, obrigado por sua paciência.
Sou iniciante e gerei o código e me aparece esse erro, não estou a conseguir solucionar, por favor alguém pode me ajudar??
Warning: include({$arquivo}.php): Failed to open stream: No such file or directory in C:\xampp\htdocs\PWeb\Controller.php on line 21
Warning: include(): Failed opening ‘{$arquivo}.php’ for inclusion (include_path=’C:\xampp\php\PEAR’) in C:\xampp\htdocs\PWeb\Controller.php on line 21
Olá André, aquele include está encapsulado entre aspas duplas? Se não estiver, tenta assim por favor: include(“{$arquivo}.php”).
[]’s
Obrigada Alexandre.
O primeiro erro foi superado agora está aparecer esse erro de sintaxe
Parse error: syntax error, unexpected identifier “ob_flush” in C:\xampp\htdocs\PWeb\Controller.php on line 21
Oi, Alexandre!
Se eu tivesse outro controller, por exemplo, FuncionariosController.
E eu quisesse pegar todas as pessoas que tivessem o email *@empresa.com.br
Eu criaria um método getFuncionarios dentro desse controller (FuncionariosController) , um método parecido no ContatosController e criaria um __getFuncionarios dentro do model Contatos? Ou “apenas”
criaria um método getFuncionarios dentro desse controller (FuncionariosController) e criar um __getFuncionarios dentro do model Contatos?
Seria mais ou menos isso:
1) FuncionariosController->getFuncionarios()->ContatosController->getFuncionarios()->Contato->__getFuncionarios()
ou
2) FuncionariosController->getFuncionarios()->Contato->__getFuncionarios()
Obrigado!
Olá Rodrigo! tudo bem?
Você precisa ver o controller como “aquele cara” que não sabe necessáriamente fazer as coisas mas sabe para quem pedir ou perguntar. Antes de dizer onde quero chegar, uma diga é: quando desenvolver projetos pessoais, crie os métodos em português mesmo, com bons nomes. Por exemplo: obterTodos(), obterPorId(int $id), obterPorCriterios(array $critérios). Isso vai te ajudar muito a pensar.
Voltando na ideia inicial, sobre o cara que sabe onde buscar o que o usuário quer. Então, você não pode dar o poder ao Controller de ele mesmo ir até o banco de dados, mas ele sabe que um Model ou um “Serviço” sabe de onde obter os dados. No seu caso, seria interessante criar um serviço para tratar o que vêm do Funcionário, tipo um FuncionarioService. Daí talvez nessa classe você poderia fazer a mesclagens entre os dados. Por exemplo, de uma maneira bem simples vou ilustrar a ideia a seguir:
Supondo que você tenha um model Funcionario que tenha um atributo onde você armazena os Ids de contatos:
classe de serviço FuncionarioService com um método obterTodos:
Essa é uma maneira, mas poderá desenvolver dentro do Model mesmo. O ideal é sempre trabalhar com serviços. Incluisive um padrão que alguns constuma criar é uma classe de Repositório para lidar com as coleções de dados. Funciona semelhante a essa idéia acima.
Espero que aí lhe dê um uma boa visão para seguir.
[]’s
No meu caso eu não tenho um FuncionarioModel eu “só” tenho o Model Contatos (como no seu post). E o FuncionariosController teria que pegar as infos do Contatos. Gostei mesmo da ideia do FuncionarioService. Neste caso, como o FuncionarioServece pegaria as informações do Contatos (Modelo)?
Desde já agradeço pelo post e excelente explicação!
Olá , eu estou a tentar fazer esse CRUD mas já tenho todo o sistema de MVC em Codeigniter feito aqui na empresa bem como o banco de dados, o index e o template de html. Como poderia adequar este seu exemplo a este sistema já feito? Desculpe a pergunta mas sou muito iniciante em PHP.
Desde já obrigado pelo seu trabalho, está muito bom.
Cumprimentos,
Filipe
Pingback: CRUD básico em PHPoo - Alcione Ferreira