Das Örtchen RSS-Feed
Kategorie
Kategorie: Blog
Buttons & Statistiken
Neueste Kommentare

PHP: Composer und die Sache mit den Abhängigkeiten

Im Rahmen der Entwicklung meines eigenen Micro Frameworks MoreGlue stand ich gestern vor einem Problem, welches mir bis heute Kopfschmerzen bereitete. Für das Framework benötige ich einige Komponenten von Dritten, denn man will ja schließlich nicht immer das Rad neu erfinden und setzt lieber auf erprobte Bauteile. Um diese Bauteile verwalten zu können (z.B. Installation und Updates), verwende ich den Abhängigkeitsmanager Composer.

Abhängigkeiten von Abhängigkeiten

In meiner Anwendung definierte ich unter anderem mein Framework MoreGlue als Abhängigkeit. In diesem auf Packagist verfügbaren Paket, habe ich dann wiederum weitere Pakete definiert, welche das Framework benötigt (siehe composer.json). Nun ergab sich während der Entwicklung das Problem, daß sich die Abhängigkeiten in der eigentlichen Anwendung, im Framework und in einer weiteren Abhängigkeit widersprachen bzw. nicht auflösen ließen. Doch wie konnte dies passieren?

Einführung in die Composer-Versionsangaben

Gehen wir zunächst einmal die einfachsten Möglichkeiten durch, wie man bei Composer die Auswahl der gewünschten Version beschränken kann:

  1. "2.2.2"
    In diesem Fall haben wir die genaue Version 2.2.2 eines Pakets angegeben und erlaubt Composer keine Abweichung.
  2. "~2.2.2"
    Hier sagen wir Composer, daß wir eine Version ab 2.2.2 wünschen und hierbei einen höheren Patch-Level (letzte Angabe) erlauben. Ein Wechsel zum Minor-Release 2.3.x ist jedoch nicht möglich.
  3. "2.2.*"
    Alle Version inklusive 2.2.0 sind möglich, sofern sich lediglich der Patch-Level ändert.
  4. ">=2.2.2"
    Hier wünschen wir eine Version ab 2.2.2 und nehmen keine weiteren Einschränkungen vor. Auch der Sprung auf 2.3.0 (Minor) oder gar 3.0.0 (Major) sind möglich.

Soweit ist alles ziemlich einleuchtend und nicht weiter problematisch.

Komplexere Versionseinschränkungen

Ursprünglich hatte ich in der Abhängigkeit von der Abhängigkeit Variante (1) benutzt und zwingend Version "2.2.2" des Pakets "doctrine/orm" verlangt, da ich mein Paket genau mit dieser Version getestet hatte. Da Abweichungen im Patch-Level normalerweise relativ unkritisch sind und keine gravierenden API-Änderungen stattfinden, habe ich später die Angabe in Variante (2) geändert. Auf Variante (3) habe ich bewusst verzichtet, da die Versionen 2.2.0 und 2.2.1 ggf. fehlerbehaftet waren und ich dies nicht riskieren wollte.

Version "2.3.3" ist der aktuellste stable Release vom Paket "doctrine/orm" und in meinem Framework hinterlegte ich deswegen als Abhängigkeit die Versionsangabe ">=2.3.3", man will ja schließlich was aktuelles nutzen. Beim nächsten Update krachte es natürlich, da die Abhängigkeit nur 2.2er und das Framework 2.3er Versionen erlaubt und es hierbei keine Schnittmenge gibt.

Zunächst überlegte ich, wie ich dieses Problem lösen konnte. Hierfür löschte ich "doctrine/orm" als Abhängigkeit aus dem Framework. Es reicht in diesem Fall, wenn diese Abhängigkeit lediglich in der Abhängigkeit hinterlegt ist. Im gleichen Schritt verlagerte ich alle sonstigen Abhängigkeiten in die composer.json des Frameworks und das war ein größeres Problem.

Im Folgenden möchte ich nur den aktuellen Stand präsentieren, da ich dummerweise den relevanten Blog-Artikel mit einem ausführlichen Beispiel erst heute entdeckt habe und zwischendurch etliches probiert habe.

Anwendung - composer.json:

 {
    "require":{
        "php": ">=5.3.7",
        "doctrine/doctrine-bundle": "@beta",
        "doctrine/migrations": "dev-master#e1f6efc@dev",
        "doctrine/data-fixtures": "@alpha",
        "interiete/moreglue": "*@alpha"
    }
} 

Mit einem Stern überlasse ich Composer die freie Versionsauswahl. Da mein Framework MoreGlue sonst nirgends als Abhängigkeit auftauchen wird, sollte hierbei immer die aktuellste Version ausgewählt werden.

Mit der Angabe @alpha erlaube ich ausnahmsweise Alpha-Versionen, also auch eine frühe Enwicklungsversion wie beispielsweise "0.1-ALPHA4". Mit der Angabe hinter dem @-Zeichen kann ich also auch nicht unbedingt stabile Versionen erlauben. Folgende Angaben sind möglich:

  1. dev
  2. alpha
  3. beta
  4. RC
  5. stable

Variante (5) ist der stabile Standard und wird deswegen nicht angegeben. Die Varianten eins bis vier sollte man normalerweise im produktiven Umfeld vermeiden, was jedoch nicht immer möglich ist (dummerweise gibt es hier keine stabileren Versionen).

