Introducción: ¿por qué un monorepositorio en PHP?
\nEl desarrollo de aplicaciones PHP complejas (CRM, SaaS, frameworks) a menudo se enfrenta a un dilema: almacenar todo el código en un solo repositorio (monorepositorio) o dividirlo en múltiples microservicios y paquetes. Un monorepositorio (monorepo) con PHP es una estrategia en la que varios proyectos relacionados (librerías, módulos, aplicaciones) residen en un único repositorio de Git.
\nEn la práctica, esto proporciona:
\n- \n
- Historial de cambios unificado — es más fácil rastrear cómo un cambio en un paquete afectó a otro. \n
- Configuración simplificada de CI/CD — un solo pipeline para compilar y probar todos los componentes. \n
- Reducción de duplicación — configuraciones, scripts y dependencias compartidos. \n
- Iteración rápida — no es necesario publicar paquetes en Packagist para pruebas locales. \n
Sin embargo, un monorepositorio requiere disciplina. Sin una organización adecuada del código, se convierte en un "monolito espagueti". En este artículo, analizaremos los pasos prácticos para organizar un proyecto PHP en un monorepositorio.
\n\n1. Estructura de directorios del monorepositorio
\nEl principio clave es una separación clara entre paquetes y aplicaciones. Veamos un ejemplo de una arquitectura típica:
\n\nproject-root/\n├── apps/\n│ ├── web/ # Aplicación web (Symfony/Laravel)\n│ │ ├── public/\n│ │ ├── src/\n│ │ └── composer.json\n│ └── api/ # Aplicación API (Lumen/Slim)\n│ ├── public/\n│ ├── src/\n│ └── composer.json\n├── packages/\n│ ├── core/ # Núcleo (interfaces comunes, entidades)\n│ │ ├── src/\n│ │ └── composer.json\n│ ├── billing/ # Módulo de pago\n│ │ ├── src/\n│ │ └── composer.json\n│ └── notifications/ # Módulo de notificaciones\n│ ├── src/\n│ └── composer.json\n├── tools/ # Scripts de desarrollo (PHP-CS-Fixer, PHPStan)\n├── composer.json # Manifiesto raíz\n└── phpstan.neon # Configuración de análisis común\n\nTenga en cuenta: cada paquete en packages/ es una librería Composer completa con su propio composer.json. Esto permite aislar las dependencias y probarlas por separado.
Ejemplo de composer.json para el paquete core
\n{\n "name": "myproject/core",\n "type": "library",\n "autoload": {\n "psr-4": {\n "MyProject\\\\Core\\\\": "src/"\n }\n },\n "require": {\n "php": ">=8.1"\n },\n "extra": {\n "branch-alias": {\n "dev-main": "1.x-dev"\n }\n }\n}\n\n2. Gestión de dependencias con Composer
\nEl composer.json raíz es el corazón del monorepositorio. Contiene:
- \n
- La lista de todos los paquetes conectados localmente (a través del repositorio
path). \n - Las dependencias de desarrollo para todo el proyecto (PHPUnit, PHPStan, GrumPHP). \n
- Scripts para automatización (análisis estático, pruebas). \n
Ejemplo de composer.json raíz
\n{\n "name": "myproject/monorepo",\n "type": "project",\n "repositories": [\n {\n "type": "path",\n "url": "packages/*",\n "options": {\n "symlink": true\n }\n }\n ],\n "require": {\n "myproject/core": "@dev",\n "myproject/billing": "@dev",\n "myproject/notifications": "@dev"\n },\n "require-dev": {\n "phpunit/phpunit": "^10.0",\n "phpstan/phpstan": "^1.10",\n "friendsofphp/php-cs-fixer": "^3.0"\n },\n "autoload": {\n "psr-4": {\n "MyProject\\\\": "packages/*/src/"\n }\n },\n "scripts": {\n "test": "phpunit",\n "analyse": "phpstan analyse",\n "cs-fix": "php-cs-fixer fix"\n }\n}\n\nPuntos clave:
\n- \n
- symlink: true