Introdução: o que é um monorepositório e por que ele é necessário para um desenvolvedor PHP?
O desenvolvimento de grandes projetos PHP frequentemente enfrenta o problema de organização do código. A abordagem clássica com repositórios separados para cada componente (bibliotecas, microsserviços, frontend) leva à fragmentação, duplicação de dependências e dificuldades durante a refatoração. Uma alternativa é o monorepositório — um repositório único contendo todos os projetos e pacotes relacionados.
Neste artigo, vamos abordar na prática como organizar um monorepositório para um projeto PHP. Você aprenderá como configurar o Composer, estruturar pastas, gerenciar dependências e organizar CI/CD. O artigo é voltado para desenvolvedores PHP de nível intermediário, familiarizados com os fundamentos do Git e Composer.
Principais vantagens do monorepositório:
- Histórico unificado de alterações e commits atômicos
- Facilidade de refatoração de dependências compartilhadas
- Ferramentas e configurações unificadas
- Simplificação do CI/CD por meio de um pipeline único
Estrutura do monorepositório: escolhendo a arquitetura correta
O elemento-chave de um monorepositório bem-sucedido é uma estrutura de pastas bem planejada. Para projetos PHP, recomendamos o seguinte modelo, baseado na separação em pacotes e aplicações:
monorepo/├── apps/ # Aplicações prontas (sites web, APIs, scripts de console)│ ├── api/ # REST API em Slim ou Laravel│ │ ├── public/│ │ ├── src/│ │ └── composer.json│ └── admin/ # Painel de administração│ ├── public/│ ├── src/│ └── composer.json├── packages/ # Pacotes PHP reutilizáveis (bibliotecas)│ ├── core/ # Núcleo do sistema: classes base, exceções│ │ ├── src/│ │ └── composer.json│ ├── users/ # Pacote para gerenciamento de usuários│ │ ├── src/│ │ └── composer.json│ └── payments/ # Pacote de pagamentos│ ├── src/│ └── composer.json├── tools/ # Scripts de build e auxiliares├── tests/ # Testes de integração e E2E para todo o projeto├── composer.json # Manifesto raiz (geralmente "type": "project")├── composer.lock├── phpstan.neon├── phpunit.xml.dist└── .gitignoreCada pacote em packages/ é uma biblioteca Composer independente com seu próprio composer.json. As aplicações em apps/ conectam esses pacotes como dependências locais. Essa estrutura permite:
- Isolar a lógica e testar pacotes de forma independente
- Usar tipagem estrita e autoloading PSR-4
- Reutilizar código entre diferentes aplicações sem cópia
Configuração do Composer para trabalhar com monorepositório
O Composer é a principal ferramenta de gerenciamento de dependências em PHP. Para trabalhar com um monorepositório, usamos dois mecanismos-chave: caminhos locais (path) e manifesto raiz.
Passo 1: composer.json raiz
Na raiz do projeto, criamos um manifesto mínimo que define que este é um monorepositório:
{ "name": "mycompany/monorepo", "type": "project", "require": { "php": "^8.1" }, "autoload": { "psr-4": { "MyCompany\\\\": "packages/" } }, "scripts": { "test": "phpunit", "phpstan": "phpstan analyse" }}Passo 2: Dependências locais nos pacotes
Cada pacote em packages/users/ deve ter seu próprio composer.json. Por exemplo:
{ "name": "mycompany/users", "type": "library", "require": { "php": "^8.1", "mycompany/core": "*" }, "autoload": { "psr-4": { "MyCompany\\\\Users\\\\": "src/" } }}