Symfony Bundles projektübergreifend teilen: Composer, Private Packagist und Satis
AI generated
SF
{ }
Symfony · Bundles teilen · Composer · Private Packagist
Symfony Bundles projektübergreifend teilen
Private Packagist, Satis und Monorepo im Vergleich

Sobald ein internes Symfony Bundle in mehr als einem Repository gebraucht wird, stellt sich die Frage nach dem richtigen Verteilweg. Dieser Artikel vergleicht Private Packagist, ein selbst gehostetes Satis und Monorepo-Strategien, inklusive Composer-Konfiguration und CI-Absicherung, damit Bundles zuverlaessig und versioniert in mehreren Projekten ankommen.

17 Min. Lesezeit Private Packagist · Satis · Composer Repository · CI Symfony 7.x · Composer 2.x

1. Warum interne Bundles ueberhaupt verteilt werden muessen

Ein internes Symfony Bundle loest erst dann sein volles Wiederverwendungspotenzial ein, wenn es zuverlaessig in mehrere unabhaengige Projekt-Repositories eingebunden werden kann, ohne dass jedes Projekt eine eigene Kopie des Bundle-Codes pflegt. Composer ist dabei bereits das richtige Werkzeug, es fehlt lediglich ein Ort, an dem das Paket fuer alle beteiligten Projekte auffindbar und mit Versionsnummern verwaltet ist. Ohne diesen zentralen Ort landen Teams schnell wieder bei Copy-Paste oder bei fragilen Git-Submodulen.

Der Unterschied zu oeffentlichen Composer-Paketen: Ein internes Bundle soll typischerweise nicht auf Packagist.org landen, weil es unternehmensspezifische Logik, interne API-Anbindungen oder schlicht keine allgemeine Relevanz fuer die Oeffentlichkeit hat. Genau fuer diesen Fall gibt es etablierte Loesungen, die dieselbe Composer-Erfahrung wie ein oeffentliches Paket bieten, aber den Zugriff auf berechtigte Teams beschraenken.

Wer ein Symfony Bundle projektuebergreifend teilen will, sollte diese Entscheidung fruehzeitig treffen, idealerweise schon beim ersten Bundle im Unternehmen, weil ein spaeterer Wechsel des Verteilwegs bedeutet, dass composer.json in jedem konsumierenden Projekt angepasst werden muss. Je mehr Projekte bereits ein Bundle referenzieren, desto teurer wird ein solcher Wechsel spaeter, weil jede Aenderung koordiniert und getestet werden muss.

Ein oft uebersehener Vorteil einer fruehen, sauberen Verteil-Strategie: Sie zwingt Teams dazu, von Anfang an ueber Versionierung nachzudenken, statt Bundles als staendig veraenderliche, ungetaggte main-Branches zu behandeln. Ein Bundle ohne echte Releases laesst sich zwar technisch per VCS-Repository referenzieren, verhindert aber, dass konsumierende Projekte selbst entscheiden koennen, wann sie eine neue Version uebernehmen.

2. Die drei gaengigen Verteilwege im Ueberblick

Fuer interne Symfony Bundles haben sich in der Praxis drei Ansaetze etabliert. Private Packagist ist ein gehosteter Dienst, der wie Packagist.org funktioniert, aber Zugriffskontrolle pro Team oder Organisation bietet. Satis ist ein Composer-eigenes Werkzeug, um ein eigenes, statisches Paket-Repository zu generieren, das auf einem beliebigen Webserver oder sogar in einem einfachen Git-Repository gehostet werden kann. Der dritte Weg, direkte VCS-Repositories in Composer, verzichtet komplett auf einen Paketserver und verweist stattdessen direkt auf das Git-Repository des Bundles.

Alle drei Wege haben gemeinsam, dass sie echte Versionsnummern ueber Git-Tags nutzen und composer update im Ziel-Projekt normal funktioniert. Der Unterschied liegt in Betriebsaufwand, Geschwindigkeit und Funktionsumfang wie automatischer Sicherheitsscans oder Statistiken ueber Paketnutzung, die vor allem Private Packagist zusaetzlich mitbringt.

3. Private Packagist im Detail

