Php5 - gestion de modules en objet

Soyez le premier à donner votre avis sur cette source.

Snippet vu 12 196 fois - Téléchargée 24 fois


Contenu du snippet

Kikoo :)

Bon, ca faisait bien longtemps que j'avais pas posté, et pour cause... les études ayant repris (pour ma part :p), j'ai un peu tous les langages qui viennent se méler un peu n'importe comment donc PHP passe un peu par la trappe ces temps ci.
Qu'à cela ne tienne, me voila de retour (ca me manquait un peu je dois dire) !

Alors, j'ai déja fais une classe à peu près à l'identique, sauf que cette fois ci... elle est fonctionnelle !

Le code se découpe en 2 (nan en 3 en faites) :
-> fichier XML en tant que fichier de configuration (jvois déja Malalam qui sourit ^^)
-> Classes PHP.

Pour mes classes PHP, y'a en tout 2 classes :
-> Une classe abstraite Core que toutes mes classes de mon projet vont hériter. Cette classe contient tout le nécessaire pour la gestion des modules.
-> Une classe concrète SystemCore qui lui seul peut gérer les modules et autres évenements survenu dans le Core.

Je peux ajouter une 3ème classe Mysql pour vous faire voir que c'est totalement transparent :)

Ce que ce script fait :
-> Gestion des classes en tant que modules. Permet d'activer ou non un module, de pouvoir logguer ces actions...

Voyons le code en détail.

Source / Exemple :


<?php
 // En premier lieu, le fichier .xml
?>
<?xml version='1.0'?>
<modules status="1">
 <module name="systemcore" status="2" src="./class/SystemCore.php" />
 <module name="log" status="1" src="./class/log.php" />
 <module name="mysql" status="1" src="./class/mysql.php" />
 <module name="msn" status="1" src="./class/msn.php" />
</modules>
<?php
 // Jusque la, pas de suprise. Je dispose de plusieurs modules (pour l'exemple) : systemcore (obligatoire), log (pour avoir un système de logging), mysql (pour ma gestion de base de donnée) et msn (pour avoir mon status d'afficher sur mon site).
 // Le status se découpe comme ceci : 0 - Inactif ; 1 - Actif ; 2 - Actif avec débug.
 // Le src indique le chemin de la classe. Pas obligatoire, ca sert à rien sinon à faire joli pour le moment ^^

 // Visons la classe abstraite maintenant :

abstract class Core {

 private static $_module = array();
 private static $_xml;
 private $FileConf = './xml/conf.xml';

 protected $debug = FALSE;
 
// Initalisation de chaque module
 protected function __construct() {

  $classname = strtolower(get_class($this));  
   
  // Si la classe a déja été instancié, pas la peine de refaire une recherche.
   if ( !isset(self::$_module[$classname]) ) {
   	    // On charge le fichier de conf.
         self::$_xml = simplexml_load_file($this->FileConf);
         
        //On regarde si le module existe dans le fichier de conf.
         $var = self::$_xml->xpath('//module[@name="'.$classname.'"]');
        // Si c'est pas le cas ==> erreur
          if ( $var === FALSE )
               throw new Exception('Module '.$classname.' introuvable dans le fichier de configuration');
        
        // On recherche la chaine XML du module.
         $mod = simplexml_load_string($var[0]->asXml());
        // On vérifie son status.
          if ( (int) $mod['status'] === 0 ) {
               throw new Exception('Module '.$classname.' ne peut être chargé : Status = 0');
          } elseif ( (int) $mod['status'] === 2 ) {
   	           $this->debug = TRUE;
          }
   }
   
 // On oublie pas de mettre le module comme actif :)
  self::$_module[$classname]['actif'] = TRUE;
    
 }

// Destruction de chaque module.
 public function __destruct() {
  $classname = strtolower(get_class($this));
  self::$_module[$classname]['actif'] = FALSE;
 }
 
// Récupère les infos du Core SEULEMENT par la classe Système.
 protected function GetCoreInfos($property) {
   if ( $this->isSystemCore() ) {
   	     switch ( $property ) {
   	     	case 'fileconf':
   	     		  return $this->_xml;
   	     		  break;
   	     	case 'module':
   	     		  $modulename = func_get_arg(1);
                  return ( isset(self::$_module[$modulename] ) ) ? self::$_module[$modulename] : FALSE;
                  break;
   	     	default:
   	     		  throw new Exception ($property.' n\'existe pas !');
   	     }
   } else {
   	    throw new Exception('Impossible d\'accéder aux ressources... Accès impossible ! (GetCoreInfos '.$property.' )');
   }
 }
 
// Ecrit des infos dans le Core SEULEMENT par la classe Système.
 protected function SetCoreInfos($property) {
  if ( $this->isSystemCore() ) {
  	    switch ( $property ) {
  	    	case 'module':
  	    		  $modulename = func_get_arg(1);
  	    		  $key = func_get_arg(2);
  	    		  $val = func_get_arg(3);
	  	   	      self::$_module[$modulename][$key] = $val;
  	    		  break;
  	    }
   } else {
   	    throw new Exception('Impossible d\'accéder aux ressources... Accès impossible ! (SetCoreInfos '.$property.' )');
   }  
 }
 
// Vérification si présence de la classe Système pour accéder au ressources du Core.
 private function isSystemCore() {
  if ( get_class($this) === 'SystemCore' && is_subclass_of('SystemCore', 'Core') ) {
  	   return TRUE;
  } else {
       return FALSE;
  }	
 }
 
}

