ULTIMATE PHP Blog

Conheça 15 Ferramentas Essenciais Para PHP
15 Ferramentas Essenciais Para PHP

Coloque seu e-mail abaixo e baixe agora um PDF 100% gratuito mostrando 15 ferramentas indispensáveis para PHP

Fique tranquilo. Odeio spam tanto quanto você :)

MVC: Uma Estrutura Básica Com PHP Orientado a Objetos

MVC: Uma Estrutura Básica Com PHP Orientado a Objetos

O Padrão MVC (Model View Controller) é um dos mais utilizados atualmente e é requisito praticamente essencial para qualquer programador, independente da plataforma que utiliza.

A ideia central desse padrão é criar uma separação clara entre modelo de dados (a letra M, que corresponde a Model) e a parte visual da aplicação (a letra V, de View).

Quem faz a ligação entre essas duas camadas é o controlador, ou Controller, a letra C do MVC.

Neste artigo vou explicar o que é cada uma dessas 3 camadas e também irei apresentar uma aplicação usando essa arquitetura.

NOTA: Este artigo é um excerto do Curso ULTIMATE PHP 2.0. Para conhecer todos os detalhes do curso, clique aqui.

Model: o M do MVC

O Modelo, ou Model, em inglês, é a camada que representa a informação no banco de dados.

Geralmente criamos uma classe que repre Este artigo é um senta uma tabela do banco de dados, onde os campos da tabela são atributos (propriedades) da classe.

Qualquer interação com o banco de dados deve ser feita pelo Modelo. Geralmente é o Controlador que solicita essas informações.

View: o V do MVC

Essa é a camada de exibição, que formata os dados na tela, para o usuário final.

É, basicamente, um arquivo de template, com a estrutura HTML junto com alguns comandos PHP, para exibir as informações do modelo.

Controller: o C do MVC

O Controlador é quem faz a ligação entre a Model e a View.

Essa camada verifica a URL, identificando qual foi o recuso solicitado. A partir daí, busca os dados no modelo, processa-os, se necessário, e os envia para a View.

MVC Na Prática

Não adianta eu falar, falar e falar e esperar que você entenda 100%.

A melhor forma de entender é fazendo!

Então vamos colocar a mão na massa e montar uma pequena aplicação em uma estrutura MVC básica.

Eu digo “básica”, porque vamos usar apenas a ideia central. Dá pra melhorar, acrescentar diversos outros recursos, como interfaces, classes abstratas, herança e muito mais.

Visão Geral da Aplicação

Decidi me basear no Sistema de Cadastro que ensinei neste artigo.

Vamos implementar todos os recursos, mas usando uma estrutura MVC.

A estrutura que mostrei naquele artigo já era bem limpa e clara, separando bem a lógica da exibição.

Desta vez vamos separar ainda melhor, organizando tudo no padrão MVC.

Estrutura da Aplicação

Nossa aplicação terá esta estrutura de arquivos e diretórios:

├── app: diretório base da estrutura MVC
│   ├── Controllers: diretório dos controllers
│   │   └── UsersController.php
│   ├── DB.php: classe para acesso ao banco de dados
│   ├── Models: diretório de Models
│   │   └── User.php
│   ├── View.php: classe para geração de Views
│   ├── Views: diretório de views
│   │   ├── template.php
│   │   ├── users.create.php
│   │   ├── users.edit.php
│   │   └── users.index.php
│   └── helpers.php: arquivo com funções genéricas
├── composer.json: arquivo de configuração do Composer
├── index.php: arquivo onde definiremos as rotas
├── init.php: arquivo de inicialização
└── vendor: diretório do Composer, com todas as dependências

Vou usar o Composer, que é o melhor gerenciador de dependências para PHP.

Ele também nos dá, de graça, um excelente autoloader, seguindo o padrão PSR-4.

Se você não usa o Composer, está esperando o quê?!

Veja este meu artigo sobre as principais funcionalidades dele. Se quiser ir mais a fundo (acredite, você vai querer), conheça o meu Curso Ultimate Composer. É rápido, barato e você aprende uma ferramenta incrível que você vai usar para o resto da vida!

Com o Composer, faremos duas coisas:

  1. Baixaremos o Slim, o micro-framework que vai cuidar das rotas (URLs Amigáveis) da nossa aplicação;
  2. Vamos configurar o autoloader, seguindo o padrão PSR-4.

Não se assuste!

