Expand MVC structure and modularize by files?

Asked

Viewed 340 times

2

I’m trying to understand the pattern MVC and created an example with CRUD users (with login), but I don’t know if it’s the best way I’ve created.

Follow a few pages and the link to download the project:

index php.

<?php
/**
 * Created by PhpStorm.
 * User: Leonardo Vilarinho
 * Date: 10/03/2016
 * Time: 00:55
 */

// include da camada Controller
require_once 'controller/ControllerLogin.php';



// Se variáveis de sessão tiverem ativas então já fez o login
if(isset($_SESSION['usuario']) and isset($_SESSION['id']))
{
    // define ato como listar-usuarios (primeira página apos login)
    $_GET['ato'] = (isset($_GET['ato'])) ? $_GET['ato'] : "listar-usuarios" ;
}
// se login não tiver sido feito
else
{
    // o ato será entrar
    $_GET['ato'] = "entrar";
}

//instancia uma nova classe Controller (do arquivo ControllerLogin ) 
$controller = new ControllerLogin();

//chama método do controller
$controller->requerir();

Controllerlogin.php

<?php

/**
 * Created by PhpStorm.
 * User: Leonardo Vilarinho
 * Date: 10/03/2016
 * Time: 00:56
 */

// include em camada model
require_once 'model/ModelLogin.php';

class ControllerLogin
{
    // variavel para ser a camada model
    private $model = NULL;

    // metodo contrutor, sempre que a classe ControllerLogin for criada ele executará esse metodo
    public function __construct()
    {
        //instancia uma classe da camada Model
        $this->model = new ModelLogin();
    }

    // método para encaminhar ação do usuário
    public function requerir()
    {
        // pega o get do link (exemplo index.php?ato=entrar) ato é a ação e entrar é o valor da ação
        $ato = (isset($_GET['ato'])) ? $_GET['ato'] : NULL;
        try
        {
            // verifica e chama metrodo para fazer ação selecionada
            if(!$ato or $ato == "entrar")
            {
                $this->fazerLogin();
            }
            else if($ato == "listar-usuarios")
            {
                $this->listarUsuarios();
            }
            else if($ato == "novo-usuario")
            {
                $this->novoUsuario();
            }
            else if($ato == "editar-usuario")
            {
                $this->editarUsuario();
            }
            else if($ato == "apagar-usuario")
            {
                $this->apagarUsuario();
            }
            else if($ato == "sair")
            {
                $this->sairSistema();
            }
        }
        catch(Exception $ex)
        {

        }

    }

    // método como um goto, para ir para uma página especifica
    private function irPara($pagina)
    {
        header("Location:".$pagina);
    }

    // método para o ato entrar
    private function fazerLogin()
    {
        // titulo da página
        $titulo = "Login MVC";

        // se formuĺário de login foi enviado (quando usuário clica em Entrar no login)
        if(isset($_POST['login-requerido']))
        {
            try
            {
                // cria uma variavel login para armazenar o resultado do metodo preparaLogin do model
                // aqui ele chama o métolo preparaLogin do arquivo ModelLogin passando os dados informados pelo usuario
                $login = $this->model->preparaLogin($_POST['nome'], $_POST['senha']);

                // se login for true (foi validado)
                if($login)
                {
                    // ele vai para a página com o ato de listar usuarios
                    $this->irPara("index.php?ato=listar-usuarios");
                }
                else
                {
                    // define um erro
                    $erro = "Usuário ou senha inválido(a).";
                }
            }
            catch(ValidationException $ex)
            {
                $erro = $ex->pegarErros();
            }
        }
        // inclue (escreve) arquivo entrar.php na página atual
        include 'view/entrar.php';
    }

    // método para o ato listar-usuarios
    private function listarUsuarios()
    {
        // define titulo da página
        $titulo = "Listagem de Usuários";
        try
        {
            // cria uma variavel lista para pegar o retorno do metodo listarTodos de model "usuarios" é a tabela do banco
            $lista = $this->model->listarTodos("usuarios");

            // se lista tiver vazia ou nao foi declarada
            if(empty($lista) or !$lista)
            {
                // define um erro
                $erro = "Sem usuários";
            }
        }
        catch(ValidationException $ex)
        {
            $erro = $ex->pegarErros();
        }

        // inclue (escreve) arquivo listar-usuarios.php na página atual
        include 'view/listar-usuarios.php';
    }