// Toute classe abstraite ou concrète DOIT ( c'est une OBLIGATION !!! ) étendre cette classe !
// Cette classe abstraite "core" est le coeur de la gestion des classes.

// Maintenant, voici le code de ma classe abstraite pour gérer le Core :

// Classe Système. Peut intéragir avec le Core.
class SystemCore extends Core {

 // Instance unique du Système.
 private static $_SystemInstance;

 // Identifie le système dans le Core.
 protected function __construct() {
  parent::__construct();
 }
 
// Instance unique.
 public static function GetInstance() {
   if ( !isset(self::$_SystemInstance) ) self::$_SystemInstance = new self;
  return self::$_SystemInstance;
 }

// Recherche de l'activation ou non d'un module dans le Core.
 public function isActive($modulename) {
  $mod = $this->GetCoreInfos('module',$modulename);
  return $mod['actif'];
 }

// Pré-initialise un module dans le corps. (Evite le parsing du fichier xml)
 public function PreInit($modulename) {
  $this->SetCoreInfos('module', $modulename, 'actif', TRUE);
 /*  if ( $this->debug ) {
   	    $this->newEntry('Pré-initialisation du module '.$modulename.' accomplie.');
   }*/
 }
 
}

// Voila, on voit bien que le Système peut faire ce qu'il veut avec les modules, choses que peut ne pas faire les autres classes qui héritent.

// Une autre classe concrète, celui d'une base de donnée (raccourcie au max !!) :

class mysql extends Core {

 public function __construct($host, $user, $passwd, $basename) {
   parent::__construct(); // Obligatoire !
   mysql_connect(...);
 }

}

// Bref, c'est une classe banale quoi.
// Maitenant, voyons voir comment ca fonctionne dans une page web.

// On inclus les fichiers :
include ('core.php');
include ('mysql.php');
include ('systemcore.php');
// Jusque la tout va bien. Je vais donc initialiser ma classe de BDD :
try {
 $db = new mysql;
} catch ( Exception $e ) {
  die ($e->getmessage());
}
// Et oui ! C'est tout simple ! C'est exactement comme si on instanciait une classe "normale" !
// Où est l'intéret de mon "Core" la dedand ?
// Simple, il ne faut pas oublier que tout tourne autour de mon fichier XML. Pour rappel, j'ai mis mysql en tant que "Status = 1", donc j'ai activé le droit d'utiliser mysql sur mes pages. Si j'avais mis "Status = 0" j'aurais eu une exception !
// Cette méthode sera pareil pour les autres classes.

// Regardons maintenant si ma classe est bien initialisée par le Core :
$Sys = SystemCore::GetInstance(); // On récupère l'instance unique du Systeme.
 if ( $Sys->isActive('mysql') ) {
      echo 'Module mysql activé';
 }

// On voit bien que le texte "Module mysql activé" est affiché à l'écran. Donc c'est que tout va bien.
// Si un jour, pour une raison où pour une autre, vous souhaitez couper un module (un bug dessus par exemple), il suffit de modifier le fichier XML et mettre "Status = 0" sur le module que vous voulez couper.
// Tout ca doit être géré dans le SystemeCore... chose que je n'ai pas encore implanté pour le moment. Ca va venir :)

// Tout est centralisé avec ce système... il n'y a plus de modules de classes qui se baladent dans le vide.
// Ca nécessite de passer votre projet au "prèsque tout-objet"... mais ca reste une facon de coder assez sympatoche :)

Conclusion :


Bon bah voila à peu près vite fait ce que ca peut donner.

Si y'a des suggestions (en rajout - modif - suppression de choses), je suis preneur pour agrémenter tout ca.
Vala vala :)

A voir également

Ajouter un commentaire

Commentaires

