How and why use MVC in PHP?

Question:

I've always built sites and systems without problems using structured PHP, curiosity came to me if it's possible to make a complete OOP system and if it's more advantageous. Searching I found MVC, but I'm having difficulties in understanding and using it, all tutorials I found use Composer, but I don't need to use it, because I don't use frameworks or libraries, I always do it in pure PHP.

The question is clear in the title, first, why use it? Since structured PHP works very well for registration, editing and deletion systems, at first I thought that MVC would only serve to complicate the code, in exchange for making it more organized.

Another thing is that I'm not able to understand, especially the View layer, could you give an example, Client crud or something like that? Just to see if I understand.

Answer:

introduction

MVC is the acronym for Model View Controller, it is an architectural pattern used as a general way of structuring code that generates a user interface (html/css/js in the case of php). The central idea is to separate your application into three logical components:

  • model. Here is the part of the application that deals with the logic of your entities, the codes that know how they work (the "problem domain" or the "business rules" of the system if you like buzzwords ) and that know how to apply validations , conversions, and interacting with the database or persistence layer.

  • view. This layer is responsible for displaying the graphical interface and interacting with the user. Each "view" is a visual representation of its "model", so if we have a "ModelQuestao" the "ViewQuestao" is the one that knows how to display the model.

  • controller. The controller is responsible for receiving user data and deciding what to do with it. It will process requests, transform their data (which comes in GET's and POST's in the case of web) and send everything to the appropriate model.

why use

The main advantage is the clear separation of responsibilities you have between the layers, each of them is responsible for a part of the work your application does, this kind of division is essential if you want to work large amounts of code or in a team. A sticky application where you have a file/class that does everything (processes requests, manipulates entity data structures, displays content, etc.) can work fine and do everything you need to, but it's a sacrifice to maintain, especially if you weren't the guy who created it (and 6 months without looking at the code you wrote will make you think it was someone else).

The fact that this pattern is widespread is also a bonus, it's much easier for you to immerse yourself in someone else's code that uses an architectural model you're already familiar with than one that has been structured to the author's taste.

how to use?

It's interesting that you're talking about how you wanted to make a system completely OOP and you ended up in MVC because you don't need to implement MVC using object orientation , the default is at a higher level of abstraction than OO programming || functional || structured. It's true that you will almost always find references to MVC using OO, however that's because OO is ubiquitous these days.

To give you an example of MVC in code: suppose you for some reason decided that it's a good idea to make a stackoverflow concurrent application, and then thinking about the problem you decided to start it with the "Question" entity, your model could look like this:

namespace Model\Questao;

function build($id, $titulo, $ultimaEdicao, $gratificacao, $criadorId)) {
    // validamos nosso modelo
    validate($id, $titulo, $ultimaEdicao, $gratificacao, $criador);

    return [
        'id' => $id,
        'titulo' => $id,
        'ultimaEdicao' => $ultimaEdicao,
        'gratificacao' => $gratificacao,
        'criador' => $criadorId
    ];
}

function validate($id, $titulo, $ultimaEdicao, $gratificacao, $criadorId) {
    if (!is_int($id) || $id < 0) {
        throw new Exception('Id inválida');
    }
    else if (mb_strlen($titulo) < 5) {
        throw new Exception('Títulos de questões devem ter no minímo 5 caracters.');
    }
    else if ($ultimaEdicao && !ehUmaDatetimeValida($ultimaEdicao)) {
        throw new Exception('Data de última edição inválida');
    }
    else if ($gratificacao && $gratificacao < 50 || $gratificacao > 200) {
        throw new Exception('Gratificações devem ser entre 50 e 200 pontos.');
    }
    else if (!is_int($criadorId) || $criadorId <= 0) {
        throw new Exception('Usuário inválido.');
    }
}

function create($questao) {
    $sql = 'INSERT INTO question (title, creationDate, fk_id_user)';
    getDb()->query(
        $sql, [$questao['titulo'], date("Y-m-d H:i:s"), $questao['criador']]
    );

    // checar se a query deu certo, talvez carregar a id no objeto para uso, etc
}

function update ($questao) {
    // mesma coisa do create, mas dessa vez UPDATE ... WHERE id=$questao['id']
}

function recuperarTodas() {
    // faz um select na db e retorna um array de questões ( build(dados..) )
}

function recuperarPorId($id) {
    // faz um select na db e constrói a questão a ser retornada com "build"
}

// delete, getQuestaoByName, etc

Note how the question model knows the rules for building and validating a question, as well as knowing how to persist, update, delete and retrieve questions from the database. Now for the View:

namespace View\Questao;

use Model\Questao as M;

function exibirTodasAsQuestoes() {
    echo '<table>';
    echo '<thead><tr>Id</tr><tr>Titulo</tr><tr>Última edição</tr><tr>Gratificação</tr><tr>Criador</tr></thead>';
    echo '<tbody>';
    foreach(M\recuperarTodas() as $questao) {
        echo '<tr><td>' . $questão['id'] . '</td><td>' . $questão['titulo'] . '</td>' . 
            '<td>' . $questão['ultimaEdicao'] . '</td><td>' . $questão['gratificacao'] . '</td>' . 
            '<td>' . $questão['criador'] . '</td></tr>';
    } 
    echo '</tbody></table>':
}

function exibirQuestao($questao) {
    // sabe como exibir o html correto para uma questão específica
}

function exibirErro($error) {
    echo // exibe o erro apropriadamente formatado
}

// etc

The view knows how to display the question in different contexts (listing, display, etc) and communicates with the model that knows the internal structure of "Question" and knows how to retrieve data from the persistence layer. Finally the controller:

namespace Controller\Questao;

use Model\Questao as M;
use View\Questao as V;

function post() {

    // também faz Sanitização do conteúdo, checa se não possui conteúdo malicioso, etc
    // todo o processamento que não é específico deste modelo.
    $id = $_POST['id'];
    $titulo = $_POST['titulo'];
    $ultimaEdicao = $_POST['ultimaEdicao'];
    $gratificacao = $_POST['gratificacao'];
    $criadorId = $_POST['criador'];

    try { 
        $questao = M\build($id, $titulo, $ultimaEdicao, $gratificacao, $criadorId);
        if ($questao['id']) { // possui id, atualizar
            M\update($questao);
        }
        else { // sem ID, criar
            M\create($questao);
        }
    }
    catch(Exception e) {
        V\exibirErro($e->getMessage());
    }
}

function exibir() {
    $id = $_POST['id'];
    $questao = M\recuperarPorId($id);
    V\exibirQUestao($questao);
}

// etc

The controller receives requests from the user, does general processing on the data for that request, calls the right functions in the model, and displays data through the view if necessary.

Notice how I didn't use classes, just namespaces (because after all working with globals is a headache) and functions, but you could easily transport this model to an OO or even remove the namespaces if you wish, the important thing is to understand that it can be implemented MVC in any desired paradigm.

obs: the code may contain some errors, do not take it to the letter as it is just an example.

should i use?

How big is your application? who will develop it? It's just you? who will maintain it? it depends on a lot of factors, if you're doing a project that you're going to throw away later (like a college paper) or something really simple maybe it's overengineering . However if you plan to make a large application that you will need to maintain for a long period of time it is worth considering this pattern, remembering of course that there are other alternatives and MVC is just one of them.

Scroll to Top