    // método para o ato novo-usuario
    private function novoUsuario()
    {
        // define titulo da página
        $titulo = "Adicionar Usuário";

        // se usuario clicou no botao Criar do formulario
        if(isset($_POST['novousuario-requerido']))
        {
            try
            {
                // cria uma variavel cadastro para armazenar o resultado do metodo preparaUsuarioNovo do model
                // aqui ele chama o métolo preparaUsuarioNovo do arquivo ModelLogin passando os dados informados pelo usuario
                $cadastro = $this->model->preparaUsuarioNovo($_POST['nome'], $_POST['senha']);

                // se fez o cadastro de usuário com sucesso
                if($cadastro)
                {
                    // volta para a página de listagem
                    $this->irPara("index.php?ato=listar-usuarios");
                }
                else
                {
                    // define um erro
                    $erro = "Houve um erro ao gravar o usuário.";
                }
            }
            catch(ValidationException $ex)
            {
                $erro = $ex->pegarErros();
            }
        }

        // inclue (escreve) arquivo novo-usuario.php na página atual
        include 'view/novo-usuario.php';
    }

    // método para o ato editar-usuario
    private function editarUsuario()
    {
        // define um titulo
        $titulo = "Editar Usuário";

        // pega id que está no link (index.php?ato=editar-usuario&id=4) id é 4
        $id = (int) $_GET['id'];

        // pesquisa usuario a ser editado pelo id e coloca em $usuario
        $usuario = $this->model->preparaUsuarioId($id);

        // se formulario de editar-usuario foi enviado
        if(isset($_POST['editarusuario-requerido']))
        {
            try
            {
                // chama método do model que edita um usuario
                $edicao = $this->model->preparaUsuarioEditar($_POST['id'], $_POST['nome'], $_POST['senha']);

                //se editou com sucesso
                if($edicao)
                {
                    // volta para listar usuarios
                    $this->irPara("index.php?ato=listar-usuarios");
                }
                else
                {
                    //define um erro
                    $erro = "Houve um erro ao editar o usuário.";
                }
            }
            catch(ValidationException $ex)
            {
                $erro = $ex->pegarErros();
            }
        }
        // inclue (escreve) arquivo editar-usuario.php na página atual
        include 'view/editar-usuario.php';
    }

    // método para o ato apagar-usuario
    private function apagarUsuario()
    {
        // titulo da página
        $titulo = "Editar Usuário";
        // pega id que esta no link " href="index.php?ato=apagar-usuario&id={$lista[$item]['id']}" "
        $id = (int) $_GET['id'];
        try
        {
            // chama metodo de apagar na camada model
            $tentativa = $this->model->preparaUsuarioApagar($id);

            // se apagou
            if($tentativa)
            {
                // vai para listagem
                $this->irPara("index.php?ato=listar-usuarios");
            }
            else
            {
                // exibe um erro
                $erro = "Houve um erro ao apagar o usuário.";
            }
        }
        catch(ValidationException $ex)
        {
            $erro = $ex->pegarErros();
        }
    }

    // método para o ato sair
    private function sairSistema()
    {
        // destroi variaveis de sessão
        unset($_SESSION['id']);
        unset($_SESSION['usuario']);
        // destroi sessao
        session_destroy();
        //vai para página de login
        $this->irPara("index.php?ato=entrar");
    }
}

Modellogin.php

<?php

/**
 * Created by PhpStorm.
 * User: Leonardo Vilarinho
 * Date: 10/03/2016
 * Time: 01:10
 */

// include na biblioteca de CRUD
require_once 'libs/crud.php';

// inicia sessao
session_start();

class ModelLogin
{
    // variavel privada para chamar o crus
    private $crud = NULL;

