Türchen 02: Composer für Magento

Als ich vor ein paar Monaten von composer erfuhr, war ich überrascht das ich nicht schon früher darauf gestoßen bin – die PHP Welt entwickelt sich derzeit schnell weiter, und ich bin so sehr auf Magento fokussiert sodass ich manche Sachen verpasse. Um so schöner composer jetzt kennen zu lernen :)

Über Composer

Falls der Fall bei Dir ähnlich gelagert ist und du composer noch nicht wirklich kennst, hier ein kurzer Überblick:

composer ist ein Dependency Manager für PHP Bibliotheken. Aber das war doch schon PEAR? Das Hauptproblem bei PEAR ist das Pakete systemweit installiert werden. In der Praxis benötigen aber Projekte meistens bestimmte Bibliothek-Versionen. Composer installiert deswegen alle Bibliotheken für jedes Projekt getrennt. Konkret, composer installiert Pakete in einem Verzeichnis namens vendor/. Ausserdem erstellt es eine vendor/autoload.php Datei, welche die Konfiguration des PHP autoloading für alle Bibliotheken übernimmt. Will man also in dem Projekt Bibliotheken verwenden, muss man nur die vendor/autoload.php Datei einbinden und kann sofort losprogrammieren.

Pakete, die von composer installiert werden sollen, werden in eine kleine Konfigurations-Datei namens composer.json eingetragen. Dabei bekommt jedes Paket eine Version zugewiesen (der * steht für die aktuellste Version). Die genaue Syntax sprengt den Rahmen dieses Artikels und kann in der Dokumentation nachgelesen werden.

Bevor wir uns Magento zuwenden, noch ein bisschen Hintergrund zu Installations-Quellen.
Im Gegensatz zu PEAR kann composer mit verschiedenen Quellen für Pakete umgehen. Das können unter anderem github repositories, git repositories, ZIP File URL’s, SVN Server oder auch PEAR Channel sein. Alles was benötigt wird, damit ein Paket installiert werden kann, ist eine Konfigurations-Datei namens composer.json (ja, genau wie die oben genannte Datei mit der Liste der zu installierenden Pakete).

Alle öffentlich verfügbaren, per compsoser installierbaren Pakete sind auf http://packagist.org gelistet. Magento Module haben ihr eigenes Repository http://packages.firegento.com (mehr dazu später). Normalerweise interessiert es also gar nicht, woher ein Paket installiert wird. Alles was man machen muss, ist den Paket-Namen und die Version in der composer.json anzugeben:

{
    "minimum-stability":"dev",
    "require":{
        "phpunit/phpunit":"3.7.9",
        "n98/magerun":"*",
        "twig/twig":"v1.11.2"
    }
}

Nach dem Aufruf von php composer.phar install sind all diese Pakete installiert und verwendungsbereit.

Zurück zu Magento

Um Unterschied zu „üblichen“ PHP Bibliotheken haben Magento Module die Besonderheit, dass enthaltene Dateien nicht in einem Verzeichnis gesammelt sind, sondern an verschiedenen Stellen in Magento liegen müssen – je nach Verwendungszweck. Um dieses Problem zu lösen hat sich unter Magento Entwicklern das Tool modman eingebürgert. Wer das nicht kennt, sollte sofort das Adventskalender-Türchen Nummer 8 aus 2011 von Fabrizio Branca zu dem Thema lesen.

Bei dem Magento Hackathon in München erstellte eines der Teams eine composer-Erweiterung, welche auch Magento Module per composer installierbar macht. Dazu werden bei der Installation eines Magento Moduls entsprechend einer modman Datei Symlinks aus dem vendor/ Verzeichnis in die Magento erstellt. Alternativ kann auch das linking in der composer.json des Moduls konfiguriert werden.

Damit also ein Magento Modul per composer zu installieren ist, muss
1) eine composer.json vorhanden sein
2) das Einhaken der Modul-Dateien per modman oder in der composer.json konfiguriert sein.

Hier ein Beispiel für eine composer.json eines Magento Moduls:

{
    "name":"netzarbeiter/customer-activation",
    "type":"magento-module",
    "license":"OSL-3.0",
    "homepage":"https://github.com/Vinai/customer-activation",
    "description":"Makes it impossible for a customer to log in until the account has been activated by the administrator.",
    "authors":[
        {
            "name":"Vinai Kopp",
            "email":"vinai@netzarbeiter.com"
        }
    ],
    "require":{
        "magento-hackathon/magento-composer-installer":"*"
    }
}

Der Eintrag "type":"magento-module" sorgt dafür, dass composer den Magento Modul-Installer zum installieren benutzt anstatt des regulären composer Installers. Deswegen muss auch die Abhängigkeit zum magento-composer-installer unter "require" eingetragen werden.

Hier ein Beispiel für eine composer.json Datei eines Projektes, in dem unter anderem einige Magento Module gelistet sind.

