Php5 - gestion de modules en objet


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

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.