Avant de me lancer, j'ai regardé un peu le code des versions en développement (rocky-dev, et trunk), j'ai lu et relu les informations à destination des développeurs sur le wiki, notamment celle sur la nouvelle architecture des plugins.

C'est donc en toute connaissance de cause que j'ai décidé de ne pas suivre le schéma exposé. Et si j'expose ici mon développement, je n'invite personne l'imiter le copier ou simplement à l'utiliser. (Traduction: Pour ceux qui voulaient un beau script PHP prêt à dezipper, c'est loupé)

En effet dans la nouvelle architecture les informations d'identification ('nom', 'version', 'auteur', 'libellé', 'description') et d'exploitation ('activation') de chaque plugin ne seront plus stockées dans un fichier XML (desc.xml), mais dans un script PHP. Vous me direz : et alors, PHP, XML quelle importance ?

Ce que je reproche a cette méthode, c'est l'obligation pour les fichiers ainsi constitués d'appeler une fonction avec les informations comme paramètres. Ce qui limite la connaissance de ces informations à la seule fonction appelée. Sauf mettre en place un système de lecture et de traduction du fichier PHP, il est difficile de connaître ces informations en dehors de l'appel à cette fonction. Le format XML permet l'utilisation de ces informations par système tiers (programme de mise à jour automatique par exemple).

Le deuxième reproche que je fais à cette architecture définie, c'est justement qu'elle n'est que définie, mais pas disponible dans une version publique. Alors même si certains me diront que seule cette architecture sera présente dans Dotclear 2, j'attends de voir, de toucher et d'utiliser.

Donc pour revenir à nos moutons, je suis partie de ma version (basée sur Dotclear 1.2.3). J'ai donc adapté le contenu des fichiers desc.xml

le fichier desc.xml d'origine :

[xml]

<?xml version="1.0" encoding="ISO-8859-1"?>
<plugin name="monplugin" version="0.5" active="1">
  <author>Me</author>
  <label>My plugin</label>
  <desc>This is my first plugin!</desc>
</plugin>

définition des éléments XML du plugin :

  • plugin/name : Nom du plugin, uniquement des lettres ou des chiffres,
  • plugin/version : numéro de version du plugin, à votre convenance,
  • plugin/active : (O ou 1) indique si le plugin est activé,
  • author : le nom de l'auteur du plugin,
  • label : le titre du plugin,
  • desc : description du plugin.

L'encodage des caractères doit impérativement être ISO-8859-1. ( Je verrai plus tard pour changer ça, sinon ces fichiers risquent d'être les seuls en ISO-8859-1 )

le fichier desc.xml complété :

[xml]

<?xml version="1.0" encoding="ISO-8859-1"?>
<plugin name="monplugin" version="0.5" active="1">
  <author>Me</author>
  <label>My plugin</label>
  <desc>This is my first plugin!</desc>
  <perms>admin</perms>
  <link>plugin1_name, plugin2_name</link>
  <callback>xxxx</callback>
  <url>http://domain/rep/file.pkg.gz</url>
</plugin>

Définition des éléments ajouté :

  • perms : Définition des permissions (usage futur/modification en cours)
  • link : Liste des plugins devant être présents et activé avant chargement
  • callback : Définition des callback (usage futur/modification en cours)
  • url : localisation de la source de package (usage futur: mise à jour automatique)

Note : Pour les callback, j'ai rien fait c'est déjà dans le code.

Pour prendre en compte ces nouvelles valeurs, j'ai modifié dans la classe plugin ( /inc/classes/class.plugin.php ) les fonctions _getPluginInfo() et _closeTag().

