Einleitung: Warum ein Monorepository in PHP?
\nDie Entwicklung komplexer PHP-Anwendungen (CRM, SaaS, Frameworks) steht oft vor einem Dilemma: Soll der gesamte Code in einem Repository (Monorepository) gespeichert oder in viele Microservices und Pakete aufgeteilt werden? Ein Monorepository (Monorepo) mit PHP ist eine Strategie, bei der mehrere zusammenhängende Projekte (Bibliotheken, Module, Anwendungen) in einem einzigen Git-Repository liegen.
\nIn der Praxis bietet dies:
\n- \n
- Eine einheitliche Änderungshistorie — einfacher nachzuvollziehen, wie sich eine Änderung in einem Paket auf ein anderes ausgewirkt hat. \n
- Vereinfachte CI/CD-Konfiguration — eine einzige Pipeline zum Erstellen und Testen aller Komponenten. \n
- Reduzierung von Redundanzen — gemeinsame Konfigurationen, Skripte und Abhängigkeiten. \n
- Schnelle Iteration — keine Notwendigkeit, Pakete für lokale Tests auf Packagist zu veröffentlichen. \n
Allerdings erfordert ein Monorepository Disziplin. Ohne eine korrekte Code-Organisation wird es zu einem „Spaghetti-Monolithen“. In diesem Artikel werden wir praktische Schritte zur Organisation eines PHP-Projekts in einem Monorepository durchgehen.
\n\n1. Verzeichnisstruktur des Monorepositorys
\nDas Schlüsselprinzip ist eine klare Trennung in Pakete und Anwendungen. Betrachten wir ein Beispiel einer typischen Architektur:
\n\nproject-root/\n├── apps/\n│ ├── web/ # Webanwendung (Symfony/Laravel)\n│ │ ├── public/\n│ │ ├── src/\n│ │ └── composer.json\n│ └── api/ # API-Anwendung (Lumen/Slim)\n│ ├── public/\n│ ├── src/\n│ └── composer.json\n├── packages/\n│ ├── core/ # Kern (allgemeine Schnittstellen, Entitäten)\n│ │ ├── src/\n│ │ └── composer.json\n│ ├── billing/ # Zahlungsmodul\n│ │ ├── src/\n│ │ └── composer.json\n│ └── notifications/ # Benachrichtigungsmodul\n│ ├── src/\n│ └── composer.json\n├── tools/ # Entwicklungsskripte (PHP-CS-Fixer, PHPStan)\n├── composer.json # Root-Manifest\n└── phpstan.neon # Allgemeine Analyse-Einstellungen\n\nBeachten Sie: Jedes Paket in packages/ ist eine vollwertige Composer-Bibliothek mit eigener composer.json. Dies ermöglicht es, Abhängigkeiten zu isolieren und sie separat zu testen.
Beispiel composer.json für das Paket 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. Abhängigkeitsverwaltung mit Composer
\nDie root-composer.json ist das Herz des Monorepositorys. Sie enthält:
- \n
- Eine Liste aller lokal eingebundenen Pakete (über das
path-Repository). \n - Dev-Abhängigkeiten für das gesamte Projekt (PHPUnit, PHPStan, GrumPHP). \n
- Skripte zur Automatisierung (statische Analyse, Tests). \n
Beispiel einer root composer.json
\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\nWichtige Punkte:
\n- \n
- symlink: true