Framework - composer.json

 {
    "require": {
        "php": ">=5.3.7",
        "fuelphp/alias": "~0.1.2",
        "symfony/http-foundation": "~2.2.0",
        "symfony/routing": "~2.2.0",
        "symfony/http-kernel": "~2.2.0",
        "mnapoli/php-di": "~2.1.0",
        "monolog/monolog": "~1.4.0",
        "webmasters/doctrine-extensions": "~2.3.5",
        "doctrine/doctrine-bundle": "*",
        "doctrine/migrations": "*",
        "doctrine/data-fixtures": "*",
        "Respect/Validation": "~0.4.4",
        "ircmaxell/password-compat": "~1.0.0",
        "twig/twig": "~1.12.2",
        "symfony/twig-bridge": "~2.2.0"
    }
} 

Ursprünglich hatte ich alle Abhängigkeiten außer dem Framework aus der Anwendung gekickt. Dies musste ich jedoch teilweise rückgängig machen, da Angaben zur Stabilität nur in Anwendung und NICHT in der composer.json einer Abhängigkeit möglich sind.

  1. Es reicht in der Anwendung lediglich die Stabilität (also "@alpha" oder "@beta") ohne sonstige Angaben zu notieren.
  2. Im Framework habe ich als Version dann "*" notiert. Composer soll hier einfach das aktuellste liefern, was möglich ist.
  3. Die Angabe "dev-master" ist ein Entwicklungszweig (Stichwort Versionsverwaltung Git). Diesen nutzt man ebenso wie die Stabilitätsangabe @dev nur, wenn man dringend einen aktuellen Bugfix benötigt.
  4. Die Angabe #e1f6efc ist eine interne Versionsangabe von Git und dient zur genauen Einschränkung des Entwicklungszweiges dev-master.

Die composer.json der Abhängigkeit

 {
    "require": {
        "php": ">=5.3.2",
        "doctrine/orm": ">=2.2.2,<2.4",
        "gedmo/doctrine-extensions": "~2.3.2"
    }
} 

Hier gibt es nur eine einzige Besonderheit, nämlich die Angabe ">=2.2.2,<2.4". Diese Angabe war nötig, da von "doctrine/common" bereits RC1 der 2.4er Version erschienen ist und ich erst Tests mit der stabilen Version machen möchte, bevor ich mein Paket hierfür freigebe.

Package not found und das Thema minimum-stability

Wenn man diese Composer-Meldung das erste mal sieht, rät einem die Hilfe zum Herabsetzen der minimalen Stabiltätsangabe in der composer.json. Diese Möglichkeit hat man wie alle anderen Angaben zur Stabilität NUR in der composer.json der Anwendung und NICHT in der composer.json der Abhängigkeiten! Allerdings brockt man sich damit massig Probleme ein, da diese Angabe für alle Abhängigkeiten gilt! Für eine genauere Erklärung des Problems rate ich jedem, sich dieses Beispiel für die Composer Stability Flags zu Gemüte zu führen.

Fazit

Ich hoffe, daß einige Leser durch diesen Artikel und den Beispiel-Link massive Kopfschmerzen vermeiden können. Dummerweise habe ich das Beispiel erst heute gefunden und die Angabe root-only irgendwie die ganze Zeit gekonnt ignoriert.

Hallo! Bist du neu hier? Dann abonniere doch den RSS-Feed dieses nicht mehr ganz so stillen Örtchens, um über meine geistigen Ergüsse auf dem Laufenden zu bleiben. Alternativ besteht auch die Möglichkeit, sich von FeedBurner per E-Mail über meine Ausscheidungen benachrichtigen zu lassen.

Kommentare

Hallo Jan,

über Symfony bin ich nun auch schon einige Zeit beim composer hängen geblieben und obwohl ich ihn als eine wirkliche Erleichterung empfinde grübelt man immer wieder vor seiner composer.json und versucht Abhängigkeitsprobleme zu umgehen. Immer wieder stoße ich auf Bundles welche die Abhängigkeiten nicht automatisch auflösen können, wegen der angegebenen Versionsstände. Ich umgehe diese Probleme hautsächlich damit, das ich die Abhängigkeit innerhalb meiner eigenen composer.json nachtrage.

@Michael: Symfony-Bundles sind sowieso noch einmal eine Sache für sich, da sie ja die Abhängigkeitskette um ein Glied erweitern. Da kann man nur hoffen, daß der Maintainer schnell auf neue Versionen reagiert oder man muss halt notfalls selbst Hand anlegen.

Neuen Kommentar schreiben

Der Inhalt dieses Feldes wird nicht öffentlich zugänglich angezeigt.
Der Inhalt dieses Feldes wird öffentlich zugänglich angezeigt, aber als rel="nofollow" markiert.
Hinweis

Kommentare beleben den Blog! Ich freue mich über jeden Kommentar. Du kannst hier offen Deine Meinung zum Artikel sagen, aber bitte beachte die Netiquette und vermeide es andere zu beleidigen.

Bitte unterlasst es die Kommentare zu SEO-Zwecken zu missbrauchen. Kommentare mit Links, die nicht zu Blogs führen (oder zu Blogs mit Grauzonen-Themen) und/oder Keywords als Namen verwenden, sind nicht erwünscht!

Möchtest Du mir einen Blog-Artikel schmackhaft machen, dann schreib die URL ohne HTML-Tag in den Kommentarbereich und ich werde diesen bei Gefallen verlinken.