Private Packagist, betrieben vom Composer-Team selbst, ist die pflegeleichteste Option fuer Unternehmen, die ein Symfony Bundle teilen wollen, ohne eigene Infrastruktur zu betreiben. Nach Verbindung mit dem Git-Provider synchronisiert Private Packagist automatisch neue Tags und aktualisiert die verfuegbaren Versionen, ohne dass ein manueller Build-Schritt noetig ist. Zugriff wird ueber Teams und ein API-Token gesteuert, das im Ziel-Projekt in der auth.json hinterlegt wird.

Der Composer-Konfigurationseintrag im Ziel-Projekt ist minimal: Ein composer-Repository vom Typ composer, das auf die Private-Packagist-URL der eigenen Organisation zeigt. Composer fragt dann bei jedem Update automatisch alle konfigurierten Repositories ab, zuerst Packagist.org fuer oeffentliche Pakete, dann die eigene Private-Packagist-Instanz fuer interne Bundles.

Ein weiterer Vorteil von Private Packagist, der bei der ersten Einrichtung leicht uebersehen wird: Der Dienst bietet automatische Sicherheitswarnungen, wenn eine der Abhaengigkeiten eines Bundles eine bekannte Schwachstelle enthaelt, vergleichbar mit Dependabot fuer GitHub. Fuer Unternehmen, die mehrere Dutzend interne Bundles pflegen, ist dieser zentrale Ueberblick oft der ausschlaggebende Grund fuer die Wahl von Private Packagist gegenueber einer selbst gehosteten Loesung.


{
  "repositories": [
    {
      "type": "composer",
      "url": "https://repo.packagist.com/acme-corp/"
    }
  ],
  "require": {
    "acme/audit-bundle": "^2.3",
    "acme/notification-bundle": "^1.0"
  }
}

4. Satis: das eigene, selbst gehostete Repository

Satis ist die kostenlose Alternative fuer Teams, die keine externe Abhaengigkeit zu einem gehosteten Dienst wollen. Es handelt sich um ein statisches Paket-Repository, das aus einer satis.json-Konfiguration generiert wird und anschliessend als reine Dateisammlung auf einem beliebigen Webserver liegt. Der zentrale Nachteil gegenueber Private Packagist: Satis muss aktiv per Cronjob oder CI-Pipeline neu gebaut werden, sobald ein neuer Tag in einem der referenzierten Bundle-Repositories erscheint, sonst sehen Ziel-Projekte die neue Version nicht.

Fuer Teams mit bestehender CI/CD-Infrastruktur ist dieser zusaetzliche Build-Schritt meist unproblematisch, weil er sich als weiterer Pipeline-Job neben den ohnehin vorhandenen Deployment-Jobs einreiht. Der Vorteil: volle Kontrolle ueber die Infrastruktur, keine laufenden Kosten fuer einen externen Dienst, und die Moeglichkeit, Satis selbst hinter einer internen Firewall zu betreiben, wenn Bundles besonders sensible Logik enthalten.


# Regenerate the static Satis repository after a new bundle tag was pushed
php satis.phar build satis.json public/

# Typical cron entry: rebuild every 10 minutes to pick up new tags
*/10 * * * * php /opt/satis/satis.phar build /opt/satis/satis.json /var/www/packages.internal

Die generierte packages.json und die dazugehoerigen Metadaten landen im angegebenen Ausgabeverzeichnis und muessen anschliessend nur noch von einem einfachen Webserver ausgeliefert werden, ein voller Anwendungsserver ist dafuer nicht noetig.


{
  "name": "acme-corp/satis-repository",
  "homepage": "https://packages.internal.acme-corp.de",
  "repositories": [
    { "type": "vcs", "url": "git@github.com:acme-corp/audit-bundle.git" },
    { "type": "vcs", "url": "git@github.com:acme-corp/notification-bundle.git" }
  ],
  "require-all": true
}

5. Der Zwischenweg: VCS-Repository ohne Paketserver

Fuer ein einzelnes oder wenige Bundles lohnt sich oft nicht einmal Satis. Composer kann ein Git-Repository direkt als Paketquelle referenzieren, ganz ohne generiertes Paket-Repository dazwischen. Composer liest dabei die composer.json direkt aus dem referenzierten Repository und leitet verfuegbare Versionen aus dessen Git-Tags ab. Dieser Weg ist der schnellste Einstieg, skaliert aber schlecht, sobald zehn oder mehr interne Bundles verteilt werden muessen, weil jedes Ziel-Projekt jeden einzelnen VCS-Eintrag in seiner composer.json pflegen muss.

