Tuto : Installer Composer sur un projet web pour gérer facilement les libraires externes (et internes) de ton framework

Installer composer sur ton poste / serveur

Ton poste doit bien sûr avoir un serveur web qui tourne avec PHP.

Site officiel de Composer : getcomposer.org/download/

Si tu es sous Windows, je te recommande de l’installer via leur « Windows Installer », permettant d’éxécuter composer sur n’importe quel dossier de ton poste, juste en tapant « composer », car il aura correctement intialisé le PATH

Sur un autre OS, le plus simple c’est d’ouvrir une console positionnée dans le répertoire de projet et de taper :

curl -sS https://getcomposer.org/installer | php --filename="composer.phar"

Dans ce cas, il faudra taper « php composer.phar » au lieu de simplement « composer » pour le tuto qui va suivre.

Configuration de composer dans ton projet

Si tu as déja composer installé, vérifie qu’il est bien à jour :

composer self-update

Ensuite, créé un fichier composer.json à la racine de ton projet, comme celui-là :

{
    "name": "My project",
    "version": "1.0.0",
    "description": "",
    "homepage": "http://thomas.bondois.info",
    "license": "proprietary",
    "config": {
        "vendor-dir": "vendor",
        "bin-dir": "bin/vendor",
        "component-dir": "web/component/vendor",
        "optimize-autoloader": true,
        "preferred-install": "source"
    },
    "minimum-stability": "dev",
    "prefer-stable": true,
    "require": {
        "php": "~5.5",
        "ext-xml": "*",
        "ext-dom": "*",
        "ext-SimpleXML": "*",
        "ext-date": "*",
        "ext-json": "*",
        "ext-PDO": "*",
        "ext-pdo_mysql": "*",
        "ext-Reflection": "*",
        "ext-SPL": "*",
        "ext-zip": "*",
        "ext-ftp": "*",
        "ext-soap": "*",
        "lib-curl": "*",
        "psr/log": "1.*",
        "psr/http-message": "1.*"
    },
    "require-dev": {
    },
    "autoload": {
        "psr-4": {
        }
    },
    "autoload-dev": {
        "psr-4": {
        }
    }
}

Dans cette configuration d’exemple, voici la structure de dossier de mon framework (c’est d’ailleurs la structure qu’on retrouve souvent dans les frameworks PHP modernes, comme Symfony 3 ou Magento 2) ;

bin/ # droits d'éxécution par le système : scripts à éxécuter en lignes de commandes
    vendor/ # scripts des librairies importées par composer
src/ # librairies internes du projet
tests/ # librairies internes du projet liées aux tests unitaires / de développement
var/  # droits d'écriture par le système, dossier non versionné par Git.
    cache/
    logs/
vendor/ # librairies importées par composer
web/ #droits de lecture/execution sur serveur http sur ce dossier, virtual host pointant directement ici
    component/ # ressources web
        vendor/ # ressources web importées par composer
    index.php
composer.json
.gitignore

Un point sur ce contenu :
– Dans cet exemple, j’inclue les packages PSR de logging (PSR-3) et de réponses HTTP (PSR-7). Il s’agit de classes-interfaces qui n’auront aucun impact sur ton projet. Et en plus, il y aura un lien avec un de mes prochains tutos qui devrait porter sur les loggers, héhé.

– Pense à adapter les valeurs des premières lignes (nom, version l’application etc) pour qu’elles collent à ton projet. Par ailleurs je crois qu’aucun des champs n’est requis, si tu veux faire le ménage.

– Dans l’exemple, mon projet PHP contient toutes les libraires dans un répertoire /src/ à partir de la racine du projet (c’est devenu une norme), sauf les librairies de tests unitaires dans un dossier /tests/ à la racine (encore une norme), et les binaires dans un répertoire /bin/ (comme Magento 2 et Symfony 3).
Je pourrais mettre les librairies de Composer dans « src/vendor », mais je préfère les laisser dans le dossier par défaut « vendor/ » (explications à la fin), et par contre déplacer les binaires dans « bin/vendor » et les composants dans « web/component/vendor ».