{
    "minimum-stability":"dev",
    "require":{
        "fbrnc/aoe_templatehints":"*",
        "netzarbeiter/customer-activation":"*",
        "riconeitzel/vertical-navigation":"v0.4.2",
        "colinmollenhour/cache-backend-file":"*",
    },
    "repositories":[
        {
            "type":"composer",
            "url":"http://packages.firegento.com"
        }
    ],
    "extra":{
        "magento-root-dir":"./htdocs/"
    }
}

Wenn jetzt composer.phar install aufgerufen wird, landet das z.B. Modul Aoe_TemplateHints im Verzeichnis vendor/fbrnc/Aoe_TemplateHints.
Außerdem werden alle Symlinks entsprechend der modman Datei nach app/code/local/Aoe/TemplateHints/ erstellt.

Wie bereits erwähnt, kann anstatt einer modman Datei das Verlinken nach Magento auch in der composer.json des Moduls angegeben werden:

{
    "name": "fbrnc/Aoe_TemplateHints",
    "license": "OSL-3.0",
    "type": "magento-module",
    "description": "Advanced Template Hints for Magento",
    "homepage": "http://www.fabrizio-branca.de/magento-advanced-template-hints-20.html",
    "require": {
        "magento-hackathon/magento-composer-installer": "*"
    },
    "authors":[
        {
            "name":"Fabrizio Branca",
            "email":"mail@{firstname}-{lastname}.de"
        }
    ],
    "extra":{
        "map": [
            ["app/etc/modules/Aoe_TemplateHints.xml", "app/etc/modules/Aoe_TemplateHints.xml"],
            ["app/code/local/Aoe/TemplateHints/", "app/code/local/Aoe/TemplateHints/"],
            ["skin/frontend/base/default/aoe_templatehints", "skin/frontend/base/default/aoe_templatehints"]
        ]
    }
}

Magento Modul Repository

Wie bereits erwähnt haben Magento Module ihr eigenes Repository, denn entsprechend den composer Richtlinien sollen Erweiterungen für Applikationen mit eigenem Eco-System (zb Wordpress) nicht auf packagist.org gelistet werden. Anstatt dessen sollen diese in einem eigenen Repository geführt werden. Deswegen wurde composer–installierbare Magento Module http://packages.firegento.org initiiert.

Damit Pakete von dort installiert werden können müssen die folgenden Zeilen in die Projekt composer.json eingetragen werden:

"repositories":[
        {
            "type":"composer",
            "url":"http://packages.firegento.com"
        }
    ]

Damit wird bei einem composer.phar install zuerst auf packages.firegento.com gesucht, und erst danach, sollte ein Packet nicht gefunden worden sein, auf packagist.org.
Eigene Magento Module können der packagist.firegento.com einfach und schnell hinzugefügt werden. Dazu sind die folgenden Schritte notwendig.
1.) Hinzufügen einer composer.json
2.) Magento repository auf gitub clonen
3.) Eigenes Modul in die satis.json eintragen
4.) Pull request machen

Danach wird das Modul auch per composer installierbar sein.

Man muss nicht unbedingt nur externe Repositories nutzen – composer unterstützt auch die Installation von privaten Quellen, aber das sprengt den Rahmen dieses Adventskalender-Türchens.

Versionsverwaltung und composer

Bei der Verzeichnis-Struktur für Projekte scheiden sich die Geister – jeder Entwickler und jede Agentur hat ihre eigenen Richtlinien. Da composer Packete in das vendor/ Verzeichnis installiert, muss dieses irgendwo eingeordnet werden. Im Prinzip kann das vendor/ Verzeichnis direkt in dem Magento Root-Verzeichnis liegen:

htdocs
├── .git
├── composer.json
├── composer.lock
├── index.php
├── app
├── js
├── lib
├── media
├── skin
├── var
└── vendor

In dem Fall muss das vendor/ Verzeichnis mit allen Inhalten durch eine .htaccess Datei geschützt werden.

Besser ist jedoch eine Ebene höher anzusetzen, zum Beispiel wie folgt:

├── .git
├── composer.json
├── composer.lock
├── htdocs
│   ├── index.php
│   ├── app
│   ├── includes
│   ├── js
│   ├── lib
│   ├── media
│   ├── shell
│   ├── skin
│   └── var
└── vendor

Wird das ganze Projekt mit einem Versions-Controll-System wie z.B. git verwaltet, wird das vendor/ Verzeichnis üblicherweise nicht mit in das Projekt Repository aufgenommen. Anstatt dessen wird die composer.json und die composer.lock Datei hinzugefügt. Letztere wird durch composer bei der installation angelegt, und enthält immer alle aktuell installierten composer Pakete mit der jeweiligen Version.

Wird compser.phar install in einem Projekt ohne vendor/ Verzeichnis, aber mit composer.lock Datei, aufgerufen, wird der Status aus der lock Datei wieder hergestellt. Im konkreten Fall muss jeder natürlich selber entscheiden welches Vorgehen für ihn am meisten Sinn macht.