Ein praktischer Zwischenschritt: Wer mit VCS-Repositories startet und spaeter zu Private Packagist oder Satis wechselt, muss lediglich den repositories-Block in jedem Ziel-Projekt austauschen, die require-Zeilen mit Paketnamen und Versionsbeschraenkung bleiben unveraendert. Dieser geringe Migrationsaufwand macht den VCS-Ansatz zu einem vertretbaren Startpunkt, solange die Anzahl interner Bundles ueberschaubar bleibt.


{
  "repositories": [
    {
      "type": "vcs",
      "url": "git@github.com:acme-corp/audit-bundle.git"
    }
  ],
  "require": {
    "acme/audit-bundle": "^2.3"
  }
}

6. CI-Absicherung fuer geteilte Bundles

Ein Symfony Bundle, das in mehreren Projekten verwendet wird, braucht eine eigene CI-Pipeline im Bundle-Repository selbst, unabhaengig von den Pipelines der konsumierenden Projekte. Diese Pipeline sollte PHPUnit-Tests mit einem minimalen Test-Kernel, statische Analyse mit PHPStan und einen Kompatibilitaetscheck gegen mehrere unterstuetzte Symfony-Versionen umfassen. Ohne diese Absicherung bemerkt ein Team eine Breaking Change im Bundle erst, wenn ein konsumierendes Projekt nach composer update fehlschlaegt, oft weit entfernt vom eigentlichen Verursacher.

Ein zusaetzlicher Sicherheitsnetz-Baustein ist ein automatisierter Release-Prozess, der bei jedem Merge in den main-Branch pruefit, ob die composer.json-Version-Constraints und der aktuelle CHANGELOG-Eintrag zusammenpassen. Tools wie semantic-release lassen sich auch fuer PHP-Projekte adaptieren, um Versionsnummern automatisch aus Commit-Nachrichten abzuleiten, statt sie manuell zu pflegen.

Wichtig ist ausserdem ein dokumentierter Upgrade-Pfad fuer jede Major-Version. Ein UPGRADE.md im Bundle-Repository, das Breaking Changes explizit auflistet, spart konsumierenden Teams erheblichen Aufwand gegenueber dem muehsamen Durchsuchen von Commit-Historien. Diese Disziplin zahlt sich vor allem dann aus, wenn ein Bundle von mehreren Teams mit unterschiedlichem Symfony-Kenntnisstand genutzt wird.


# .gitlab-ci.yml — CI pipeline inside the shared bundle repository
stages: [test, release]

test:
  stage: test
  parallel:
    matrix:
      - SYMFONY_VERSION: ["6.4.*", "7.0.*", "7.1.*"]
  script:
    - composer require --no-update "symfony/framework-bundle:${SYMFONY_VERSION}"
    - composer update --prefer-stable
    - vendor/bin/phpunit
    - vendor/bin/phpstan analyse src --level=8

release:
  stage: release
  only: [tags]
  script:
    - echo "Tag ${CI_COMMIT_TAG} triggers Private Packagist sync automatically"

7. Zugriffsrechte und Auth-Tokens verwalten

Egal fuer welchen Verteilweg sich ein Team entscheidet, der Zugriff auf private Bundle-Repositories muss ueber Authentifizierung geregelt sein. Bei Private Packagist geschieht das ueber ein Organisations-Token, das in der globalen oder projektspezifischen auth.json von Composer hinterlegt wird, niemals direkt in der versionierten composer.json. Bei Satis oder direktem VCS-Zugriff kommt meist ein SSH-Deploy-Key oder ein Composer-spezifisches GitHub- beziehungsweise GitLab-Token zum Einsatz.