– J’utilise aussi les alias de Packagist pour indiquer que mon projet nécessite certaines extensions PHP. Enlève-les du « require » (les lignes commencant par « ext- » ou « lib-« ) si tu préfères. Tu peux contrôler comme ca les extensions nécéssaires a ton projet via « ext- » + le nom de l’extension (aide-toi avec un phpinfo()), ou « lib- » pour une petite minorité dont la version peut aussi être gérée.
– Tu peux voir un exemple de fichiers .gitignore permettant d’exclure les fichiers générés par Composer (qui devraient être considéré comme du cache, du point de vue du versioning) dans un autre de mes articles.

– Revenons également sur ce package :

     "require": {
        "php": "~5.4"
    }

– Tu noteras le signe « ~ » préfixant certaines version : dans Composer il indique qu’il va prendre la dernière version (stable) en 5.x, mais jamais au delà de la version 5 (pas de PHP 6, 7 etc). Si j’avais mis « ~5.4.3 », il aurait cherché la dernière version en 5.4.* (au dessous de 5.4.3) mais jamais là 5.5.0.
Pratique, et contrairement à la notation « 5.* », ça permet de fixer un numéro de sous-version minimum et d’avoir une idée de la dernière version installée et fonctionnelle.
Un autre opérateur intéressant est « ^ », qui va juste restreindre les mises à jour sur le numéro de version majeur.
Plus d’info sur le format des version et les opérateurs-joker (>, =, cette page la doc officielle.

Avec ce package « php », Composer va donc jeter quelqu’un qui fait install / update si son PHP est différent de la version 5, ou en dessous de la version 5.4.0. Pratique mais attention car ce faux-package a (avait ?) parfois la fâcheuse tendance à rajouter plein de librairies complètement inutiles (ex : du doctrine alors que le projet ne l’utilise pas), et on peut parfois préférer faire les tests dans les pages PHP plutôt qu’à l’installation des librairies.

Installer d’autres librairies

Le repository officiel de composer est Packagist.org, donc beaucoup de librairies open-sources sont indexées sur ce site. Pour en rajouter une à ton composer.json, utilise la recherche pour trouver ton bonheur et tape la commande indiquée sur la page du package. Souvent, un repository composer se base lui-même sur un repository GitHub.

Exemple avec Monolog :

On voit sur la page Packagist du projet que pour inclure la dernière version stable (je te déconseille de prendre des version étiquetées comme -dev ou -alpha) tape cette ligne de commander :

composer require 'monolog/monolog:1.13.1'

Ou autre manière de faire : modifie ton fichier composer.json et rajoute dans require :

      "monolog/monolog": "~1.13"

En faisant attention à rajouter une virgule sur la ligne d’avant (le format JSON est très strict, pas de virgules superflues non plus)

Puis tape :

composer update

Ce qui fera un update de toutes les librairies incluses.

Une parenthèse sur sur la configuration pour environnement de production :

Il existe deux instructions, « require-dev » et « autoload-dev », qui servent à inclure des librairies qui ne serviront qu’en environnement de développement. Ca peut être le cas de librairies de Debugging, ou de tests unitaires par exemple :

    "require-dev": {
        "phpunit/phpunit": "~4.7",
        "mockery/mockery": "~0.9"
},

Ainsi en environnement de production, pour ne pas les inclure, il faut rajouter l’option suivante :

composer install --no-dev
composer update --no-dev

Pour en savoir plus sur composer, je t’invites vivement à consulter la doc officielle.

Initialisation du projet

Une fois que tout cela est bon, tape :

composer install

Tu devrais voir ca :

$ composer install
launching C:\ProgramData\ComposerSetup\bin\composer
Loading composer repositories with package information
Installing dependencies (including require-dev)
  - Installing psr/log (1.0.0)
    Cloning fe0936ee26643249e916849d48e3a51d5f5e278b

Writing lock file
Generating optimized autoload files

Interaction avec Git

Un exemple du .gitignore qui pourrait être à la racine de ton projet :

/var/
# composer php archive
/composer
/composer.phar
# all composer vendor folders in all hierarchy
vendor/

### Fichiers de workspace générés par des IDE
# PhpStorm
/.idea/
/.idea_modules/
# NetBeans
/nbproject/
# Eclipse & ZendStudio
/.buildpath
/.cache
/.metadata
/.project
/.settings
# Others
/atlassian*
/sitemap
# backup files
~* # some temp files begins by ~
*.bk 
*.bak

### Fichiers générés par les OS
# Windows folders cache
desktop.ini
Desktop.ini
Thumbs.db
# Windows shortcuts
*.lnk
# Recycle Bin used on file shares
$RECYCLE.BIN/
# MacOS
.DS_Store

En effet inutile de versionner les librairies installées par Composer, qu’il faut conidérer comme du cache et ne pas modifier directement.

Par contre bien sûr il faut versionner le composer.json, et il est aussi fortement recommandé de versionner le fichier composer.lock. C’est un checksum de ce qui a été installé. Ceci permettra aux gens qui récupèrent le projet de ne pas aller plus loin dans les version de librairies que toi-même l’as fait au moment de l’installation. A moins de faire un « composer update », et donc d’assumer les bus potentiels de montée de version.

Prendre en compte les librairies installées par Composer dans ton projet

Rajouter simplement cette ligne à l’endroit ou typiquement tu inclurais l’appel à l’enregistrement d’un autoloader :

require_once 'vendor/autoload.php'

Pour savoir comment instancier les classes qui sont dans vendor, regarde le fichier vendor/composer/autoload_classmap.php. Les indexes de ce tableau sont les namespace à utiliser.
Il est tout à fait possible d’utiliser composer avec des librairies qui n’utilisent pas les namespace.php : dans ce cas, elles sont appelées sans namespace. Ça laisse des traces de pneus, mais ça fonctionne.

Bonus : Utiliser l’autoloader de Composer pour tes propres librairies

Tu peux profiter de Composer pour qu’il s’occupe aussi de charger tes propres librairies. Tu centraliseras ainsi l’autoloader, te déchargera de la maintenance de ce truc fastidieux, et profitera d’un autoloader super optimisé et performant.

Si par exemple tu utilises les namespaces, et que par tes classes de base sont dans /src/Acme/ et commencent par le namespace Acme/,
tandis que celles de tests unitaires sont dans /tests/Acme/ et commencent par le namespace Test/Acme/ :


    "autoload": {
        "psr-4": {
            "Acme\\": "src/Acme/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\\Acme\\": "tests/Acme/"
        }
    }

Si par contre tu sais que tout le code interne de ton framework utiliseront les namespaces, et peut être autoloadé en Psr-4 tu peux faire ça, et pour ce coup c’est vachement classe :


    "autoload": {
        "psr-4": {
            "": "src"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "": "tests"
        }
    }

Pour ce cas, il faut que les librairies composer (le dossier « vendor ») ne sont trouve pas dans un sous-répertoire de « src » ou « tests ».

Si tu n’utilises pas les namespaces, tu peux inclure tout un dossier comme ceci, même si c’est bien dégueulasse :


    "autoload": {
        "classmap": [
            "src/main/",
            "src/foo/",
            "src/foo/bar/",
            "index.php"
        ]
    }
    "autoload-dev": {
        "classmap": [
            "tests/"
        ]
    }

D’autres exemples avec « classmap » ou « files » ici dans la doc officielle.

Pense ensuite à mettre a jour ton projet avec composer pour prendre en compte ces changements :

composer update

Et voilà. Tout a bien marché ?

Une réflexion sur « Tuto : Installer Composer sur un projet web pour gérer facilement les libraires externes (et internes) de ton framework »

Un commentaire ?