Ausblick

Beim nächsten Magento Hackathon in Januar in Berlin ist geplant, Module auch direkt von Magento Connect via composer installierbar zu machen.

Screencast

Um das ganze zu illustrieren habe ich zwei kleine Screencasts aufgenommen:

Magento Composer Installer Howto

Adding Extensions to the Magento Module Repository

Viel Spaß! UPDATE


Ein Beitrag von Vinai Kopp
Vinai's avatar

Vinai Kopp arbeitet seit Oktober 2011 als Manager of Developer Education für Magento Inc. Vorher war er als freier Magento Entwickler und Berater tätig, mit dem Schwerpunkt Entwicklerschulung. Desweiteren ist er Co-Autor des Magento Entwicklerhandbuchs, erschienen im O'reilly Verlag.

Alle Beiträge von Vinai

Kommentare
Türchen 18: Von GermanSetup zu MageSetup « Magento Blog für Entwickler und eCommerce-Shops - webguys.de Magento Blog für Entwickler und eCommerce-Shops – webguys.de am

[…] Composer kann das Modul über den Namen “firegento/magesetup” integriert werden, sofern das […]

n98-magerun Modulsystem - Einfach Kommandos registrieren und mit anderen teilen | Blog von Christian Münch am

[...] auch ganz normal über z.B. modman registriert werden. Auch die Installation über Composer mit dem Magento-Composer-Installer ist damit [...]

Türchen 05: Magento Connect Pakete in der Shell bauen « Magento Blog für Entwickler und eCommerce-Shops – webguys.de am

[...] Türchen 02: Composer für Magento [...]

Flyingmana am

Freut mich, dass Composer so gut ankommt bei vielen. Werde auch beim hackathon in Berlin sein und bin schon gespannt auf deine Ideen Tobi und werde gerne wieder bei der Umsetzung mit helfen.

Vinai Kopp am

Hi Tobi - ich freue mich schon auf Januar! Am besten du machst gleich ein paar Issues draus (https://github.com/magento-hackathon/magento-composer-installer/issues).

Sebastian Müller am

Vielen Dank für das schöne Türchen! ;)

Tobias Vogt am

Hey Vinai,

danke das du wieder dieses Jahr dabei warst und tolles Projekt. Ich hab im produktiven Alltag jedoch einige Probleme/ Ideen identifiziert die wir in Berlin noch gemeinsam lösen könnten :-)

Eventuell mache ich dann dort mal einen kleinen Kickoff!

Liebe Grüße

Tobi

P.S. Die Videos hab ich gerade repariert!

Vinai Kopp am

@Simon: das muss in die Projekt composer.json. In den Package composer.json wird ein repositories Eintrag eh ignoriert (siehe http://getcomposer.org/doc/04-schema.md#repositories (Root Only))

Simon am

Danke für den schönen Artikel, Vinai! "Damit Pakete von dort installiert werden können müssen die folgenden Zeilen in die Projekt composer.json eingetragen werden:"


"repositories":[
    {
        "type":"composer",
        "url":"http://packages.firegento.com"
    }
]

Muss das wirklich so sein? Wenn ich mir die composer.json Dateien der auf http://packages.firegento.com/ gelisteten Extensions so anschaue, hat das keiner...

Matthias Zeis am

Danke, Vinai. Dann müssen wir uns alle ranhalten, unsere Releases auch anständig zu taggen. Sollte man sowieso machen und das ist dann eine gute Motivation. ;-)

Vinai Kopp am

Gute Frage Matthias. Der composer bekommt die Paket Versionen meistens aus annotated git tags. Sie müssen das Format n[.n]* (z.B. 1.2.4.2) haben, optional auch mit einem vorangestelltem v (z.B. v3.1). Ausserdem wird jeder git branch als version mit vorangestelltem "dev-" gewertet, so ist z.B. "dev-master" der master branch, "dev-test" wäre ein test branch. Versionen , und auch Aliase, können auch in die composer.json eingetragen werden. Mehr Infos hier: http://getcomposer.org/doc/02-libraries.md#specifying-the-version

Weitere Infos, wie die zu installierenden Version spezifiziert werden kann, sind hier zu finden: http://getcomposer.org/doc/01-basic-usage.md#package-versions

Cyrill Schumacher am

Sehr interessant! Vielleicht koennen wir damit Maven abloesen ...

Matthias Zeis am

Hi Vinai, danke auch von mir! Woher bezieht Composer die Magento-Modul-Versionsnummern? Aus den git-Tags?

Fabian Blechschmidt am

Wie geil, danke Vinai! Großartige Erklärung und ich hoffe, dass ich zeitnah dazu komme endlich meine Extension mit einer composer.json auszustatten :)

Danke für die ausführliche Erklärung!

Dein Kommentar