Je viens juste de proposer un ticket avec un patch pour une amélioration (à mon sens) de la gestion des services dans jelix et la gestion des dépendances de ces services. Cette proposition est très inspirée de l'implémentation de Stubbles pour son conteneur d'inversion de contrôle. Mon implémentation est beaucoup moins complète mais aussi beaucoup plus simple. Je l'utilise depuis pratiquement 1 an au boulot mais je viens de pas mal la modifier pour plus coller avec l'esprit de Jelix ou au moins la vision que j'en ai.

Le but

Proposer un moyen de lier une interface (ou une classe) a une classe de façon à récuperer une instance de la deuxième lorsque j'invoque la première. Cette liaison peut être définie dans le fichier de configuration de Jelix, dans une constante spéciale de l'interface invoquée, et peut être modifiée pendant l'exécution.

Un exemple simple

Si je met :

modulename1*itfname = modulename2~targetclassname

dans le fichier de configuration de Jelix dans la section "Bindings", je peux utiliser cette liaison de cette façon :

$service = jClasses::getBindedService('modulename1~itfname');

Et j'aurai un instance de la classe "targetclassname" dans la variable $service.

Explications

Vous allez peut-être me dire que cela ne sert pas à grand chose. Pour le moment, c'est vrai. Mais supposez maintenant que vous vouliez faire des tests unitaires pour une classe qui utilise ce service et supposez aussi que ce service modifie plein de chose dans votre base de données, par exemple. Vous ne voulez pas mettre le cirque dans votre base de données à chaque passage de tests unitaires. Dans ce cas, vous pouvez créer un "Mock object", par exemple avec PHPUnit et vous en servir à la place du précédent service sans même modifier la classe que vous testez. Voilà ce que vous pouvez faire dans votre test unitaire :

$mock = $this->getMock('targetclassname');
jClasses::bind('modulename1~itfname')->to($mock);

Et $mock sera l'instance utilisée à chaque appel à jClasses::getBindedService('modulename1~itfname'), et votre base de donnée est sauve. Et il y a encore bien d'autres utilités à tout ça.

Détails

Pour le moment, je ne suis pas très satisfait de ce qu'il faut mettre dans le fichier de config de Jelix, le caractère "~" des sélecteurs Jelix est interdit en tant que clé dans les fichiers ini et j'ai du le remplacer par un "*". Je pense faire un fichier de config particulier avec mon propre parseur autorisant tous les caractères nécessaires, avec la possiblité de le compiler et de le mettre en cache. Il y a encore pas mal d'améliorations que je voudrait apporter encore à tout ça :

  • Faire fonctionner ce système avec les classes et non plus seulement les services
  • Faire de la vraie injection de dépendance, comme dans Stubbles mais en plus simple et pas trop au détriment des performance (c'est pas forcément gagné ! ;-))
  • Intégrer ce mécanisme complètement dans les méthode existante de jClasses (create, getService), si j'ai l'approbation des contributeur de Jelix)