[php]

	function _getPluginInfo($p)
	{
		if (file_exists($p))
		{
			$this->_current_tag_cdata = '';
                        //JL 2006/06/01 add 'link', 'perms', 'url' information
			$this->_p_info = array('name'=>NULL,'version'=>NULL,
						'active'=>NULL,'author'=>NULL,'label'=>NULL,
						'desc'=>NULL,'callbacks'=>array(),
						'perms'=>array(),'link'=>array(),'url'=>NULL);
			
			$this->_xml = xml_parser_create('ISO-8859-1');
			xml_parser_set_option($this->_xml, XML_OPTION_CASE_FOLDING, false);
			xml_set_object($this->_xml, $this);
			xml_set_element_handler($this->_xml,'_openTag','_closeTag');
			xml_set_character_data_handler($this->_xml, '_cdata');
			
			xml_parse($this->_xml,implode('',file($p)));
			xml_parser_free($this->_xml);
			
			if (!empty($this->_p_info['name'])) {
				return $this->_p_info;
			} else {
				return false;
			}
		}
	}
	
	
	function _closeTag($p,$tag)
	{
                //JL 2005/06/01 add 'link', 'perms', 'url' information
		switch ($tag)
		{
			case 'author':
			case 'label':
			case 'desc':
			case 'url':
				$this->_p_info[$tag] = $this->_current_tag_cdata;
				break;
			case 'perms' :
				$this->_p_info[$tag] = array_merge(array('admin'),explode(',',strtolower(preg_replace('/\s*/ ','',$this->_current_tag_cdata))));
				break;
			case 'link' :
				$this->_p_info[$tag] = explode(',',strtolower(preg_replace('/\s*/ ','',$this->_current_tag_cdata)));
				break;						
		}
	}

Ensuite histoire de tenir compte de ces valeurs, j'ai modifié les fonctions permettant d'établir la liste des plugins.

J'ai fait ici une petite simplification. Je considère que l'on a besoin

  • soit d'une liste complète pour l'affichage par exemple, et dans ce cas je laisse le trie alphabétique,
  • soit d'une liste réduite aux plugins activés pour les charger par exemple, et dans ce cas je modifie l'ordre en tenant compte des dependances.
[php]

//JL 2005/06/01 remplacement getFunctions (source rocky-dev )
	function getFunctions($f='functions.php')
	{
		return $this->getFile($f);
	}
	
	
	function getFile($f='functions.php')
	{
		$res = array();
		if (empty($this->p_list)) {
		         $this->getPlugins();
		}
		if (!empty($this->p_list))
		{
			foreach ($this->p_list as $entry)
			{
				if ($entry['active']) {
					$filepath = $entry['ppath'].'/'.$f;
					if (file_exists($filepath)) {
						$res[] = $filepath;
					}
				}
			}
		}
		return $res;
	}

et bien sur

[php]

	function getPlugins($active_only=true)
	{
		if (($list_files = $this->_readDir()) !== false)
		{
			$this->p_list = array();
			foreach ($list_files as $entry => $pfile)
			{
				if (($info = $this->_getPluginInfo($pfile)) !== false) { 
					if (($active_only && $info['active']) || !$active_only) {
						$this->p_list[$entry] = $info;
						$this->p_list[$entry]['ppath'] = dirname($pfile);
						$this->p_list[$entry]['loaded'] = false;
					}
				}
			}
			if (!$active_only) {
  			         ksort($this->p_list);
			} else {
                                 $alist =array();
  			         while (count($alist) != count($this->p_list)) {
 			  
     			                   foreach ($this->p_list as $entry)
    			                   {
    				                   if ($entry['active'] && !array_key_exists($entry['name'],$alist)) {
    				                            $flg_link = true;

    				                            $alinks = $entry['link'];		
    					                    foreach ($alinks as $link) {
    					                            if (!array_key_exists($link,$alist)) {
        				                                     $flg_link = false;
    						                    }
               					            }
    					                    if ($flg_link) {
    					                            $alist[$entry['name']] = $entry;
						            }else{
							            // si c'est pas ce coup ci on recommence, mais faudra bien finir 
						            }   					
    				                   }
    			                  }
				}
  			$this->p_list = $alist;
			}
			return true;
		}
		else
		{
			return false;
		}
	}

Voilà, c'est tout pour aujourd'hui. Il faudra que j'ajoute quelques tests pour éviter les situations de blocage, pour l'instant ça peut boucler. Mais pour l'instant je suis assez content de ce petit bout de code qui me permettra de mieux contrôler l'exécution de certains plugins en préparation.