Já parece muita coisa? Não é, não. É só uma boa estrutura, para facilitar nosso trabalho.

Há diversas formas de fazer URLs Amigáveis, mas eu prefiro usar o sistema de rotas do Slim.

Ele é simples e fácil de usar. Neste artigo eu mostrei como fazer tudo isso em menos de 30 segundos!

E todos os principais frameworks de hoje usam esse mesmo estilo de sistema de rotas. Então vale a pena usá-lo.

Baixe o Composer

Se você ainda não possui o Composer, baixe-o e intale-o.

Neste artigo eu mostro como fazer isso.

Baixe o Slim

Com o Composer instalado, vamos instalar o Slim:

composer require slim/slim

Esse comando vai baixar o Slim 3, que é a nova versão do framework, na data em que escrevi este artigo (dezembro de 2015).

Configure o Composer

Após baixar o Slim, o arquivo composer.json terá sido criado. Ele deve estar com este conteúdo:

{
    "require": {
        "slim/slim": "^3.0"
    }
}

Vamos deixar o arquivo já configurado com o autoloader.

Para isso, adicione as linhas destacadas no código abaixo, que é como seu arquivo deverá ficar:

{
    "require": {
        "slim/slim": "^3.0"
    },
    "autoload": {
        "psr-4": {
            "App\\" : "app/"
        },
        "files": [
            "app/helpers.php"
        ]
    }
}

Nas linhas 6 e 7 dizemos que usaremos o padrão PSR-4, associando o namespace App à pasta app.

Se você não conhece namespaces, estude neste link.

Nas linhas 9 e 10 dizemos para o Composer sempre carregar o arquivo app/helpers.php, que possui nossas funções genéricas.

Arquivo de Inicialização

Se você já me acompanha há algum tempo, sabe que eu SEMPRE recomendo que você crie Arquivos de Inicialização (Bootstrapping). E aqui não será diferente.

Crie o arquivo init.php com este conteúdo:

<?php
// diretório base da aplicação
define('BASE_PATH', dirname(__FILE__));

// credenciais de acesso ao MySQL
define('MYSQL_HOST', 'localhost');
define('MYSQL_USER', 'usuario');
define('MYSQL_PASS', 'senha');
define('MYSQL_DBNAME', 'nome_do_banco');

// configurações do PHP
ini_set('display_errors', true);
error_reporting(E_ALL);
date_default_timezone_set('America/Sao_Paulo');

Sem segredos, né?

Criando as Rotas

Agora nossa aplicação vai começar a ganhar forma.

No arquivo index.php insira este conteúdo:

<?php // inclui o autoloader do Composer require 'vendor/autoload.php'; // inclui o arquivo de inicialização require 'init.php'; // instancia o Slim, habilitando os erros (útil para debug, em desenvolvimento) $app = new \Slim\App([ 'settings' => [
        'displayErrorDetails' => true
    ]
]);
 
// página inicial
// listagem de usuários
$app->get('/', function ()
{
    $UsersController = new \App\Controllers\UsersController;
    $UsersController->index();
});


// adição de usuário
// exibe o formulário de cadastro
$app->get('/add', function ()
{
    $UsersController = new \App\Controllers\UsersController;
    $UsersController->create();
});

// processa o formulário de cadastro
$app->post('/add', function ()
{
    $UsersController = new \App\Controllers\UsersController;
    $UsersController->store();
});


// edição de usuário
// exibe o formulário de edição
$app->get('/edit/{id}', function ($request)
{
    // pega o ID da URL
    $id = $request->getAttribute('id');

    $UsersController = new \App\Controllers\UsersController;
    $UsersController->edit($id);
});

// processa o formulário de edição
$app->post('/edit', function ()
{
    $UsersController = new \App\Controllers\UsersController;
    $UsersController->update();
});

// remove um usuário
$app->get('/remove/{id}', function ($request)
{
    // pega o ID da URL
    $id = $request->getAttribute('id');

    $UsersController = new \App\Controllers\UsersController;
    $UsersController->remove($id);
});

$app->run();

Eu já coloquei a implementação de todas as rotas. Mas você pode trocar tudo por alguns echo‘s, apenas para testar todas elas, se quiser.

Classe Para Acesso ao Banco de Dados

Vamos criar uma classe para acessar o banco via PDO.

Algo simples, apenas para facilitar a conexão.

No arquivo app/DB.php coloque isto:

<?php

