Modularizando aplicações PHP – PHP sem framework – parte 4

Tempo de leitura 6 minutos

Sabe porque modularização é o sonho de consumo de todo desenvolvedor com experiêcia? Porque você só trabalha uma vez para desenvolver e ainda facilita a manutenção em caso de bugs, já que o desenvolvimento é centralizado. Claro que você vai precisar de umas dicas, mas é pra isso que esse artigo serve.

Quer saber quando um novo artigo vai sair por aqui? Assine a newsletter!

Modularização em tecnologia da informação é um conceito onde o sistema ou software é dividido em partes distintas. Compõe o ferramental necessário para um programa mais legível com uma melhor manutenção e melhor desempenho por meio da programação estruturada.

https://pt.wikipedia.org/wiki/Modularidade

Uma coisa eu digo, modularização é um conceito criado para andar de mãos dadas com orientação a objetos. E ainda reforço: o ecossistêma do PHP nos da todas as oportunidades para aplicar isso de forma prática e elegante HOJE.

O que é modularização

Madularizar uma aplicação nada mais é que separar o projeto em partes que possam ser reutilizadas sem muito trabalho.

Imaginemos um contexto comum, a camada de autenticação e autorização de uma aplicação poderia ter:

  • Autenticação com senha
  • Autenticação social (redes sociais)
  • Formulário de cadastro
  • CRUD de usuários
  • ACL
  • Recuperação de senha
  • Configurações de tempo de sessão
  • Autenticação OAuth2/JWT para APIs

Isso tudo faz parte de um assunto/problema específico a se resolver e que seria “obter acesso ao aplciativo de forma segura e controlada”.

Imagine que você possa simplesmente rodar um comando no Terminal/CMD e pronto, isso tudo já estaria instalado e pronto para usar.

Isso é modularização, da um pouco mais de trabalho, mas uma vez que esteja pronto você vai poder reutilizar e disponibilizar instantâneamente uma feature específica que pode receber correções e novos recursos rápidamente.

Práticamente todos os frameworks trazem uma forma de modularizar partes do projeto, o Laravel com os services providers, o CakePHP com os plugins, o Zend Frameork com… bem… com ele mesmo… e tudo isso ainda mais facilitado graças a uma ferramenta chamada Composer.

O Composer e a modularização

Se você se perguntou o que o Composer tem com isso de modularização, eu gostaria de dizer que o seu mundo vai ficar um pouco maior a partir dos próximos parágrafos.

Composer é um “package manager” para PHP , em termos tupiniquins isso quer dizer que ele é um gerenciador de pacotes e que oferece recursos úteis e extensos para resolver esse problema.

Um módulo nada mais é que um pacote, assim como uma (ou library, lib, biblioteca …), um bom exemplo de pacote é o Eloquent.

Neste ponto já temos um pouco de conhecimento prático sobre o Composer postado aqui no blog, mas eu gostaria de enriquecer o assunto com mais artigos sobre isso, então aqui eu vou focar em dar dicas pontuais, ok?

O importante agora é saber que vamos falar sobre:

Deixei alguns links para você não me ter como sua única fonte de conhecimento, mas vou falar sobre cada item no momento certo de forma pontual.

Primeiramente, precisamos que nosso projeto de suporte a modularização.

Preparando o projeto PHP para modularização

Não adianta você estudar Composer, Git e SemVer (Semantic Versioning) e ter um projeto que NÃO suporte modularização ou que dificulte isso, não queremos isso, então vamos adaptar nosso micro-framework.

Se você perdeu aos outros artigos, aqui o link para se guiar:

Série PHP sem frameworks.

A primeira coisa que você vai precisar compreender é que eu quero que os módulos sejam facilmente exportados para o Packagist (ou alternativa que permita repositórios privados) para no futuro ser simples usarmos como fazemos normalmente com o comando composer require.

Se você não viu os artigos anteriores, vou tomar como base este projeto:

https://github.com/erikfig/php-do-zero/tree/01e9e086ce202eb4007923a8f224af61a8b0f23b

Então vamos criar nosso primeiro repositório local (do Composer) para abrigar nosso módulo, crie um diretório chamados modules (aqui vou colocar os nossos módulos) e dentro dele outro chamado user (este é o nosso módulo).

Acesse o diretório modules/user no terminal e rode o comando composer init respondendo as perguntas conforme fizemos em um artigo anterior.

O meu ficou assim:

{
    "name": "erikfig/module-users",
    "description": "",
    "authors": [
        {
            "name": "Erik Figueiredo",
            "email": "erik.figueiredo@gmail.com"
        }
    ],
    "require": {}
}

Por fim, vamos registrar um autoload para um futuro diretório src:


    "autoload": {
        "psr-4": {
            "ErikFig\\Framework\\Users\\": "src"
        }
    },

Agora vamos mover TODA a lógica do nosso projeto para este novo diretório. Crie um diretório src e dentro dele outros dois chamados Controllers e Models, e no mesmo nível do src crie um outro diretório chamado templates.

Mova os arquivos app/Controllers/HomeController.php e app/Models/User.php para os respectivos diretórios dentro de src. Eu também renomeei a classe HomeController para UsersController, o que me forçou alterar os nomes dos arquivos, segundo PSR-4/PSR-0.

Mova também o arquivo templates/users/index.html para o novo local.

Por último, crie uma nova classe chamado Register diretamente dentro de src.

Pronto… os arquivos estão no lugar, o meu ficou assim:

Não se esqueça de acertas TODOS os namespaces de App para o novo (que no meu caso é ErikFig\Framework\Users).