audayls
Messages postés
373
Date d'inscription
samedi 9 juillet 2005
Statut
Membre
Dernière intervention
11 août 2008
-
Salut,
Je ne sais pas si tu es en train de refaire une nouvelle version de cette source mais j'ai relevé un peu bug dans cette version.

C'est 3 fois rien et c'est facilement corrigeable : lorsque tu initialises plusieurs fois une classe qui est en status 2 une seule a la variable debug initialisée.
kankrelune
Messages postés
1305
Date d'inscription
mardi 9 novembre 2004
Statut
Membre
Dernière intervention
21 mai 2015
-
"Oui parce que je veux bien laisser le choix de la configuration, et Non parce que SQL ne doit pas être utilisé puisqu'il est mis en tant que module. A la limite, je devrais découper mon Core en 2 : Une partie "critique" (genre classe sql et gestion de session) et une autre partie "module" (genre classe users, commentaires, galleries etc...).
Oui je pourrais faire ca en effet :) Jvais m'y attarder tiens."

Pour moi un module est une partie escamotable du site... un plug-in... pas une partie du core du site... je définnirais donc plutot comme module les sous catéorie d'un site (gallerie photos, espace de téléchargement)... mais c'est une question de sémantique qui n'enleve rien à la qualité de la source... .. .

J'ais une class qui ressemble à la tienne dans le principe... mais pour des modules comme je le définis plus haut... on y retrouve des options tel que...

- isActiv : comme statut pour toi sauf que c'est un booléen la notion de debug étant gérés sur la globalité du site et non par module
- hasAdmin : possede (ou non) une partie administrable à inclure en back office
- hasMain : est directement visionable ou doit etre inclus dans le site

Si ça peut te donner des idées... .. . ;o)

Sinon comme d'hab pas grand chose à redire (muarf même pô drole lOl)... si ce n'est que je ne comprend pas trop l'interet du destructeur de ta classe Core... .. .

Pour la variable $classname pourquoi ne pas la stocker dans un attribut plutot que de faire plusieur fois...

$classname = strtolower(get_class($this));

Mais c'est un détail... .. .

@ tchaOo°
FhX
Messages postés
2350
Date d'inscription
mercredi 13 octobre 2004
Statut
Membre
Dernière intervention
18 avril 2015
3 -
"C'est une nouvelle version de ta précédente source?" On peut dire ca comme ca oui :)
Encore, comme Mala vient de l'expliquer, ceci est plus du code concret qu'un simple "blabla" que j'avais fait il y a quelques mois :)

"et je dirais que le choix du xml ou d'une base de données est à chacun en fonction de ses moyens/preférences/..." Oui et Non.
Oui parce que je veux bien laisser le choix de la configuration, et Non parce que SQL ne doit pas être utilisé puisqu'il est mis en tant que module. A la limite, je devrais découper mon Core en 2 : Une partie "critique" (genre classe sql et gestion de session) et une autre partie "module" (genre classe users, commentaires, galleries etc...).
Oui je pourrais faire ca en effet :) Jvais m'y attarder tiens.

"Maintenant je me suis toujours pune question sur les systèmes modulaire : comment associé ça avec un système de template (comme PHPnuke par exemple)."Simple, avec du try{}catch{}.
Tu fais ca :
try {
$x = new class();
// Signifie que la classe est instanciable, donc que le module est chargé. On peut continuer et afficher la suite sans problème.
} catch ( Exception $e ) { // Voir à faire une classe d'exception plus poussé aussi.
// Ici, la classe n'est pas instanciable, donc le module est désactivé. On fait tout autre chose.
}

Voila, c'est aussi simple que ca.

"Pourrais-je l'avoir en zip."Oui, quand j'aurais fais des modifs dessus. Un gros travail est en cours, je retravaille le Core au niveau de la gestion des modules (via numéro ID unique plutot que via un nom d'instance).

"Es-tu facher avec __autoload() ?" Pas du tout, mais je voulais pas me faire chier avec une fonction externe à mes classes pour l'exemple du code :)
Rassure toi, __autoload() est bien présent chez moi ^^


Je préviens pour dire que je vais faire une grosse modif du code... Mais que j'attends toujours autant d'idées pour l'améliorer :)
juki_webmaster
Messages postés
947
Date d'inscription
mercredi 19 novembre 2003
Statut
Membre
Dernière intervention
5 avril 2008
3 -
// On inclus les fichiers : << Es-tu facher avec __autoload() ?
alpha386
Messages postés
16
Date d'inscription
jeudi 23 octobre 2003
Statut
Membre
Dernière intervention
15 novembre 2006
-
Salut

Pourrais-je l'avoir en zip.

Bye

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.