Recherche2025

PHP Packages Graph

Explorer l’écosystème PHP à partir des paquets publiés sur packagist.org

Illustration de PHP Packages Graph

PHP Packages Graph est né d’un projet de recherche visant à comprendre l’écosystème PHP au-delà des noms de paquets, du nombre de téléchargements et des métadonnées propres à chaque dépôt.

L’objectif n’était pas simplement de collecter des données depuis Packagist. Il s’agissait surtout de transformer les métadonnées des paquets Composer en un modèle de graphe permettant d’étudier les relations de dépendance, l’influence des paquets, les pratiques de licence, les indicateurs de stabilité et les tendances de maintenance au sein d’un même écosystème connecté.

PHP Packages Graph est conçu comme un pipeline allant des données à l’analyse. Il associe scripts backend, ingénierie des données, bases de données orientées graphes, analyse des dépendances, recherche sur les écosystèmes logiciels et analyse exploratoire des données.

Le problème

Le problème central de PHP Packages Graph n’était pas l’accès aux paquets PHP, mais la compréhension de la structure de l’écosystème open source PHP.

Packagist et Composer facilitent l’installation des paquets, mais ne répondent pas directement aux questions plus profondes sur l’écosystème :

Mermaid

Un gestionnaire de paquets sait très bien résoudre les dépendances d’un projet. Il n’est pas conçu pour expliquer la structure des dépendances d’un écosystème entier.

Cette distinction compte, car les applications PHP modernes dépendent souvent de dizaines, voire de centaines de paquets directs et transitifs. Certaines bibliothèques deviennent une infrastructure invisible. Elles ne sont pas nécessairement visibles dans le produit, mais soutiennent une grande partie de l’écosystème.

En pratique, comprendre l’écosystème PHP devient un problème de graphe.

Un paquet peut en requérir un autre. Un fournisseur peut posséder de nombreux paquets. Un paquet peut entrer en conflit avec un autre, le remplacer, le fournir, le suggérer ou n’en dépendre que pour le développement. Ces relations ne sont pas des métadonnées secondaires : elles constituent la structure même de l’écosystème.

PHP Packages Graph est ainsi passé d’un simple script de collecte de données Packagist à un système de recherche fondé sur les graphes.

Orientation de la recherche

PHP Packages Graph est parti d’une idée simple :

Construire un graphe de dépendances des paquets PHP publiés sur Packagist.

Cette idée a rapidement pris de l’ampleur. Pour être utile, le système devait faire plus que récupérer les fichiers JSON des paquets. Il devait :

  • collecter les noms des paquets depuis Packagist ;

  • récupérer les métadonnées détaillées des paquets ;

  • stocker le jeu de données brut localement afin de pouvoir le rejouer et l’examiner ;

  • normaliser les données des paquets entre leurs différentes versions ;

  • extraire les dépendances depuis require, require-dev, conflict, provide, replace et suggest ;

  • modéliser les fournisseurs, les paquets et leurs relations de dépendance dans Neo4j ;

  • conserver les métadonnées utiles, notamment les licences, les auteurs, les téléchargements, les liens vers les dépôts, le type de paquet, son statut d’abandon et ses dates de mise à jour ;

  • rendre le graphe accessible au moyen de requêtes Cypher ;

  • répondre à des questions de recherche sur l’influence, la stabilité, les licences et la maintenance.

Le défi d’ingénierie consistait à concevoir un pipeline reproductible capable de transformer les métadonnées de Packagist en une base de données orientée graphe, interrogeable comme une carte de l’écosystème.

Architecture du système

PHP Packages Graph s’organise autour de quatre couches principales :

Mermaid

Chaque couche a une responsabilité claire.

La couche de collecte assure l’acquisition des données. La couche de modélisation prend en charge leur validation et leur normalisation. La base orientée graphe assure la persistance et la modélisation des relations. Enfin, la couche d’analyse traduit le graphe en questions de recherche.

Le système suit ce flux :

Mermaid

Cette structure facilite l’examen, la réexécution, le débogage et l’extension du projet.

Couche de collecte des données

La couche de collecte des données est le premier composant technique majeur de PHP Packages Graph.

Son rôle est de transformer Packagist, registre public de paquets, en un jeu de données de recherche local. Packagist fournit les noms et métadonnées des paquets, leurs versions, dépendances, téléchargements, dépôts, mainteneurs, licences et types.

Le collecteur repose sur une idée centrale :

La collecte des données doit être reproductible, pouvoir reprendre après une interruption et rester séparée de l’import dans le graphe.

Au lieu de mêler directement les appels d’API aux écritures dans Neo4j, PHP Packages Graph crée d’abord un jeu de données JSON local. Le pipeline est ainsi plus facile à examiner, déboguer, réexécuter et étendre.

Le processus de collecte est simple :

Mermaid

Cette séparation est importante, car récupérer des données à l’échelle d’un écosystème est lent, fragile et exposé aux pannes réseau.

Un import dans le graphe ne devrait pas échouer à cause d’une seule requête HTTP. Un notebook de recherche ne devrait pas dépendre d’appels d’API en direct. Le jeu de données local fournit au projet une couche intermédiaire stable.

Collecte de la liste des paquets

La première étape récupère la liste complète des paquets depuis Packagist :

Plain text
/packages/list.json

Elle fournit les noms de paquets au format standard de Composer :

Plain text
vendor/package

Ce format devient l’identifiant de référence pour le reste du système.

Le collecteur utilise ensuite le nom de chaque paquet pour récupérer ses métadonnées détaillées :

Plain text
/packages/{vendor}/{package}.json

Chaque paquet est enregistré dans un chemin qui reprend son identité Composer :

Plain text
packages/vendor/package.json

C’est une décision de conception modeste, mais utile. La structure du système de fichiers suit celle des noms de paquets, ce qui facilite la navigation manuelle dans le jeu de données.

Récupération incrémentale

Avant chaque récupération, le collecteur vérifie si les informations du paquet existent déjà.

Le pipeline bénéficie ainsi d’un comportement incrémental simple :

Mermaid

C’est important, car Packagist contient un grand nombre de paquets. Tout récupérer à nouveau à chaque exécution ferait perdre du temps et de la bande passante.

La version actuelle conserve une stratégie simple, fondée sur des délais d’expiration des requêtes, la vérification de l’existence des fichiers locaux et des options de ligne de commande :

Plain text
--fetch-list

--fetch-info

--force-update

Cela suffit pour un pipeline de recherche.

Pourquoi la conception de la collecte est importante

La décision d’ingénierie essentielle est de distinguer la collecte de l’analyse.

Le collecteur ne cherche pas à répondre aux questions de recherche. Il crée une frontière fiable autour du jeu de données.

Le reste du projet gagne ainsi en clarté :

Mermaid

Cette approche est préférable à un unique script volumineux qui téléchargerait les paquets, analyserait le JSON, écrirait les nœuds, créerait les relations et produirait des graphiques au cours d’une même exécution.

Couche de base de données orientée graphe

Une fois les métadonnées des paquets collectées, le défi suivant concerne leur représentation.

Une table relationnelle peut stocker les enregistrements des paquets. Une base documentaire peut stocker leur JSON. Cependant, les écosystèmes de dépendances sont, par nature, largement structurés par leurs relations.

Neo4j est donc particulièrement adapté à ce projet.

La base de données orientée graphe repose sur une idée centrale :

Modéliser l’écosystème PHP comme un réseau de relations, et non comme une simple liste de paquets.

Le nœud Package se trouve au centre du graphe.

Un paquet appartient à un fournisseur et se connecte à d’autres paquets au moyen des relations de dépendance de Composer :

Mermaid

Ce modèle permet d’interroger l’écosystème sous une forme fidèle au domaine réel des dépendances.

Un paquet n’est pas seulement un enregistrement. C’est un nœud dans un réseau de dépendances.

Choix technologique

PHP Packages Graph utilise Neo4j comme base de données orientée graphe.

Le projet exécute Neo4j avec Docker Compose et active les plugins APOC et Graph Data Science. Ceux-ci constituent une base utile pour l’analyse de graphes et de futurs algorithmes de centralité.

Le service Neo4j local expose :

Plain text
7474 -> Neo4j Browser

7687 -> Bolt protocol

Le projet dispose ainsi de deux interfaces :

Mermaid

Cette répartition convient bien à un projet de recherche : Python traite les données, tandis que Neo4j assure le stockage du graphe et l’analyse interactive.

Modèle principal du graphe

Le premier import dans le graphe crée deux types de nœuds :

Plain text
Vendor

Package

ainsi qu’une relation de propriété :

Cypher
(v:Vendor)-[:OWNS]->(p:Package)

Le nœud du paquet stocke son nom Composer canonique :

Plain text
full_name: vendor/package

Cette propriété devient la clé de recherche principale pour l’enrichissement ultérieur et la mise en correspondance des dépendances.

L’importateur crée également des contraintes d’unicité :

Plain text
Vendor.name

Package.full_name

C’est important, car les imports dans le graphe doivent pouvoir être réexécutés sans risque.

Sans contraintes d’unicité, la base pourrait créer silencieusement des fournisseurs ou des nœuds de paquets en double. Grâce aux contraintes et à MERGE, les imports deviennent plus prévisibles et idempotents.

Schéma du graphe

Le schéma du graphe peut être représenté comme un modèle compact de l’écosystème :

Mermaid

Ce schéma maintient un modèle simple tout en préservant les relations nécessaires à l’analyse de l’écosystème.

Le paquet comme objet de connaissance canonique

Après la création des nœuds initiaux, la couche de mise en correspondance enrichit chaque nœud de paquet avec des métadonnées :

Plain text
description

published_at

updated_at

licenses

versions

authors

repository

github_stars

github_watchers

github_forks

github_open_issues

language

abandoned

downloads

type

has_stable_release

is_custom_type

Chaque nœud Package devient ainsi un objet de connaissance compact.

Le graphe ne sait pas seulement qu’un paquet existe. Il peut aussi stocker son type, la présence de versions stables, les licences utilisées selon les versions, son nombre de téléchargements, ses dates de publication et de dernière mise à jour, ainsi que son éventuel abandon.

C’est cette combinaison qui rend le graphe utile à la recherche.

Les relations de dépendance expliquent la structure. Les propriétés des paquets apportent le contexte.

Couche de modélisation et de normalisation

Les métadonnées des paquets Packagist sont imbriquées, versionnées et ne sont pas uniformes d’un paquet à l’autre.

Un paquet peut avoir de nombreuses versions. Chacune peut définir ses propres dépendances, licences, auteurs, son type, sa stabilité et ses règles de remplacement.

La couche de modélisation transforme cette complexité propre aux versions en indicateurs au niveau des paquets.

Mermaid

Le modèle repose sur une idée centrale :

Préserver les métadonnées propres à chaque version, tout en exposant des indicateurs au niveau du paquet pour l’analyse du graphe.

PHP Packages Graph utilise des modèles Pydantic pour valider et structurer les données des paquets avant leur import dans Neo4j.

Le modèle comprend des objets au niveau du paquet, tels que :

Plain text
Package

Downloads

Maintainer

Author

Version

Le modèle Version recueille notamment les champs Composer suivants :

Plain text
require

require_dev

suggest

conflict

provide

replace

license

authors

version

version_normalized

abandoned

Le modèle Package agrège ensuite ces champs sur l’ensemble des versions.

Indicateurs agrégés des paquets

Le modèle calcule des valeurs au niveau du paquet, telles que :

Plain text
aggregate_versions()

aggregate_licenses()

aggregate_authors()

aggregate_require()

aggregate_require_dev()

aggregate_suggest()

aggregate_conflict()

aggregate_provide()

aggregate_replace()

has_stable_version()

last_updated_time()

is_custom_type()

C’est à cette étape que le jeu de données devient analysable.

Au lieu de demander à chaque requête Cypher d’examiner tous les objets de version, la couche Python prépare les propriétés et listes de relations utiles au niveau du paquet avant leur écriture dans Neo4j.

Le graphe reste ainsi lisible.

Neo4j stocke les relations. Python prend en charge la normalisation plus complexe.

Mise en correspondance des relations de dépendance

La couche de mise en correspondance des dépendances crée des relations explicites dans le graphe à partir des métadonnées Composer :

Plain text
REQUIRES

DEV_REQUIRES

CONFLICTS

PROVIDES

REPLACES

SUGGESTS

Cette distinction est importante.

Une dépendance de production n’est pas équivalente à une dépendance de développement. Un paquet souvent requis dans require-dev peut être central pour les tests, l’analyse statique, les normes de code, le débogage ou les outils de développement, sans pour autant intervenir lors de l’exécution.

En séparant ces types de relations, PHP Packages Graph peut répondre à des questions plus précises :

Mermaid

Une table de paquets à plat ne permet pas de répondre clairement à ce type de question.

Pourquoi la conception de la modélisation est importante

La principale valeur de la couche de modélisation réside dans la simplification sans perte de sens.

Les métadonnées Composer sont riches, mais cette richesse brute peut devenir du bruit. Un graphe de recherche a besoin des bonnes abstractions.

PHP Packages Graph conserve les distinctions importantes :

Mermaid

Il en résulte un graphe assez expressif pour analyser l’écosystème, tout en restant suffisamment simple pour être interrogé directement.

Couche d’analyse

Une fois le graphe construit, Cypher devient l’interface de recherche.

La couche d’analyse interroge directement le graphe sur des questions à l’échelle de l’écosystème.

Mermaid

La couche d’analyse repose sur une idée centrale :

Transformer les métadonnées des paquets en questions à l’échelle de l’écosystème.

Le projet comprend des requêtes Cypher sur la répartition des licences, les paquets les plus requis, les dépendances de développement, les paquets présents dans les deux catégories de dépendances, les téléchargements, les moyennes par auteur, les années de publication et les paquets maintenus sur une longue période.

Ces requêtes ne sont pas de simples vérifications de la base de données. Elles représentent l’orientation de recherche du projet.

Répartition des licences

Les licences constituent l’un des indicateurs les plus importants à l’échelle de l’écosystème.

Le graphe peut répondre aux questions suivantes :

Mermaid

C’est important, car les licences influencent l’adoption, la conformité, la redistribution et les risques pour les organisations.

Un graphe de dépendances dépourvu d’analyse des licences ne donne qu’une vision partielle.

Influence des dépendances

La question la plus importante pour le graphe concerne l’influence des paquets.

Un paquet qui reçoit de nombreuses relations REQUIRES est structurellement important, car beaucoup d’autres paquets en dépendent.

Le graphe peut répondre aux questions suivantes :

Mermaid

Cette analyse révèle la couche d’infrastructure de l’écosystème PHP.

Certains paquets peuvent sembler peu visibles en tant que produits, alors qu’ils sont profondément intégrés à la chaîne d’approvisionnement logicielle. Ils méritent une attention particulière, car leur maintenance, leur stabilité et leur sécurité affectent de nombreux projets en aval.

Téléchargements et centralité des dépendances

Les téléchargements et la centralité des dépendances sont liés, mais ne mesurent pas la même chose.

Les téléchargements mesurent le volume d’utilisation.

Les relations de dépendance entrantes mesurent l’influence structurelle.

Un paquet peut compter de nombreux téléchargements parce que beaucoup de projets l’installent directement. Un autre peut être structurellement important parce qu’il soutient d’autres paquets populaires.

PHP Packages Graph permet de comparer ces indicateurs au lieu de réduire la popularité à une seule dimension.

C’est important, car la santé d’un écosystème dépend à la fois de son infrastructure visible et invisible.

Stabilité et maintenance

Le projet étudie aussi la stabilité et la maintenance à partir de champs tels que :

Plain text
has_stable_release

published_at

updated_at

abandoned

versions

Ces champs aident à répondre à des questions comme :

Mermaid

Les métadonnées des paquets deviennent ainsi des indicateurs de pérennité.

La taille ne suffit pas à déterminer la santé d’un écosystème de dépendances. Celui-ci est sain lorsque ses paquets importants sont maintenus, stables, compréhensibles et utilisables dans un cadre légal clair.

Exemples de requêtes

Le projet utilise des requêtes Cypher pour explorer le graphe.

Par exemple, la répartition des licences peut être interrogée avec :

Cypher
MATCH (p:Package)

UNWIND p.licenses AS license

RETURN license, COUNT(p) AS package_count

ORDER BY package_count DESC;

Les principales dépendances d’exécution peuvent être interrogées avec :

Cypher
MATCH (:Package)-[:REQUIRES]->(p:Package)

RETURN p.full_name AS package, COUNT(*) AS times_required

ORDER BY times_required DESC

LIMIT 100;

Les principales dépendances de développement peuvent être interrogées avec :

Cypher
MATCH (:Package)-[:DEV_REQUIRES]->(p:Package)

RETURN p.full_name AS package, COUNT(*) AS times_required

ORDER BY times_required DESC

LIMIT 100;

Les paquets importants à la fois pour l’exécution et le développement peuvent être interrogés avec :

Cypher
MATCH (p:Package)

OPTIONAL MATCH (:Package)-[:REQUIRES]->(p)

WITH p, COUNT(*) AS required_count

OPTIONAL MATCH (:Package)-[:DEV_REQUIRES]->(p)

WITH p, required_count, COUNT(*) AS dev_required_count

WHERE required_count > 0 AND dev_required_count > 0

RETURN p.full_name, required_count, dev_required_count

ORDER BY required_count DESC, dev_required_count DESC

LIMIT 10;

Les anciens paquets toujours maintenus peuvent être interrogés avec :

Cypher
MATCH (p:Package)

WHERE (p.abandoned IS NULL OR p.abandoned = false)

  AND p.published_at IS NOT NULL

  AND p.updated_at IS NOT NULL

WITH DISTINCT p,

     duration.between(datetime(p.published_at), datetime(p.updated_at)) AS lifespan

ORDER BY lifespan.years DESC

LIMIT 10

RETURN DISTINCT p.full_name AS package_name, p.published_at, p.updated_at, lifespan.days;

Grâce à ces requêtes, le graphe devient un outil de recherche, et non un simple système de stockage.

Notebook de recherche et figures

Le dépôt comprend également un notebook et des figures, en cohérence avec l’orientation du projet.

Le code ne se limite pas à un importateur. Il constitue aussi un environnement de recherche exploratoire.

Le notebook permet d’examiner les résultats, de créer des graphiques, de comparer des mesures et de transformer les requêtes du graphe en explications visuelles.

Les figures constituent la couche de communication de la recherche.

Une base orientée graphe aide à poser les questions. Un notebook aide à interpréter les réponses. Les figures rendent ces réponses compréhensibles.

Le processus de recherche se présente ainsi :

Mermaid

Ce processus ancre le projet dans des données réelles tout en rendant les résultats compréhensibles en dehors de la base de données.

Principales décisions d’ingénierie

Partir de la question sur l’écosystème, pas de l’outil

Le projet est parti d’une question de recherche :

À quoi ressemble l’écosystème PHP lorsque les paquets Packagist sont modélisés sous forme de graphe de dépendances ?

Cette question a guidé l’architecture.

L’objectif n’était ni « d’utiliser Neo4j » ni de « récupérer les données de Packagist ». Il s’agissait de comprendre la structure des dépendances, l’influence des paquets, leur stabilité, leurs licences et les tendances de maintenance.

Neo4j est utile parce que le problème prend naturellement la forme d’un graphe.

Utiliser une base orientée graphe pour les relations de dépendance

Les écosystèmes de paquets sont des réseaux.

Un paquet peut en requérir, suggérer, remplacer ou fournir un autre, ou entrer en conflit avec lui. Il s’agit de relations, pas seulement de colonnes.

Neo4j fait de ces relations des éléments de premier plan.

C’est le modèle de stockage adapté à l’analyse des dépendances.

Séparer la collecte de l’import

Le collecteur écrit un jeu de données JSON local avant l’entrée des données dans Neo4j.

C’est une décision solide pour la recherche.

Elle facilite la réexécution, l’examen, le débogage et l’extension du système. Elle évite aussi que l’import dans le graphe dépende de la disponibilité de l’API en direct.

Garder des types de relations explicites

Le projet ne réduit pas toutes les arêtes à une relation générique DEPENDS_ON.

Il conserve séparément les types de relations de Composer :

Plain text
REQUIRES

DEV_REQUIRES

CONFLICTS

PROVIDES

REPLACES

SUGGESTS

Ce choix de modélisation est pertinent, car chaque relation a une signification différente.

L’influence des dépendances d’exécution et celle des dépendances de développement ne doivent pas être confondues trop tôt.

Agréger les métadonnées des paquets avant leur insertion dans le graphe

Le modèle Pydantic agrège les licences, les auteurs, les versions, les dépendances, la stabilité et les horodatages de mise à jour avant l’écriture dans Neo4j.

Le graphe reste ainsi plus simple et les requêtes plus claires.

La base de données ne devrait pas avoir à comprendre chaque détail imbriqué du JSON de Packagist pour répondre à des questions élémentaires sur l’écosystème.

Utiliser Cypher comme interface de recherche

Cypher convient bien, car les questions de recherche portent sur les relations.

Des requêtes comme « paquets les plus requis » ou « paquets requis à la fois lors de l’exécution et du développement » s’expriment naturellement dans un graphe.

La base de données ne sert donc plus seulement à la persistance : elle devient une interface d’analyse.

Préparer l’utilisation d’algorithmes de graphe

La configuration de Neo4j comprend le plugin Graph Data Science, ce qui ouvre la voie à des analyses ultérieures plus approfondies.

L’étape suivante naturelle consiste à calculer :

Mermaid

Le projet passerait ainsi d’une analyse descriptive à une recherche structurelle sur l’écosystème.

Considérer la maintenance comme un indicateur de l’écosystème

Le projet ne se limite pas aux téléchargements ou au nombre de dépendances.

Il intègre aussi des champs tels que le statut d’abandon, les dates de publication et de mise à jour, la présence d’une version stable, les versions et le type de paquet.

C’est important, car la santé d’une dépendance ne dépend pas seulement de sa popularité.

Un paquet abandonné dont dépendent de nombreux projets représente un risque. Un ancien paquet toujours maintenu constitue une infrastructure. Un paquet sans version stable peut être utile, mais il transmet un autre type d’indicateur d’adoption.

Ce que j’ai appris

La principale leçon de PHP Packages Graph est qu’un écosystème logiciel ne se résume pas à un ensemble de paquets.

C’est un réseau d’infrastructure.

Certains paquets sont visibles parce que les développeurs les installent directement. D’autres restent invisibles, car ils se trouvent en profondeur dans l’arbre des dépendances. Les deux peuvent pourtant être importants.

La modélisation en graphe rend cette structure visible.

J’ai également appris que les métadonnées des paquets gagnent en valeur lorsqu’elles sont reliées. Un champ de licence, un nombre de téléchargements ou un indicateur d’abandon sont utiles. Mais l’analyse devient réellement éclairante lorsque ces signaux sont combinés aux relations de dépendance.

Par exemple, un paquet abandonné avec peu de dépendants pose un certain type de problème. Un paquet abandonné qui reçoit des milliers de relations de dépendance en pose un tout autre.

Le projet a aussi montré que la recherche sur un écosystème exige une préparation rigoureuse des données. Les métadonnées de Packagist sont riches, mais imbriquées entre les versions et pas toujours uniformes. Avant toute analyse, les données doivent être validées, normalisées, agrégées et associées à la structure appropriée.

Enfin, Neo4j n’est pas ici un simple outil de visualisation. Il change la nature des questions que le projet peut poser. Dès lors que les paquets deviennent des nœuds et les dépendances des arêtes, l’écosystème PHP peut être étudié comme un réseau.

Conclusion

PHP Packages Graph est un système de recherche fondé sur les graphes pour analyser l’écosystème des paquets PHP.

Sa principale valeur d’ingénierie ne réside pas dans la récupération des métadonnées depuis Packagist, mais dans le pipeline construit autour d’elles : collecte, création d’un jeu de données local, validation, normalisation, modélisation du graphe, mise en correspondance des dépendances, analyse Cypher et visualisation des résultats de recherche.

Le système transforme les données des paquets Packagist en un graphe connecté dans lequel les paquets peuvent être analysés selon leur influence, leur rôle comme dépendance, leur licence, leur stabilité, leurs téléchargements, leur ancienneté, leur maintenance et la structure de leurs relations.

Voici l’idée centrale de PHP Packages Graph :

Rendre la structure cachée de l’écosystème PHP visible, interrogeable et analysable.

Autres projets

Tout voir

2026

Leganews Pro

Conception d’une plateforme structurée de veille juridique pour le marché congolais

Voir

2025

Basango

Vers un système évolutif et intelligent de curation de l’actualité congolaise

Voir

2025

Points of Interest

Cartographie collaborative des zones d’activité par contributions anonymes

Voir