namespace app;

class DB extends \PDO
{
    public function __construct($dsn = null, $username = null, $password = null, $options = array())
    {
        $dsn = ($dsn != null) ? $dsn : sprintf('mysql:dbname=%s;host=%s', MYSQL_DBNAME, MYSQL_HOST);
        $username = ($username != null) ? $username : MYSQL_USER;
        $password = ($password != null) ? $password : MYSQL_PASS;
        
        parent::__construct($dsn, $username, $password, $options);
    }
}

A classe herda a PDO, apenas sobrescrevendo seu construtor, pegando os valores que definimos em nosso arquivo de inicialização.

No início do arquivo, dizemos que a classe pertence ao namespace App.

E por esse motivo, a classe PDO possui uma barra invertida, informando que ela está no namespace raiz. Sem isso, o PHP procuraria pela classe \App\PDO, que não existe.

Gerador de Views

Vamos criar uma classe para gerar views.

A ideia é simples: uma classe que receba o nome da view e um array de variáveis. O único método dessa classe vai carregar o arquivo de template, incluindo a view especificada e passando as variáveis informadas.

Eu me inspirei na classe que o Laravel 4 utiliza. Mas não se preocupe, a ideia é simples.

Este é o código do arquivo app/View.php:

<?php

namespace App;

/**
 * Classe para gerar uma view da aplicação.
 * É responsável por carregar o template geral e adicionar a view que deve ser exibida
 */
class View
{
    /**
     * Exibe uma view.
     * Função inspirada na usada pelo Laravel 4. Veja: http://laravel.com/docs/4.2/responses#views
     *
     * @link http://laravel.com/docs/4.2/responses#views
     * @param  string $viewName   Nome da view, que é o nome do arquivo em lib/views, sem o ".php"
     * @param  array  $customVars (opcional) Array com variáveis que serão usadas na view
     */
    public static function make($viewName, array $customVars = array())
    {
        // cria as variáveis do array $customVars
        extract($customVars);
        
        // inclui o template, que vai processar a view na variável $viewName
        require_once viewsPath() . 'template.php';
    }
}

A função viewsPath() nós vamos implementar no helpers.php. O arquivo template.php será criado em breve, com o template da aplicação.

O que o método make faz é usar a função extract do PHP para transformar o array em variáveis, que estarão disponíveis em nossa view.

Em seguida, o arquivo de templates é chamado. Ele que vai incluir o arquivo da view que foi especificado no primeiro parâmetro do método make.

Arquivo de Funções Genéricas

O nosso app/helpers.php vai guardar algumas funções que não estão ligadas a nenhuma classe.