Ein haeufiger Sicherheitsfehler: Auth-Tokens landen versehentlich in einem Docker-Image oder in einem CI-Log, weil composer install ohne besondere Vorsicht in einem gebauten Image ausgefuehrt wird. Multi-Stage-Docker-Builds, bei denen composer install nur im Build-Stage laeuft und die auth.json nie in das finale Image gelangt, sind die uebliche Absicherung dagegen. In CI-Pipelines gehoert das Token immer in eine als geheim markierte Variable, niemals als Klartext in die Pipeline-Konfiguration.


// auth.json — never commit this file, keep it outside version control
{
  "http-basic": {
    "repo.packagist.com": {
      "username": "token",
      "password": "acme-corp-private-packagist-token"
    }
  },
  "github-oauth": {
    "github.com": "ghp_exampleTokenForDeployAccessOnly"
  }
}

8. Wann sich ein Monorepo stattdessen lohnt

Nicht jedes Team profitiert vom Aufwand eines eigenen Paket-Repositorys. Wenn alle Projekte, die ein Symfony Bundle nutzen, ohnehin im selben Repository liegen oder eng koordiniert deployt werden, kann ein Monorepo mit Composer Path-Repositories eine einfachere Alternative sein. Aenderungen am Bundle sind dann sofort in allen Anwendungen sichtbar, ohne Release-Zyklus, was die Entwicklungsgeschwindigkeit erhoeht, aber auch bedeutet, dass ein fehlerhafter Commit sofort alle Anwendungen betrifft.

Die Entscheidung zwischen Monorepo und separat verteiltem Bundle haengt vor allem davon ab, wie unabhaengig die konsumierenden Projekte voneinander deployt werden sollen. Projekte mit unterschiedlichen Release-Zyklen und unterschiedlichen Teams profitieren fast immer von einem echten, versionierten Paket-Repository, weil sie so selbst entscheiden koennen, wann sie ein Bundle-Update uebernehmen. Ein Monorepo kann zudem organisatorisch schwerer zu pflegen sein, sobald mehrere Teams mit unterschiedlichen Zugriffsrechten am selben Repository arbeiten muessen.

In der Praxis entscheiden sich viele Unternehmen fuer einen hybriden Ansatz: Bundles, die eng an ein einzelnes Produkt gekoppelt sind, bleiben im Monorepo dieses Produkts, waehrend echte, produktuebergreifende Bundles wie ein Audit-Log oder eine Zahlungsintegration ueber Private Packagist oder Satis verteilt werden. Diese Trennung vermeidet unnoetigen Verteil-Aufwand fuer Code, der ohnehin nur an einer Stelle gebraucht wird.

9. Private Packagist vs. Satis vs. VCS-Repository

Die folgende Tabelle fasst die wichtigsten Unterschiede der drei Verteilwege fuer geteilte Symfony Bundles zusammen.

Kriterium Private Packagist Satis Direktes VCS-Repository
Betriebsaufwand Keiner, gehosteter Dienst Eigener Build-Job und Hosting Keiner, nutzt bestehendes Git
Kosten Laufende Lizenzkosten Kostenlos, nur Hosting Kostenlos
Skalierung ab 10+ Bundles Sehr gut Gut, mit CI-Automatisierung Schlecht, jeder Eintrag manuell
Zusatzfunktionen Sicherheitsscans, Statistiken Keine, reines Repository Keine
Geeignet fuer Unternehmen mit vielen internen Paketen Teams mit eigener CI-Infrastruktur Ein bis zwei Bundles, schneller Start

Fuer die meisten Teams, die ein Symfony Bundle projektuebergreifend teilen wollen und bereits CI-Infrastruktur betreiben, ist Satis der pragmatische Mittelweg zwischen Kosten und Komfort. Private Packagist lohnt sich, sobald die Anzahl interner Bundles waechst und der Wartungsaufwand fuer ein selbst gehostetes Satis den Lizenzpreis uebersteigt.

Ein realistisches Entscheidungsraster: Bis zu drei interne Bundles rechtfertigen selten mehr als ein direktes VCS-Repository. Zwischen vier und etwa zwanzig Bundles zahlt sich ein selbst gehostetes Satis meist aus, weil die Betriebskosten gering bleiben. Ab zwanzig oder mehr Bundles, insbesondere ueber mehrere Teams hinweg, ueberwiegen die Vorteile von Private Packagist durch automatische Synchronisation und eingebaute Sicherheitswarnungen deutlich die laufenden Lizenzkosten.