    // metodo contrutor, sempre que a classe ModelLogin for criada ele executará esse metodo
    public function __construct()
    {
        // instancia um novo crud
        $this->crud = new CRUD();
    }

    // método que pega nome e senha do login
    public function preparaLogin($nome, $senha)
    {
        // aqui tem a validação dos campos (de tamanho etc)

        // retorna o resultado do método efetua login
        return $this->efetuaLogin($nome, $senha);
    }

    // metodo que verifica login (pega dados no banco e compara com os recebidos)
    private function efetuaLogin($nome, $senha)
    {
        try
        {
            // chama o metodo consult do crud na tabela usuarios onde a coluna usuario é igual nome
            // e armazena em usuario
            $usuario = $this->crud->consult("usuarios", "*", "usuario = {$nome}");

            // se o nome digitado for igual a coluna 'usuario' do primeiro resultado da consulta
            // e o a senha equivale a criptografada do banco
            if($nome == $usuario[0]['usuario'] and password_verify($senha, $usuario[0]['senha']))
            {
                // cria variaveis de sessao (que sao destuidas somente quando o navegadore fecha)
                $_SESSION['id'] = $usuario[0]['id'];
                $_SESSION['usuario'] = $usuario[0]['usuario'];

                return true;
            }
            else
            {
                return false;
            }
        }
        catch(CRUDException $ex)
        {
            return false;
        }
    }

    // método que pega a tabela a ser listada
    public function listarTodos($tabela)
    {
        // retorna resultado da execução
        return $this->executarConsulta($tabela);
    }

    // método para consultar em uma tabela
    private function executarConsulta($tabela)
    {
        try
        {
            // retorna um array com o resultado da pesquisa de todas as colunas (*)
            return $resultado = $this->crud->consult($tabela, "*");
        }
        catch(CRUDException $ex)
        {
            return false;
        }
    }

    // método que pega dados para criar um novo usuario
    public function preparaUsuarioNovo($nome, $senha)
    {
        // retorna resultado do insert
        return $this->cadastraUsuario($nome, $senha);
    }

// metodo que cadastro usuario no banco
    private function cadastraUsuario($nome, $senha)
    {
        try
        {
            // consulta no banco se tem um usuario com o mesmo nome 
            $verifica = $this->crud->consult("usuarios", "*", "usuario = {$nome}");

            // se nao tiver encontrado um usuario igual
            if(empty($verifica) or $verifica == null)
            {
                // insere novo usuario
                $this->crud->insert
                (
                    "usuarios",
                    array("usuario", "senha"),
                    array($nome, password_hash($senha, PASSWORD_DEFAULT))
                );
                return true;
            }
            // se usuario ja tiver cadastrado
            else
            {
                return false;
            }
        }
        catch(CRUDException $ex)
        {
            return false;
        }
    }

    // metodo que pega id do usuario a ser editado (para pegar os dados dele e colocar na pagina de edição)
    public function preparaUsuarioId($id)
    {
        // retorna resultado da procura
        return $this->procuraUsuarioId($id);
    }

    // procura um usuario por id
    private function procuraUsuarioId($id)
    {
        try
        {
            // $consulta  vai receber um array com os dados daquele usuario
            $consulta = $this->crud->consult("usuarios", "*", "id = {$id}");

            // retorna o array ou false se nao achou usuario
            return (!empty($consulta)) ? $consulta : false;

        }
        catch(CRUDException $ex)
        {
            return false;
        }
    }

    // pega novas dados do usuario a ser editado
    public function preparaUsuarioEditar($id, $nome, $senha)
    {
        // retorna o resultado da edição
        return $this->editarUsuario($id, $nome, $senha);
    }

    // edita usuario
    private function editarUsuario($id, $nome, $senha)
    {
        try
        {
            // retorna true ou false se editou ou nao o usuario
            return $this->crud->update
                (
                    "usuarios",
                    array("usuario", "senha"),
                    array($nome, password_hash($senha, PASSWORD_DEFAULT)),
                    "id = {$id}"
                );
        }
        catch(CRUDException $ex)
        {
            return false;
        }
    }