<?php /** * Retorna o diretório das views */ function viewsPath() { return BASE_PATH . DIRECTORY_SEPARATOR . 'app' . DIRECTORY_SEPARATOR . 'Views' . DIRECTORY_SEPARATOR; } /** * Converte datas entre os padrões ISO e brasileiro * Fonte: http://rberaldo.com.br/php-conversao-de-datas-formato-brasileiro-e-formato-iso/ */ function dateConvert($date) { if ( ! strstr( $date, '/' ) ) { // $date está no formato ISO (yyyy-mm-dd) e deve ser convertida // para dd/mm/yyyy sscanf($date, '%d-%d-%d', $y, $m, $d); return sprintf('%02d/%02d/%04d', $d, $m, $y); } else { // $date está no formato brasileiro e deve ser convertida para ISO sscanf($date, '%d/%d/%d', $d, $m, $y); return sprintf('%04d-%02d-%02d', $y, $m, $d); } return false; } /** * Calcula a idade a partir da data de nascimento * * Sobre a classe DateTime: http://rberaldo.com.br/php-usando-a-classe-nativa-datetime/ */ function calculateAge($birthdate) { $now = new DateTime(); $diff = $now->diff(new DateTime($birthdate));
     
    return $diff->y;
}

Arquivo de Template

Vamos deixar nosso template já pronto.

Coloque este conteúdo no arquivo app/Views/template.php:

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">

        <title>Sistema de Cadastro em MVC - ULTIAMTE PHP</title>
    </head>

    <body>
        
        <?php if (isset($viewName)) { $path = viewsPath() . $viewName . '.php'; if (file_exists($path)) { require_once $path; } } ?>

    </body>
</html>

Nas linhas 11 a 20 é onde incluímos o arquivo da view passada como parâmetro para o método make da classe View.

Agora está começando a fazer sentido, né? 🙂

Criando o Modelo

Vamos criar o arquivo app/Models/User.php, que será uma classe para manipular a tabela de usuários.

O banco de dados é o mesmo da aplicação do Sistema de Cadastro. Você pode copiar do outro post, caso não tenha a tabela no seu MySQL.

<?php namespace App\Models; use App\DB; class User { /** * Busca usuários * * Se o ID não for passado, busca todos. Caso contrário, filtra pelo ID especificado. */ public static function selectAll($id = null) { $where = ''; if (!empty($id)) { $where = 'WHERE id = :id'; } $sql = sprintf("SELECT id, name, email, gender, birthdate FROM users %s ORDER BY name ASC", $where); $DB = new DB; $stmt = $DB->prepare($sql);

        if (!empty($where))
        {
            $stmt->bindParam(':id', $id, \PDO::PARAM_INT);
        }

        $stmt->execute();

        $users = $stmt->fetchAll(\PDO::FETCH_ASSOC);

        return $users;
    }


    /**
     * Salva no banco de dados um novo usuário
     */
    public static function save($name, $email, $gender, $birthdate)
    {
        // validação (bem simples, só pra evitar dados vazios)
        if (empty($name) || empty($email) || empty($gender) || empty($birthdate))
        {
            echo "Volte e preencha todos os campos";
            return false;
        }
         
        // a data vem no formato dd/mm/YYYY
        // então precisamos converter para YYYY-mm-dd
        $isoDate = dateConvert($birthdate);
         
        // insere no banco
        $DB = new DB;
        $sql = "INSERT INTO users(name, email, gender, birthdate) VALUES(:name, :email, :gender, :birthdate)";
        $stmt = $DB->prepare($sql);
        $stmt->bindParam(':name', $name);
        $stmt->bindParam(':email', $email);
        $stmt->bindParam(':gender', $gender);
        $stmt->bindParam(':birthdate', $isoDate);

        if ($stmt->execute())
        {
            return true;
        }
        else
        {
            echo "Erro ao cadastrar";
            print_r($stmt->errorInfo());
            return false;
        }
    }



    /**
     * Altera no banco de dados um usuário
     */
    public static function update($id, $name, $email, $gender, $birthdate)
    {
        // validação (bem simples, só pra evitar dados vazios)
        if (empty($name) || empty($email) || empty($gender) || empty($birthdate))
        {
            echo "Volte e preencha todos os campos";
            return false;
        }
         
        // a data vem no formato dd/mm/YYYY
        // então precisamos converter para YYYY-mm-dd
        $isoDate = dateConvert($birthdate);
         
        // insere no banco
        $DB = new DB;
        $sql = "UPDATE users SET name = :name, email = :email, gender = :gender, birthdate = :birthdate WHERE id = :id";
        $stmt = $DB->prepare($sql);
        $stmt->bindParam(':name', $name);
        $stmt->bindParam(':email', $email);
        $stmt->bindParam(':gender', $gender);
        $stmt->bindParam(':birthdate', $isoDate);
        $stmt->bindParam(':id', $id, \PDO::PARAM_INT);

        if ($stmt->execute())
        {
            return true;
        }
        else
        {
            echo "Erro ao cadastrar";
            print_r($stmt->errorInfo());
            return false;
        }
    }


    public static function remove($id)
    {
        // valida o ID
        if (empty($id))
        {
            echo "ID não informado";
            exit;
        }
         
        // remove do banco
        $DB = new DB;
        $sql = "DELETE FROM users WHERE id = :id";
        $stmt = $DB->prepare($sql);
        $stmt->bindParam(':id', $id, \PDO::PARAM_INT);
         
        if ($stmt->execute())
        {
            return true;
        }
        else
        {
            echo "Erro ao remover";
            print_r($stmt->errorInfo());
            return false;
        }
    }
}

NOTA: não me preocupei muito com validações, por não ser o foco do artigo. Por isso apenas dei echo e print_r nos erros. O correto é tratar isso da forma certa. Faça redirecionamentos enviando os erros para a outra rota, seja via URL, Session ou outro recurso. Evite exibir erros pela Model. Além de errado, vai gerar uma péssima experiência para o usuário.

Se você acompanhou o artigo do Sistema de Cadastro, não terá problemas em entender o código.

As únicas diferenças são que cada coisa está no seu respectivo método.

E estamos usando namespaces. Então precisamos informar que a classe está no namespace App\Models.

Também informamos que usaremos a classe App\DB, com o comando use. Isso permite que usemos apenas DB em vez de \App\DB em nosso código.

Note que a classe PDO está com uma barra invertida no início do seu nome. Isso é necessário pois ela está no namespace raiz. Se não a colocássemos, o PHP procuraria pela classe App\Models\PDO e geraria um erro.

Criando o Controller

Vamos criar o arquivo app/Controllers/UsersController.php, que terá um método para cada rota que definimos no index.php.

<?php namespace App\Controllers; use \App\Models\User; class UsersController { /** * Listagem de usuários */ public function index() { $users = User::selectAll(); \App\View::make('users.index', [ 'users' => $users,
        ]);
    }


    /**
     * Exibe o formulário de criação de usuário
     */
    public function create()
    {
        \App\View::make('users.create');
    }


    /**
     * Processa o formulário de criação de usuário
     */
    public function store()
    {
        // pega os dados do formuário
        $name = isset($_POST['name']) ? $_POST['name'] : null;
        $email = isset($_POST['email']) ? $_POST['email'] : null;
        $gender = isset($_POST['gender']) ? $_POST['gender'] : null;
        $birthdate = isset($_POST['birthdate']) ? $_POST['birthdate'] : null;

        if (User::save($name, $email, $gender, $birthdate))
        {
            header('Location: /');
            exit;
        }
    }



    /**
     * Exibe o formulário de edição de usuário
     */
    public function edit($id)
    {
        $user = User::selectAll($id)[0];

        \App\View::make('users.edit',[
            'user' => $user,
        ]);
    }


    /**
     * Processa o formulário de edição de usuário
     */
    public function update()
    {
        // pega os dados do formuário
        $id = $_POST['id'];
        $name = isset($_POST['name']) ? $_POST['name'] : null;
        $email = isset($_POST['email']) ? $_POST['email'] : null;
        $gender = isset($_POST['gender']) ? $_POST['gender'] : null;
        $birthdate = isset($_POST['birthdate']) ? $_POST['birthdate'] : null;

        if (User::update($id, $name, $email, $gender, $birthdate))
        {
            header('Location: /');
            exit;
        }
    }


    /**
     * Remove um usuário
     */
    public function remove($id)
    {
        if (User::remove($id))
        {
            header('Location: /');
            exit;
        }
    }
}

Note que o papel do controller é sempre pegar dados do Modelo, se necessário, e exibir algo ou redirecionar. O Controller apenas junta as outras duas camadas.

Criando as Views de Cada Ação

Agora só falta criarmos cada uma das views.

Vamos seguir esta nomenclatura: módulo.ação.

Ou seja, o nosso módulo é users, pois o sistema gerencia usuários.

As ações são index, para listar os usuários, create, para criar usuário e edit, para editar um usuário.

Assim, teremos estes três arquivos:

  1. app/Views/users.create.php
  2. app/Views/users.edit.php
  3. app/Views/users.index.php

Vamos começar pelo users.index.php:


<h1>Listagem de Usuários</h1>




<a href="/add">Adicionar Usuário</a>


<?php if (count($users) > 0): ?>


<table width="50%" border="1" cellpadding="2" cellspacing="0">

<thead>

<tr>

<th>Nome</th>


<th>Email</th>


<th>Gênero</th>


<th>Nascimento</th>


<th>Idade</th>


<th>Ações</th>

        </tr>

    </thead>


<tbody>
        <?php foreach ($users as $user): ?>

<tr>

<td><?php echo $user['name']; ?></td>


<td><?php echo $user['email']; ?></td>


<td><?php echo $user['gender'] == 'm' ? 'Masculino' : 'Feminino'; ?></td>


<td><?php echo dateConvert($user['birthdate']); ?></td>


<td><?php echo calculateAge($user['birthdate']); ?> anos</td>


<td>
                <a href="/edit/<?php echo $user['id']; ?>">Editar</a>
                <a href="/remove/<?php echo $user['id']; ?>" onclick="return confirm('Tem certeza de que deseja remover?');">Remover</a>
            </td>

        </tr>

        <?php endforeach; ?>
    </tbody>

</table>


<?php else: ?>



Nenhum usuário cadastrado


<?php endif; ?>

Veja que ele é só um trecho de HTML, que será incluso por aquele if que colocamos no arquivo app/Views/template.php.

A variável $users é passada para a view no método index da classe UsersController.

Se você tinha alguma dúvida de como esses arquivos todos iriam se relacionar, agora tudo deve estar fazendo mais sentido, né?

Agora vamos ao app/Views/users.create.php:


<h2>Cadastro de Usuário</h2>

         

<form action="/add" method="post">
    <label for="name">Nome: </label>
    
    <input type="text" name="name" id="name">

    


    <label for="email">Email: </label>
    
    <input type="text" name="email" id="email">

    

     
    Gênero:
    
    <input type="radio" name="gender" id="gener_m" value="m">
    <label for="gener_m">Masculino </label>
    <input type="radio" name="gender" id="gener_f" value="f">
    <label for="gener_f">Feminino </label>
     
    


    <label for="birthdate">Data de Nascimento: </label>
    
    <input type="text" name="birthdate" id="birthdate" placeholder="dd/mm/YYYY">

    


    <input type="submit" value="Cadastrar">
</form>

Esse foi bem simples, sem nenhum trecho de PHP, apenas um simples formulário HTML.

Já o de edição, no arquivo app/Views/users.edit.php, é bem parecido, apenas incluindo um campo oculto com o ID do usuário, além de exibir os atuais dados do registro.


<h2>Edição de Usuário</h2>

         

<form action="/edit" method="post">
    <label for="name">Nome: </label>
    
    <input type="text" name="name" id="name" value="<?php echo $user['name']; ?>">

    


    <label for="email">Email: </label>
    
    <input type="text" name="email" id="email" value="<?php echo $user['email']; ?>">

    

     
    Gênero:
    
    <input type="radio" name="gender" id="gener_m" value="m" <?php if ($user['gender'] == 'm'): ?> checked="checked" <?php endif; ?>>
    <label for="gener_m">Masculino </label>
    <input type="radio" name="gender" id="gener_f" value="f" <?php if ($user['gender'] == 'f'): ?> checked="checked" <?php endif; ?>>
    <label for="gener_f">Feminino </label>
     
    


    <label for="birthdate">Data de Nascimento: </label>
    
    <input type="text" name="birthdate" id="birthdate" placeholder="dd/mm/YYYY" value="<?php echo dateConvert($user['birthdate']) ?>">

    


    <input type="hidden" name="id" value="<?php echo $user['id'] ?>">

    <input type="submit" value="Cadastrar">
</form>

Testando o Projeto

Vamos usar o Servidor Nativo do PHP para testar o projeto.

Abra o terminal na pasta raiz do projeto e digite:

php -S localhost:8000

Depois é só acessar http://localhost:8000 em seu navegador e Voilà!

O sistema de cadastro deve funcionar igual ao anterior, que tínhamos feito sem MVC.

Não foi tão difícil assim, foi?

Conclusão

O artigo foi longo, mas espero ter explicado bem.

Tentei deixar os códigos bem comentados, para ficar fácil de entender.

Parece que é bastante coisa, mas não é tanto. É que está tudo bem dividido.

E, acredite, dá pra dividir ainda mais. Afinal, tudo dá pra melhorar.

Mostrei aqui apenas a ideia básica. A partir daqui você pode seguir seu próprio caminho.

Diga aqui nos comentários o que achou do artigo!

E se tiver dúvidas, pergunte aqui também!

NOTA: Este artigo é um excerto do Curso ULTIMATE PHP 2.0. Para conhecer todos os detalhes do curso, clique aqui.

Aprenda Ainda Mais

15 Dicas, Boas Práticas e Fundamentos do PHP

Conheça Dicas FUNDAMENTAIS para programar em PHP de forma Profissional

Não se considere Programador PHP sem antes ler este guia e adotar estas práticas!

Baixe gratuitamente este guia com 15 Dicas de PHP

Sobre Roberto Beraldo
Desenvolvedor Web desde 2007, com foco em PHP. Criador do Curso ULTIMATE PHP e autor do Blog do Beraldo (rberaldo.com.br), onde compartilha dicas sobre PHP e Programação em geral.
  • Marcos

    Ta foda aprender esse lance viu… Acho que vou continuar fazendo as coisas erradas por um tempo , ja tentei MVC para PHP e MVVM para UWP C# so que nao sai…

  • Ailton Lopes

    como resolver esse erro: Fatal error: Class ‘appControllerscategoria’ not found in C:AGLDIVERSOSwamp64wwwlojavirtual_001adminappcontrollersCategoriaController.php on line 16

    OBS: quase sempre aparece esse erro (Class…….. not found), ou seja, a classe não existe. Entretanto, a class existe (foi criada).

    • Olá. Verifique se é “categoria” ou “Categoria”. Muitos sistemas são case-sensitive

      • Ailton Lopes

        Obrigado por responder.

        Já verifiquei e alterei, mas não resolveu.

        • Você pode tentar atualizar o autoloader, executando “composer dump-autoload -o”.
          Se não funcionar, sugiro rever o processo todo. Provavelmente você errou o nome ou o caminho de algum arquivo. É possível que o autoloader não esteja corretamente configurado no arquivo composer.json.

  • Matheus Ramos

    Show de bola Beraldo!! Deu várias idéias para estudo com MVC. E esse Slim é legal demais. Parabéns!

    • Obrigado!
      A ideia é mostrar o conceito de forma simples. E o Slim’e ótimo, mesmo! Muito prático

  • Caio Nunes

    Quando posiciono o curso em “adicionar”, “editar” e “remover”, o link gerado é assim http://localhost/add
    ou http://localhost/edit/4 por exemplo, e não da forma certa http://localhost/ultimatephp-mvc/add. O que pode ser?

    • Olá.
      Basta editar os atributos href:
      Adicionar Usuário
      Você também pode usar a função dirname() com o valor de $_SERVER[‘PHP_SELF’], por exemplo.

      • Caio Nunes

        Consegui! So tirei as barras “”.

  • Clebson Pettenon

    O meu deu esse erro
    ::1:51761 [200]: / – require(): Failed opening required ‘/Users/clebsonpettenon/www/app/vendor/composer/../../app/helpers.php’ (include_path=’.:’) in /Users/clebsonpettenon/www/app/vendor/composer/autoload_real.php on line 66

    • Olá. Verifique se o arquivo helpers.php existe na pasta app. O erro diz que ele não existe.

      • Clebson Pettenon

        O arquivo existe sim. Roberto vc pode enviar o código fonte completo para o meu email?
        clebsonpettenon@gmail.com
        Abraço.

  • Jackson Lemos Moreira

    Legal, obrigado por compartilhar.
    No server local rodou bem, online somente a listagem, e quando tento editar, add e remover dá erro 404. O que pode ser?
    Obrigado!

    • Tente criar o arquivo .htaccess com este conteúdo:

      RewriteEngine On
      RewriteCond %{REQUEST_FILENAME} !-f
      RewriteRule ^ index.php [QSA,L]

      • Jackson Lemos Moreira

        Bom dia! Blz, tentei de duas formas:

        Na raiz domínio dá esse erro
        Fatal error: Class ‘AppControllersUsersController’ not found in /home/storage/2/4e/96/jlemos/public_html/index.php on line 48

        Na raiz da aplicação dá erro 404

        • o .htaccess deve ficar na raiz da aplicação.
          E como as rotas foram feitas pensando na raiz do domínio (sempre iniciadas por barra “/”), a aplicação não roda em subpastas. Se for hospedar em subpasta, crie um subdominio: mvc.seusite.com.
          Sobre a classe não encontrada, pode ser uma falha no autoloader. Rode este comando na raiz do projeto:
          composer dump-autoload

          • Jackson Lemos Moreira

            legal, deixei na raiz
            eh tentei modificar na rota para “/pasta/”, mas não funcionou, rs. vou testar com subdomínio.
            executei o composer dump-autoload, mas deu erro fatal
            Obrigado pelo apoio. Abs

          • Qual foi a mensagem de erro?

          • Jackson Lemos Moreira

            Foi essa,
            Fatal error: Uncaught exception ‘PharException’ with message ‘phar “C:ProgramDataComposerSetupbincomposer.phar” SHA1 signature could not be verified: broken signature’ in C:ProgramDataComposerSetupbincomposer.phar on line 23

            PharException: phar “C:ProgramDataComposerSetupbincomposer.phar” SHA1 signature could not be verified: broken signature in C:ProgramDataComposerSetupbincomposer.phar on line 23

            Call Stack:
            0.0039 233368 1. {main}() C:ProgramDataComposerSetupbincomposer.phar:0
            0.0039 233496 2. Phar::mapPhar() C:ProgramDataComposerSetupbincomposer.phar:23

          • Você modificou o composer.phar? Eu nunca vi esse erro, mas pelo que pesquisei, isso acontece quando o arquivo phar é modificado e o hash deixa de ser válido.
            Sugiro baixar de novo o composer. E o ideal é instalar o composer globalmente em vez de executar sempre o composer.phar de cada projeto, como mostro neste artigo: http://rberaldo.com.br/composer-php/

          • Jackson Lemos Moreira

            Então, quando rodei o composer dump-autoload a primeira vez, deu outra mensagem dizendo que tinha que atualizar executando um comando na pasta bin do composerSetup, quando executei ele abriu o arquivo composer.phar no Sublime, ao fechar pediu para salvar e eu confirmei. Foi besteira o que fiz, e deve ter isso esse o segundo erro, que foi esse que postei.

            Apesar desse erro, local continua rodando a aplicação MVC. Estou aguardando a publicação do subdomínio para testar online.

  • Leo Barreto

    Muito bom mesmo o artigo.
    A título de estudo estou recriando o projeto, porém adaptando para o meu projeto. E me surgui um problema: O nome da view não está chegando no template.php.
    Já vi e revi os códigos e não encontro onde pode está o problema

    • Olá.
      Faça debug do seu código. Você pode usar var_dump() para exibir os valores de cada variável. Isso ajuda a entender onde elas estão “perdendo os valores”.
      Também pode usar ferramentas de debug como o XDebug para facilitar o processo.

      • Leo Barreto

        Roberto, após rever o código, depois de um breve descanso, consegui achar o erro. foi pura desatenção minha. Na function estava $nomedavariavel e no template.php estava $nomedaVariavel.
        Jamais funcionaria mesmo. Rs.
        Ainda assim agradeço a atençao.
        Grande abraço

  • Rafael de Castro

    Muito bom o artigo, parabéns. Só fiquei com uma dúvida, não encontrei em lugar algum um “require ‘helpers.php'”, então como que o projeto consegue usar as funções deste arquivo? Só de estar no mesmo diretório ele já reconhece as funções?

    • O autoloader do Composer é quem faz essa maravilhosa “mágica” 🙂

      • Rafael de Castro

        Ah ok, agora que vi no composer.json, não sabia que dava pra adicionar arquivos também, pensei que era somente os namespaces, vivendo e aprendendo. Muito obrigado!

  • Luiz Lahr

    Muito bacana, valeu… Porém mesmo copiando o código e colando nos arquivos, estou recebendo o seguinte erro
    Fatal error: Class ‘AppControllersUsersController’ not found in /Users/luizlahr/Sites/WWW/testes/mvc/index.php on line 20

    O que pode ser????

    • Verifique se o seu arquivo composer.json está igual ao que mostrei aqui, com o trecho “autoload”. Também rode este comando, na raiz do projeto:

      composer dump-autoload

      Isso faz com que o Composer recarregue os dados do composer.json, para configurar o Autoloader

      • Luiz Lahr

        Deu certo Roberto 😀 Po… Até pegar as manhas desse negócio vou apanhar muito 😀

      • Luiz Lahr

        Tive um outro problema aqui… nos links por exemplo esta lá “

        No meu isso da errado… tem que estar apenas “” sem a barra

      • Luiz Lahr

        Tive um outro problema aqui… nos links por exemplo esta lá “a href=/add”

        No meu isso da errado… tem que estar apenas “a href=add” sem a barra

        • A barra serve para garantir que a URL seja relativa à raiz do domínio

  • Alexandre Unruh

    Muito legal esse artigo, aprendi bastante até favoritei a página aqui. Só uma pergunta: Você deu alguns ‘echo’ direto no Model. Foi pra simplificar ou era essa mesma a intenção? Eu tive um instrutor que dizia que o Model deveria retornar um “False” (ou algo do tipo) para o Controller que por sua vez enviaria alguma ação para a mensagem (alerta ou erro) ser exibida na View. Mas que no MVC clássico (se é que existe isso, rsrs), nem Models nem Controllers deveriam imprimir mensagens. É meio confuso isso rsrs. Procede? Abraço e obrigado por compartilhar….

    • Sim, você está certo. Eu não me preocupei com validações nesse artigo, pois não era o foco. Eu ia comentar sobre isso no artigo, mas acabei esquecendo. Vou adicionar uma observação sobre esses echo’s. O correto é sempre redirecionar de volta, passando mensagens de erro, seja via URL, via Session ou algum outro recurso.