Un Besoin
Il y a trois manières pour ajouter ou modifier des fonctionnalités de
WikiNi :
- créer une action : c'est le cas de toutes les fonctionnalités intégrées dans le corps de la page
- créer un handler : c'est le cas des fonctionnalités qui concernent une sortie particulière des données d'une page
- ajouter des fonctionnalités au noyau (wakka.php) : c'est le cas lorsque l'on veut développer une fonctionnalité de bas niveau qui soit disponible pour le fonctionnement général de WikiNi comme pour les actions et les handlers.
Les actions et les handlers sont modulaires et une simple copie de fichier suffit à installer un nouveau handler ou une nouvelle action. Cependant, de nombreuses fonctionnalités, comme en témoigne les
ContributionsAvancees proposées, nécessitent une modification du noyau de
WikiNi.
Nous aurrions besoin d'un mécanisme simple permettant d'étendre le noyau de WikiNi sans pour autant avoir à le modifier profondément.
Pistes de solutions
GarfieldFr a proposé, pour
RendreModulaireLaGestionDesUtilisateurs, une piste de solution qui parait tout à fait intéressante. Je l'ai reformulée ici mais l'idée de départ est de lui.
Une classe
module_x gère les fonctionnalités que l'on souhaite intégrer au coeur de Wikini. La classe Wiki crée dans son constructeur (la méthode Wiki() ) une instance
$module_x de cette classe. Pour appeler les fonctions de ce module (cette classe), il suffit d'écrire :
- $this->module_x->nomDeMethode(...).
--
GarfieldFr
Peux-tu donner des exemples de code ?
Peux-t-on employer des fonctions de la classe wiki dans la classe module_x ?
J'imagine qu'il doit être possible de tester automatiquement la présence ou non de modules.
Solution 1 :
- créer un répertoire spécial où placer les modules (par exemple /_modules)
- créer un test dans wakka.php (où ?) du type : lister tous les noms de fichier de /_modules et créer pour chaque nom une instance de la classe.
Solution 2 : enregistrer les modules dans wakka.config.php.
Autres solutions ?
--
CharlesNepote
Bon, j'ai essayé plusieurs codes mais je n'arrive à rien.
Classe à inclure : test.class.php
<?php
class Test
{
// Constructeur
function Test()
{
}
function BlaBla($text)
{
return "Fonction BlaBla : impression depuis la classe test :".$text;
}
}
?>
Action test2.php :
<?php
echo $this->$classtest->BlaBla("essai");
?>
Où dois-je mettre :
require ('_modules/test.class.php');
$classtest = new Test;
J'ai beau essayer de les mettre dans/en dehors de la classe Wiki, dans/en dehors de la fonction Wiki(), etc. Je n'arrive qu'à des erreurs...
--
CharlesNepote
Pour que cela fonctionne il faut utiliser les déclarations suivantes :
<?php
// Modifications dans le fichier wakka.php
//ne pas oublier include du fichier ou est la class
include '..../_modules/test.class.php' // exemple
/* ces includes pourraient etre fait en dynamique en fonction du contenu du repertoire _module
Idem pour les instances de Class et les déclarations d'objet Class
*/
// dans la class Wiki
class Wiki
{
// rajouter la déclaration de l'objet
var $test;
// constructor
function Wiki($config)
{
// ajouter l'instance de la class Test
$this->test = new Test($this); //
}
}
?>
- Comme cela le code doit fonctionner. C'est une bonne idée d'envisager ce type d'organisation cela devrait permettre de faire évoluer plus facilement le moteur --GouBs
Rajout pour pouvoir utiliser la class Wiki dans la class Test il faut modifier le code de cette derniere comme ceci :
<?php
class Test
{
var $wiki;
// Constructeur
function Test($wiki)
{
$this->wiki = $wiki;
// les appels se font ensuite comme ceci : $this->wiki->GetPageTag() par exemple
}
function BlaBla($text)
{
return "Fonction BlaBla : impression depuis la classe test :".$text;
}
}
?>
--
GouBs
Il faut utiliser des références plutôt que des affectations simples sinon il y a recopie des objets donc le code précédent devrait plutôt être :
<?php
// Modifications dans le fichier wakka.php
//ne pas oublier include du fichier ou est la class
include '..../_modules/test.class.php' // exemple
/* ces includes pourraient etre fait en dynamique en fonction du contenu du repertoire _module
Idem pour les instances de Class et les déclarations d'objet Class
*/
// dans la class Wiki
class Wiki
{
// rajouter la déclaration de l'objet
var $test;
// constructor
function Wiki($config)
{
// ajouter l'instance de la class Test
$this->test = & new Test($this); //
}
}
class Test
{
var $wiki;
// Constructeur
function Test(&$wiki)
{
$this->wiki = &$wiki;
// les appels se font ensuite comme ceci : $this->wiki->GetPageTag() par exemple
}
function BlaBla($text)
{
return "Fonction BlaBla : impression depuis la classe test :".$this->wiki->Format($text);
}
}
?>
--
GarfieldFr
J'ai (
PiiF) utilisé un principe proche de ça dans
:
- wakka.config.php contient le nom du fichier à inclure, et le nom de la classe à y instancier,
- on appelle un constructeur qui doit prendre l'objet wiki en argument (par convention, pour établir le lien entre les 2)
- on peut l'utiliser depuis $wiki, à condition de savoir quoi appeler (mais a priori, cette classe est ensuite utilisée par des points d'entrée spécifiques (actions ou handlers)).
Pour faire comme proposé ici, on pourrait faire ça :
- un répertoire classes contient les classes à ajouter
- dedans, par convention, le fichier toto.php décrit la classe toto
- pour chaque, on instantie un objet $wiki->toto
Pour cela, je viens de tester ce code, ça marche :
fichier test.php
<?php
class wiki {
var $moi="ICI";
function wiki() {
$d = dir('classes');
while ($f = $d->read()) {
if( ($f != ".") && ($f != "..") && (!is_dir($f))
&& preg_match('/^(.*)\.php[34]?$/', $f, $r) ) {
include_once('classes/'.$f);
$cls= $r[1];
$this->$cls= new $cls($this);
}
}
}
}
$w= new wiki();
$w->toto->qqchose();
?>
fichier classes/toto.php
<?php
class toto {
var $wiki;
function toto($wiki) {
$this->wiki= $wiki;
echo "constructeur toto, depuis ".$this->wiki->moi."<br/>";
}
function qqchose() {
echo "un truc de la classe toto, depuis ".$this->wiki->moi."<br/>";
}
}
?>
- Après réflexion, c'est n'importe quoi mon truc :-) si quelqu'un veut utiliser $w->toto, c'est parce qu'il sait que toto existe, donc, autant qu'il fasse l'include de toto.php lui même.
- Bref, je rejoins l'avis de GarfieldFr plus bas : il y a 2 sortes de classes : celles de base, qu'il faut toujours inclure (mais pour lesquelles il faut choisir quelle version inclure), et les optionnelles, comme les actions (mais là, le mécanisme actuel marche aussi bien). -- PiiF
Même remarque que précédement sur les références --
GarfieldFr
Le principe d'utiliser des classes pour les différents besoins de
WikiNi serait le suivant :
- Il faut d'abord identifier les "parties" de WikiNi qui seraient soumises à modification, je pense que la gestion des utilisateurs, l'accès à la base de données, les méthodes et les actions sont concernées. Quite à modifier le code, autant considérer la page comme étant aussi soumis à modification. Par contre il faut faire une différence entre les classes "de base" (utilisées à chaque appel du moteur wiki) et les classes créées à la volée. Typiquement, la gestion des utilisateurs est une classe de base alors que les actions et les handlers sont créés à la volée.
- Ensuite, dans la configuration, il faut indiquer le nom des classes à utiliser pour chaque "partie", chaque classe étant codée dans un fichier xxxx.class.php avec xxx le nom de la classe. (Ceci est un exemple de nom de fichier)
- Le constructeur wiki::wiki() doit créer un objet à partir des classes indiquées et doit passer une référence à l'objet wiki courant.
- Il faut que chaque classe respecte une API définie, pour forcer cela, il faut que chaque classe hérite d'une classe "abstraite" (notion qui n'existe pas réellement en php) qui définie les services de chaque classe. Par exemple, on pourra avoir une classe baseUser définissant les méthodes utilisables pour la gestion des utilisateurs, ensuite on pourra spécialiser cette classe en LDAPUser, MySqlUser? ...etc selon les besoins. On aura donc une API pour chaque type de classe :
- Une API pour l'accès à la base de données
- Une API pour la gestion des utilisateurs
- Une API pour les Actions
- Une API pour les Handlers
- Et pourquoi pas une API pour la page mais cela me semble inutile.
- En fait les classes abstraites ont été introduites en php5, ainsi que les interfaces qui seraient plus appropriées dans le cas présent (voir les classes et objets, et les interfaces en php5). Ce sont des fonctionnalités intéressantes, incontestablement inspirées du langage Java (surtout avec les rapprochements actuels entre Zend et Sun...), mais malheureusement elles ne sont pas compatibles avec les versions antérieures de PhP... php5 n'étant pas encore fortement répendu, je pense que ces fonctionnalités ne sont pas encore utilisées (du moins dans des logiciels complets), mais j'imagine qu'à l'avenir il sera bon de les mettre en oeuvre, notemment pour éviter des bugs et autres failles de sécurité... -- LordFarquaad
- En effet, PHP5 offre une bonne approche de la programmation objet ( je ne vois pas pouquoi tu dis incontestablement inspirées de Java, Java est loins d'etre le premier langage objet...) mais le fait que PHP5 n'est pas encore très répandu est en effet un problème quoique mineur car il est tout à fait possible de définir des interfaces de classe sans la notion d'interface (ie classe abstraite ou classe stub ) puis de migrer vers les interface lorsque PHP5 sera très répendu --GarfieldFr
Voila l'idée générale ... et pour bien faire, ca veux dire réécrire
WikiNi complètement car faire migrer un code pas vraiment entièrement objet vers un code entièrement objet est une source de bug !
Pour info, je suis en train d'écrire un wiki qui sera entièrement objet avec quelques fonctionnalités particulières comme le choix de la syntaxe d'édition d'une page (un utilisateur peut choisir d'éditer une page avec la syntaxe
WikiNi ou
PhpWiki ou autre) --
GarfieldFr
- API accès à la base de données : fait dans ma version
- API gestion des utilisateurs : fait dans ma version
- API Actions : existe déjà (pas objet, mais ça marche ;-)
- API Handlers : existe déjà (pas objet, mais ça marche ;-)
- API page : ça veut dire quoi "pour la page" ? pour l'enchainement header/handler/footer ?
- choix de la syntaxe : c'est à dire ? comme RendreModulaireLeFormateur ? dans ce cas, c'est fait dans ma version
- -- PiiF
- "Pour la page" veux simplement dire que quitte à réécrire tout en objet, autant représenter la page aussi sous forme d'objet avec une interface pour accéder aux différents éléments de la page. --GarfieldFr