    // pega id do usuario a ser apagado
    public function preparaUsuarioApagar($id)
    {
        return $this->apagarUsuario($id);
    }

    //metodo para apagar usuario
    private function apagarUsuario($id)
    {
        try
        {
            // retorna true ou false de acordo com o sucesso
            return $this->crud->delete
            (
                "usuarios",
                "id = {$id}"
            );
        }
        catch(CRUDException $ex)
        {
            return false;
        }
    }
}

enter php.

<?php
/**
 * Created by PhpStorm.
 * User: Leonardo Vilarinho
 * Date: 10/03/2016
 * Time: 00:59
 */

// inclui arquivo do template (o inicio da pagina)
include_once 'template/header.php';

// se tiver erro armazena numa variavel o erro do Controller em um painel vermelho
$printErro = (isset($erro))
    ? "<div class='text-danger text-center'><strong>{$erro}</strong></div>"
    : "";

?>
    <section class="row">
        <div class="col-md-4 col-md-offset-4">
            <div class="panel panel-primary">
                <form method="post">
                    <div class="panel-heading">
                        <strong><?php echo $titulo; ?></strong>
                    </div>
                    <?php echo $printErro; ?>
                    <div class="panel-body">
                            <input name="nome" required  placeholder="Usuário" type="text" class="form-control"/>
                            <input name="senha" required placeholder="Senha" type="password" class="form-control" />
                            <!-- informa formulario a ser enviado desta página e quando ele foi enviado -->
                            <input name="login-requerido" value="1" type="hidden" />
                    </div>
                    <div class="panel-footer">
                        <input value="Entrar" type="submit" class="btn btn-primary" />
                    </div>
                </form>
            </div>
        </div>
    </section>

<?php
// inclui fim do template
include_once 'template/scripts.php';
include_once 'template/end.php';

list-users.php

<?php
/**
 * Created by PhpStorm.
 * User: Leonardo Vilarinho
 * Date: 10/03/2016
 * Time: 14:16
 */

// inclui arquivo do template (o inicio da pagina)
include_once 'template/header.php';

?>
    <section class="row">
        <div class="panel text-right">
            <a class="btn btn-primary" href="index.php?ato=novo-usuario" ><i class="fa fa-plus"> Novo</i></a>
        </div>

        <div class="col-md-12">
            <table class="table table-responsive table-bordered table-hover">
            <!-- cabeça da tabela -->
                <thead>
                    <tr>
                        <th>ID</th>
                        <th>Nome</th>
                        <th>Ação</th>
                    </tr>
                </thead>

                <?php
                // enquanto tiver item na lista do metodo listarUsuarios do controller
                for($item = 0; $item < count($lista); $item ++)
                {
                    /*
                        botao editar tem um ato de editar-usuario e o id do usuario a editar

                        o botao apagar chama um javascript de confimação e o botao sim chama o ato
                        apagar-usuario e o id do usuario

                    */
                    echo <<<ITEM
                <tr>
                    <td>{$lista[$item]['id']}</td>
                    <td>{$lista[$item]['usuario']}</td>
                    <td>
                        <a class="btn btn-warning" href="index.php?ato=editar-usuario&id={$lista[$item]['id']}" ><i class="fa fa-pencil"></i></a>
                        <a class="btn btn-danger apagar" id="{$lista[$item]['id']}" ><i class="fa fa-trash"></i></a>

                        <div class="text-right oculto confirmacao{$lista[$item]['id']}">
                            <span>Deseja realmente excluir?</span>
                            <a class="btn btn-danger nao" id="{$lista[$item]['id']}" >Não</a>
                            <a class="btn btn-success" href="index.php?ato=apagar-usuario&id={$lista[$item]['id']}" >Sim</a>
                        </div>
                    </td>
                </tr>
ITEM;
                }
                ?>
            </table>
        </div>
    </section>

<?php
//inclui scripts do template
include_once 'template/scripts.php';

//adiciona script somente a essa pagina
echo "<script src='js/excluir-usuario.js' type='text/javascript'></script>";

//inclui final do template
include_once 'template/end.php';

The doubt is as for example expand, create a crud of notes for example without having to put in the ControllerLogin and ModelLogin. That is, create new classes for other objects without being users (login). And if this way I used is correct?

Download the project: zip archive.

  • 1

    I didn’t quite understand what the point of doubt was. You want to unlock the model?

  • The question is how to expand the sitesma. I currently have the modelLogin, viewLogin and controllLogin.. As I expand by putting for example user notes, the right thing would be to create a model Otas, viewNotas and controllerNotas. But I don’t know how to implement it in separate files. In case I would have to create a universal controller to distribute the act flow among the other controllers?

  • And if I’m inplementando in the right way, if there’s a right way

  • I think what you’re looking for is more like HMCV. You can also create type modules widgets, some frameworks have examples that can serve as a basis for you.

1 answer

1


Buddy, you’re going on a rationale as well, to lighten up a little bit, the idea is to take out any and all structural code, and enable everything in object orientation as you can do this?

First you have to work with get navigation, via Class and Method, for example: index.php? c=classe&m=method, then of course you can organize that URL to a friendly URL.

your index.php would look something like this:

include 'CoreController.php';

$core = new CoreController();

with Corecontroller more or less like this:

class CoreController {
    private $instance;        

    public function __construct() {

        $classe = $_GET['c'];
        $metodo = $_GET['m'];

        if(isset($classe) && $classe != '') {
            $this->instance = new $classe();
            if(isset($metodo) && $metodo != '') {
                $this->instance->$metodo();
            } else {
                $this->instance->index();
            }
        } else {
            $this->instance = new MainController();
            $this->instance->index();
        }

    }
}

The $instance is the controller loaded, in it you play the desired content, and loads the desired model as you did with Controllerlogin and Modellogin

To improve, you can create additional methods in Corecontroller, to check if past GET is valid, if there is the control requested in $_GET['c'], if there is the method in the requested control, etc. You can work with passing arguments to the method as well, included more GET variables in your request.

All content validation, such as checking whether the user is logged in or not, should be done directly in your Controller and not in the index as in your example. If it is browsing Controllerlogin to display a logged in content, but it is not logged in, this controller should be able to redirect it to another controller to log in, or to display content available to the anonymous user (not logged in)

In my example, you can redirect through the URL itself simply by passing the controller and method via GET.

  • About POO I disagree, it does not need to be entirely oriented, this is fad. Now the vision of how to pass the act was good, so avoid many checks as I was doing. I will edit by putting a modified way, passing the class and the method in the same parameter.. although I find it a little insecure to pass this data by get. And about the session check would really be in the Controller. Thank you

  • Well, about Object Orientation you can say it’s a fad now, but if one day you have a big project running, you’ll feel the weight that an object orientation can do in terms of code maintenance, besides, it’s always good you keep your POO up to date, This will help you abstract more knowledge and will make a difference in competition in a job vacancy.

  • On safety depends on how you will do the treatments of your get, as I said in my reply, you can create methods to validate the gets parameters in the Corecontroller class and you can ensure that every specified Controller requested is already secured by the Corecontroller, If I do, you deny the Controller request requested in GET in Corecontroller itself.

  • Remembering that any and all access will always pass through the Corecontroller first before arriving at the specific Controller of the request.

  • I say because it is practically useless to have a view class, because it is very rare to have a method in the view, but it will taste. I understand the work of Core, I say a little insecure by displaying the names of the classes and methods in the link. But it’s just the feeling even though thinking about it doesn’t attract so many problems

  • I understand, you can start from the principle of naming all your Controller classes according to the content to be displayed and take technical terms in the class name, as example, you want to take the user to change the password, you would have a controller class called Conta and a method in this class called AlterarSenha to URI something like: index.php?c=Conta&m=AlterarSenha, if you leave it with Friendly URL it would look something like: index.php/Conta/AlterarSenha

Show 1 more comment

Browser other questions tagged

You are not signed in. Login or sign up in order to post.