Mironsoft

Symfony Bundle-Infrastruktur, Composer-Repositories und CI-Pipelines

Interne Bundles ohne zentrale Verteil-Strategie?

Wir richten Private Packagist oder ein selbst gehostetes Satis fuer eure Symfony Bundles ein, inklusive CI-Pipeline mit Matrix-Tests gegen mehrere Symfony-Versionen und sicherer Token-Verwaltung.

Repository-Setup

Private Packagist, Satis oder VCS je nach Anzahl und Sensibilitaet eurer Bundles

CI-Pipeline-Design

Matrix-Tests, PHPStan und automatisierte Releases fuer geteilte Bundles

Sicherheit

Auth-Token-Verwaltung und Multi-Stage-Docker-Builds ohne Leck-Risiko

10. Zusammenfassung

Ein Symfony Bundle ueber mehrere Projekte hinweg zu teilen, braucht mehr als nur ein Composer-Paket, es braucht einen zentralen, versionierten Verteilweg. Private Packagist ist die pflegeleichteste Option ohne eigene Infrastruktur, Satis der kostenlose Mittelweg mit eigenem Build-Job, und direkte VCS-Repositories der schnellste Einstieg fuer wenige Bundles. Alle drei Wege nutzen echte Git-Tags als Versionsnummern und funktionieren nahtlos mit composer update.

Unabhaengig vom gewaehlten Weg braucht ein geteiltes Bundle eine eigene CI-Pipeline mit Matrix-Tests gegen mehrere Symfony-Versionen, damit Breaking Changes vor dem Release auffallen statt erst in einem konsumierenden Projekt. Saubere Verwaltung von Auth-Tokens ausserhalb der versionierten composer.json rundet ein sicheres Setup ab. Wer diese Grundlagen beachtet, kann ein Symfony Bundle projektuebergreifend teilen, ohne dass Versionschaos oder Sicherheitsluecken entstehen.

Symfony Bundles projektübergreifend teilen — Das Wichtigste auf einen Blick

Private Packagist

Gehosteter Dienst ohne eigenen Betrieb, automatische Synchronisation neuer Tags.

Satis

Kostenloses, selbst gehostetes Repository, braucht eigenen Build-Job per CI oder Cron.

CI-Absicherung

Matrix-Tests gegen mehrere Symfony-Versionen im Bundle-Repository selbst.

Sicherheit

Auth-Tokens nur in auth.json oder geheimen CI-Variablen, nie in versionierter composer.json.

11. FAQ: Symfony Bundles projektübergreifend teilen

1Muss ein internes Bundle auf Packagist.org?
Nein, interne Bundles bleiben privat und werden ueber Private Packagist, Satis oder VCS verteilt.
2Private Packagist vs. Satis?
Private Packagist ist gehostet und automatisch, Satis ist kostenlos aber selbst zu betreiben und neu zu bauen.
3Wie erkennt Composer neue Versionen?
Ueber Git-Tags im Bundle-Repository, die semantischer Versionierung folgen.
4Wo gehoert ein Auth-Token hin?
In die auth.json von Composer oder eine geheime CI-Variable, nie in die versionierte composer.json.
5Wie oft Satis neu bauen?
Bei jedem neuen Git-Tag im Bundle-Repository, ueblicherweise per CI-Job ausgeloest.
6Wann Path-Repositories statt Paketserver?
Waehrend lokaler Entwicklung oder in echten Monorepo-Setups mit gemeinsamem Deploy.
7Token nicht ins Docker-Image?
Multi-Stage-Docker-Builds, composer install nur im Build-Stage, finales Image ohne Zugangsdaten.
8Skaliert VCS-Repository fuer viele Bundles?
Schlecht, jedes Ziel-Projekt muss jeden Eintrag manuell pflegen, unuebersichtlich ab etwa zehn Bundles.
9Braucht ein geteiltes Bundle eigene CI?
Ja, mit Matrix-Tests gegen mehrere Symfony-Versionen, um Breaking Changes fruehzeitig zu erkennen.
10Wechsel von VCS zu Private Packagist?
Nur der repositories-Block in composer.json wird ausgetauscht, require-Zeilen bleiben gleich.