Eu fui rápido porque neste ponto nada disso tem que ser novidade pra você, ok? Se sentiu dificuldade encare como exercício para treinar.

Ainda sobre modularização, eu preciso que o meu módulo seja facilmente utilizado em qualquer outro projeto sem que eu precise ficar configurando o caminho dos templates ou as rotas (URLs usadas no módulo para acessar seus recursos no navegador) dele, eu quero tudo “mágico”.

O arquivo Register.php vai fazer isso pra gente!

<?php

namespace ErikFig\Framework\Users;

use Twig\Environment;
use ErikFig\Framework\Router;

class Register
{
    public static function handle(Environment $twig, Router $router)
    {
        // Aqui registro a rota
        $loader = $twig->getLoader();
        $loader->addPath(__DIR__ . '/../templates');

        // Aqui registro as rotas
        $router->get('/users', 'ErikFig\Framework\Users\Controllers\UsersController::index');
    }
}

Eu comentei o arquivo para facilitar, recomendo a leitura do artigo anterior para saber mais sobre rotas e URL amigáveis:

Para dar o boot no nosso módulo, vamos alterar um pouco o nosso bootstrap.php trocando as linhas 18 e 19 por:

ErikFig\Framework\Users\Register::handle($twig, $router);

Pronto, ou quase…

Um pouco de abstração

Note no Register que eu não usei a rota '/ola-{nome}' então eu removi esta action do Controller e aproveitei para criar um novo arquivo chamado AppController.php em app/Controllers com o seguinte conteúdo:

<?php

namespace App\Controllers;

use Twig\Environment;

abstract class AppController
{
    protected $twig;

    public function __construct(Environment $twig)
    {
        $this->twig = $twig;
    }
}

Note que esta classe também tem uma propriedade $twig e um método __construct, assim como o UsersController, isso porque eu vou usa-la para remover e reaproveitar este recurso em vários lugares, mas vamos por partes.

Esta classe é uma abstract, isso quer dizer que ela só serve para prover recursos e “criar uma família” de classes (não vou me aprofundar no assunto de abstração aqui, mas ainda vou falar disso aqui no blog).

Eu vou remover estes mesmos métodos da classe UsersControllers para que eu possa “herdar” da classe AppController, assim:

<?php

namespace ErikFig\Framework\Users\Controllers;

use App\Controllers\AppController;
use ErikFig\Framework\Users\Models\User;

// aqui eu herdo os recursos na AppController
class UsersController extends AppController
{
    public function index()
    {
        return $this->twig->render('users/index.html', ['users' => User::all()]);
    }
}

Viu como ficou mais simples nosso controller e o melhor, todas as classes quer herdarem a AppController já terão acesso ao Twig sem eu precisar fazer mais nada.

O importante aqui é ressaltar que:

  • Podemos modularizar código que já existe
  • Podemos aplicar melhorias para reutilização (como eu fiz com AppController).
  • Recursos comuns a vários módulos podem ficar no projeto principal ou um “módulo base”.
  • Precisamos adaptar o código a nova realidade.

Carregando nosso módulo – Repositório local com Composer

Por fim, vamos incluir nosso pacote/módulo no projeto com o Composer, é bem simples, basta incluir o parâmetro repositories com o caminho até o composer.json (na verdade eu só informo o diretório aonde está o composer.json) e o que está no "name" do meu pacote em require no composer.json do projeto (o que está na raiz):


    "repositories": [
        {
            "type": "path",
            "url": "./modules/users"
        }
    ],
    "require": {
        "erikfig/module-users": "dev-master"
    },

Note que no require eu coloquei o mesmo que está no name do composer.json que geramos em modules/users.

Meu composer.json do projeto principal atualizado:

{
    "name": "erikfig/php-do-zero",
    "authors": [
        {
            "name": "Erik Figueiredo",
            "email": "erik.figueiredo@gmail.com"
        }
    ],
    "repositories": [
        {
            "type": "path",
            "url": "./modules/users"
        }
    ],
    "require": {
        "phpunit/phpunit": "^8.3",
        "illuminate/database": "^6.10",
        "twig/twig": "^3.0",
        "erikfig/module-users": "dev-master"
    },
    "autoload": {
        "psr-4": {
            "App\\": "app",
            "ErikFig\\Framework\\": "src"
        }
    },
    "minimum-stability": "dev",
    "prefer-stable": true
}

Atualize rodando composer update na raiz do projeto.

O resultado final deve ser exatamente o mesmo que o anterior, sem mudar nada, só que agora podemos pegar todo esse código e “copiar” para outros projetos que usem a mesma base simplesmente replicando um único diretório e adicionando uma linha ao bootstrap.php.

Para se aprofundar no assunto, leia o artigo em que falei sobre como criar pacotes com Composer e PHP.

Os arquivos finais deste artigo:

https://github.com/erikfig/php-do-zero/commit/c1a6ca23952e0459746bc8dc12c2df5c1a9c3097

Mais artigos desta série

Artigo anterior

Próximo artigo

Todos os artigos

Autor: Erik Figueiredo

Músico, gamer amador, tutor de programação, desenvolvedor freelancer full cycle, com foco em PHP (Laravel e CakePHP), Javascript (Front e Node.js), Dart (Front e Flutter) e infra.

3 comentários em “Modularizando aplicações PHP – PHP sem framework – parte 4”

  1. Show de bola o artigo Erik. To sempre acompanhando suas postagens, isso tem me ajudado muito no trabalho. Seus artigos são como uma mentoria pra mim, ja que todo iniciante precisa de um mentor rsrsrs. Grande abraço

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *