Problème avec mon moteur de template - Blocs imbriqués

cs_christophedlr Messages postés 267 Date d'inscription samedi 3 janvier 2004 Statut Membre Dernière intervention 23 août 2023 - 19 févr. 2011 à 09:18
cs_christophedlr Messages postés 267 Date d'inscription samedi 3 janvier 2004 Statut Membre Dernière intervention 23 août 2023 - 22 févr. 2011 à 15:59
Bonjour à tous,

Voila je suis entrain de programmer mon site internet et je suis tombé sur un gros bug avec mon moteur de template. Quand la fonction assign_block_vars remplace un bloc, aucun soucis mais dès que c'est le bloc parent (cas des blocs imbriqués), tout est bon SAUF le dernier remplacement à effectuer où là le moteur laisse la balise de fin de bloc.

Sur mon moteur, les blocs sont composés comme ceci : <!--BLOCK_NOM--> et pour la fin : <!--/BLOCK_NOM-->, les variables dedans sont composés comme ceci : {NOMBLOC.VAR}.

Voici le code du moteur :
<?php

class Template
{
private $directory; //Nom du répertoire de base des templates
private $contentfile = array(); //Contenu des fichiers ouverts
private $allcontentblock = array(); //Contenu complet (masque complet) des blocs

/*Constructeur de la classe*/
function __construct($directory)
{
if ( is_string($directory) )
{
$this->directory = $directory.'/';
return;
}

echo "Erreur Template::__construct - Vous n'avez pas spécifié une chaîne de caractères
";
}

/*Ouvre un template*/
function open($filename, $directory = '')
{
if ( !is_string($filename) )
{
echo "Erreur Template::open - Vous n'avez pas entré un nom de fichier
";
}

/*Si le fichier existe à l'emplacement par défaut*/
if ( file_exists($this->directory.$filename) )
{
$this->contentfile[$filename] = file_get_contents($this->directory.$filename);
return $filename;
}

else
{
/*Si le fichier est dans un répertoire différent, par exemple un module*/
if ( file_exists($directory.$this->directory.$filename) )
{
$this->contentfile[$directory.$this->directory.$filename] = file_get_contents($directory.$this->directory.$filename);
return $directory.$this->directory.$filename;
}

/*Si le fichier n'existe pas du tout*/
else
{
echo "Erreur Template::open - Vous n'avez pas indiqué un fichier éxistant
";
return FALSE;
}
}
}

/*Remplace les {QUELQUECHOSE} par la valeur*/
function assign_vars($template, $array)
{
if ( isset($this->contentfile[$template]) )
{
foreach ($array as $key => $value)
{
$this->contentfile[$template] = str_replace('{'.$key.'}', $value, $this->contentfile[$template]);
}
}

else
{
echo "Erreur Template::assign_vars - Vous n'avez pas indiqué le nom d'un template ouvert
";
}
}

/*Remplace les blocs de code*/
function assign_block_vars($template, $block, $array)
{
if ( isset($this->contentfile[$template]) )
{
if ( preg_match('#\<!--BLOCK_'.$block.'--\>(.+)\<!--/BLOCK_'.$block.'--\>#sU', $this->contentfile[$template], $matches) )
{
$this->allcontentblock[$block] = $matches[0];
$contentblock = $matches[1];

foreach ($array as $key => $value)
{
$contentblock = str_replace('{'.$block.'.'.$key.'}', $value, $contentblock);
}
$this->contentfile[$template] = preg_replace('#\<!--BLOCK_'.$block.'--\>(.+)\<!--/BLOCK_'.$block.'--\>#sU',
$contentblock.$this->allcontentblock[$block], $this->contentfile[$template]);
}
}

else
{
echo "Erreur Template:assign_block_vars - Vous n'avez pas indiqué le nom d'un template ouvert
";
}
}

/*Affiche le template*/
function display($filename, $debug = FALSE)
{
if ( $debug === FALSE )
{
$this->removedebug($filename);
}

else if ($debug !== TRUE)
{
echo "Erreur Template::display - Vous n'avez pas indiqué un booléen comme second paramètre
";
}

echo $this->contentfile[$filename];
}

/*Supprime les variables et blocs non utilisés*/
private function removedebug($filename)
{
$this->contentfile[$filename] = preg_replace('#\<!--BLOCK_(.+)--\>(.+)\<!--/BLOCK_(.+)--\>#sU',
'', $this->contentfile[$filename]);

$this->contentfile[$filename] = preg_replace('#\{(.+)\}#sU', '', $this->contentfile[$filename]);
}
}

?>


Je ne comprend pas pourquoi il me laisse cette balise de fin, j'ai tout tenter mais sans résultat.


Merci d'avance pour votre aide.

25 réponses

phpAnonyme Messages postés 392 Date d'inscription mercredi 28 octobre 2009 Statut Membre Dernière intervention 23 mars 2012 55
19 févr. 2011 à 17:36
Un exemple de cas serait le bien venu ! Et pas juste la classe car là euhhh...voilà quoi

______________________________________________________________________
0
cs_christophedlr Messages postés 267 Date d'inscription samedi 3 janvier 2004 Statut Membre Dernière intervention 23 août 2023 5
19 févr. 2011 à 17:46
Ben un exemple tout con :
<!--BLOCK_TEST-->
{TEST.VAR1}

<!--BLOCK_TEST2-->
{TEST2.VAR2}

<!--/BLOCK_TEST2-->
<!--/BLOCK_TEST-->


Ca c'est pour la page html (on l'appelera index.html), et le traitement :
<?php

include('template.class.php');

$tpl = new Template('./');

$file = $tpl->open('index.html');

for ($i = 0; $i < 2; $i++)
{
    $tpl->assign_block_vars($file, 'TEST', array(
        'VAR1' => $i ));
    for ($j = 0; $j < 2; $j++)
        {
            $tpl->assign_block_vars($file, 'TEST2', array(
                'VAR2' => $j ));
        }
}

$tpl->display($file);

?>

Et ça c'est le traitement (index.php pour l'exemple).

Au final au lieu de me retrouver avec ceci :
0
0
1
1


J'ai :
0
0
1
1
<!--/BLOCK_TEST-->
0
phpAnonyme Messages postés 392 Date d'inscription mercredi 28 octobre 2009 Statut Membre Dernière intervention 23 mars 2012 55
19 févr. 2011 à 18:08
un exemple tout con :
Un wèè boff !

C'est surtout le résultat qui m'intéressait, mais c'est bon tu la donné(à la fin) mais je vois pas ce qui te gêne !

______________________________________________________________________
0
cs_christophedlr Messages postés 267 Date d'inscription samedi 3 janvier 2004 Statut Membre Dernière intervention 23 août 2023 5
19 févr. 2011 à 18:11
Ben c'est le tag de fin qui ne doit pas se trouver là, il n'est plus existant en temps normal.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
phpAnonyme Messages postés 392 Date d'inscription mercredi 28 octobre 2009 Statut Membre Dernière intervention 23 mars 2012 55
19 févr. 2011 à 18:16
Bon visiblement il semblerait que tu parle de ce qui a dans le code source à savoir <!--/BLOCK_NOM-->, ben c'est sous la forme d'un commentaire donc tu chipote un peu (je me base bien sûre sur le résultat que tu prétend obtenir : et dans ce que as dit je ne vois rien d'anormal).

______________________________________________________________________
0
cs_christophedlr Messages postés 267 Date d'inscription samedi 3 janvier 2004 Statut Membre Dernière intervention 23 août 2023 5
19 févr. 2011 à 18:29
Oups j'ai oublié une information, en fait le vrai problème est que dans les blocs imbriqués, le premier bloc, le second etc. ont exactement la même information alors que j'ai une requête pour chercher le bloc, une autre pour les liens présent à l'intérieur. J'ai donc supposé que le problème venait de ce tag qu'il laisse (je ne sais pas pourquoi d'ailleurs).

Je te file un fichier ZIP contenant le fichier PHP et HTML concernant mon problème à savoir que dans un bloc imbriqué, tout les blocs parents auront les mêmes données même si ils doivent avoir des données différentes. Je t'ai rajouté aussi le fichier SQL pour les tables, ce qui te permet de voir comment mes tables sont construites si tu veux faire un essai par rapport à mon code.

En fait, la table des blocs contient juste son nom, et le nom d'un module (vide si le bloc aura des liens et non un module). La table des menus elle, contient tout les liens avec le numéro ID du bloc auquel le lien appartient.
En tan normal, si un lien est affecté au second bloc, il sera affiché que sur le second, mais là en pratique il affiche aussi sur le premier bloc chose que je ne veux pas bien sur.

Et pourtant ma requête (celle dans la table des menus), va chercher uniquement les liens du bloc concerné par la précédente requête. J'en ai donc conclus à un bug dans le moteur et comme j'ai le tag qui est là alors qu'il devrait pas l'être, j'ai pensé que c'était ça.


P.S : Cela dit même si le tag n'est pas responsable du problème, il est pas sensé être là, mais la priorité est qu'il me mette pas les mêmes données dans tout les blocs, juste ceux qui doivent les avoir.


Merci pour ton aide.
0
phpAnonyme Messages postés 392 Date d'inscription mercredi 28 octobre 2009 Statut Membre Dernière intervention 23 mars 2012 55
19 févr. 2011 à 19:27
Je te file un fichier ZIP contenant le fichier PHP et HTML

Je n'ai rien reçu et je préfère pas. La communauté doit pouvoir visualiser les avancés etc.

Ceci dit on va quand même essayer de t'aider dans ta tâche avec les infos que tu as fourni.
______________________________________________________________________
0
phpAnonyme Messages postés 392 Date d'inscription mercredi 28 octobre 2009 Statut Membre Dernière intervention 23 mars 2012 55
19 févr. 2011 à 19:56
Bien, à la fin de la méthode assign_block_vars() pourquoi concataner $contentblock et $this->allcontentblock[$block]
$this->contentfile[$template] = preg_replace('#\<!--BLOCK_'.$block.'--\>(.+)\<!--/BLOCK_'.$block.'--\>#sU',
$contentblock.$this->allcontentblock[$block], $this->contentfile[$template]);
Car en faisant ça, tu fais modifications + sujet d'origine




______________________________________________________________________
0
cs_christophedlr Messages postés 267 Date d'inscription samedi 3 janvier 2004 Statut Membre Dernière intervention 23 août 2023 5
19 févr. 2011 à 21:37
En faisant cela je peux dans une boucle appeler de nouveau assign_block_vars pour parser de nouveau le bloc. C'est ce qui permet par exemple d'afficher la liste des membres (c'est un bloc qui à chaque passage dans la boucle, va remplacer les variables du bloc par leur valeur, dans l'exemple la liste des membres. Remettre donc le bloc permet à nouveau de le parser).


Je ne comprend pas ta phrase : Je n'ai rien reçu et je préfère pas. La communauté doit pouvoir visualiser les avancés etc.

Que veux-tu dire par là ? Le ZIP m'évite de devoir copier/coller tout le code des fichiers concernés, donc je ne vois pas où la communauté peut pas consulter puisque je fournis le lien.
0
phpAnonyme Messages postés 392 Date d'inscription mercredi 28 octobre 2009 Statut Membre Dernière intervention 23 mars 2012 55
20 févr. 2011 à 14:36
En faisant cela je peux dans une boucle appeler de nouveau assign_block_vars pour parser de nouveau le bloc.

Oui je l'ai bien compris mais pourquoi ?? C'est une opération que j'ai envie de qualifier de non convenable puisque tu as déjà un résultat avec $matches(tu comprendra).

Je ne comprend pas ta phrase : Je n'ai rien reçu et je préfère pas. La communauté doit pouvoir visualiser les avancés etc.

Que veux-tu dire par là ? Le ZIP m'évite de devoir copier/coller tout le code des fichiers concernés, donc je ne vois pas où la communauté peut pas consulter puisque je fournis le lien.
Je ne fais pas de l'assistanat mais je propose mon aide bénévolement et sans obligation, quand tu me dis tiens le zip de mes fichiers alors que je ne l'ai pas demandé(sisi rappel toi je n'est demandé que le résultat affiché) et alors quand toute franchise je n'ai pas fraîchement envie(et surtout par manque de temps) de me lancer dans le décryptage de tes codes(d'autant que ceux-ci n'ont pas l'air très parlantes - dans la logique), j'ai l'impression que tu me force la main même si ce n'est peut être pas le cas. Voilà c'est dit !

Tu as un manque de temps pour poser les choses qu'on te demande ??
et donc tu refile le tout et qu'on ce démerde, c'est ça ??

Par ailleurs, je confirme que je n'ai rien reçu et qu'il n'y a aucun lien en tous cas venant de ta pars sur cette page !! ni même en MP ! Donc non toute la communauté ne peut en profiter.


Ton moteur n'est pas très optimisé, voir mal conçu. Tiens je t'ai fais un exemple, comme j'ai pas le temps de répondre et d'expliquer tu essaiera de comprendre :
<?php
class Template
{
private $contentfile; //Contenu des fichiers ouverts
private $parsecode =  array();
private $fileName;

public function __construct($contentfile, $file)
{
$this->filename = $file;
$this->contentfile=$contentfile;
}

function assign_block_vars($blockName, $vars)
{	
if(empty($array))
return false;

$tempStock = '';
if(preg_match('#\<!--BLOCK_'.$blockName.'--\>(.+)\<!--/BLOCK_'.$blockName.'--\>#sU', $this->contentfile, $matches) )
foreach($vars as $key => $value) {
$tempStock .= preg_replace('/\{'.$blockName.'.'.$key.'\}/', $value, $matches[1]);
}
$tempStock = preg_replace('#\<!--BLOCK_(.+)--\>(.+)\<!--/BLOCK_(.+)--\>#sU', '', $tempStock);

return $this->parsecode[$this->filename][] = $tempStock;
}

function display($fileName)
{
echo implode('',$this->parsecode[$fileName]);
}


}

$titles = array('Titre A', 'Titre B', 'Titre C');				
$articles = array(array('art1.1', 'art1.2', 'art1.3'), 
  array('art2.1', 'art2.2', 'art2.3'), 
  array('art3.1', 'art3.2', 'art3.3')
  );

$contenu_recuperer = '

<!--BLOCK_A-->
 {A.title} 

<!--BLOCK_B-->
[ {B.art}]

<!--/BLOCK_B-->	
<!--/BLOCK_A-->	


';


$tpl  = new Template($contenu_recuperer, 'index.tpl');

for ($i = 0; $i < sizeof($titles); $i++) {
    $tpl->assign_block_vars('A', array('title' => strval($titles[$i]) ));

    for ($j=0; $j < sizeof($articles); $j++)
$tpl->assign_block_vars('B', array('art' => strval($articles[$i][$j]) ));
}

$tpl->display('index.tpl');
?>







______________________________________________________________________
0
phpAnonyme Messages postés 392 Date d'inscription mercredi 28 octobre 2009 Statut Membre Dernière intervention 23 mars 2012 55
20 févr. 2011 à 15:19
Il y a une petite erreur à la 1ere ligne dans la méthode assign_block_vars(), la variable c'est $vars et non $array, j'ai oublié de la changer

______________________________________________________________________
0
cs_christophedlr Messages postés 267 Date d'inscription samedi 3 janvier 2004 Statut Membre Dernière intervention 23 août 2023 5
20 févr. 2011 à 17:07
Tu ne comprend pas ce que je veux dire. Pour afficher la liste des membres par exemple, avec un moteur de template tu n'as qu'une seule possibilité : un bloc, c'est un ensemble de variables (symbolisés ici par {NOM.VAR}), qui vont être remplacé par le moteur de template. Ce dernier fait le remplacement puis remet derrière le bloc original, cela permet à la boucle de redemander à parser le bloc pour affiche les informations du membre suivant et ainsi de suite.

Pour afficher un menu qui est un bloc, contenu dans un autre bloc, ont a donc les blocs imbriqués. Mon problème est que si le premier menu doit contenir deux liens, et le second deux autres liens, ici le moteur me met les quatre liens dans chacun des menus. Et c'est là le soucis.


Pour le lien, je l'ai mis, il semble que mon post fût modifié (peut être que le lien tel qu'il était n'allait pas et qu'un modo là donc supprimé aucune idée). Tu disais ne pas comprendre ce que je voulais, avec le code tu voyais ce que je voulais faire.


J'ai un bloc qui est le type de menu avec son nom (dans ce cas là il contiendra juste des liens), le second bloc qui est dedans c'est la liste des liens du menu. Au lieu de mettre les liens du menu 1 dans le menu 1 et du 2 dans le 2, il me met ceux du 1 et du 2 dans le 1 et le 2, et c'est là où je ne comprend pas.
0
phpAnonyme Messages postés 392 Date d'inscription mercredi 28 octobre 2009 Statut Membre Dernière intervention 23 mars 2012 55
20 févr. 2011 à 18:04
J'ai un bloc qui est le type de menu avec son nom (dans ce cas là il contiendra juste des liens), le second bloc qui est dedans c'est la liste des liens du menu. Au lieu de mettre les liens du menu 1 dans le menu 1 et du 2 dans le 2, il me met ceux du 1 et du 2 dans le 1 et le 2, et c'est là où je ne comprend pas.


Si je comprend bien :

Menu acceuil
-> Lien Mon compte
-> Lien Mes sources
Menu codes
-> Lien Tous les codes
-> Lien Ajouter un code

C'est ça??


______________________________________________________________________
0
cs_christophedlr Messages postés 267 Date d'inscription samedi 3 janvier 2004 Statut Membre Dernière intervention 23 août 2023 5
20 févr. 2011 à 18:11
Oui par exemple. Sauf que lui il va plutôt m'afficher :
Menu acceuil
-> Lien Mon compte
-> Lien Mes sources
-> Lien Tous les codes
-> Lien Ajouter un code
Menu codes
-> Lien Mon compte
-> Lien Mes sources
-> Lien Tous les codes
-> Lien Ajouter un code

0
phpAnonyme Messages postés 392 Date d'inscription mercredi 28 octobre 2009 Statut Membre Dernière intervention 23 mars 2012 55
20 févr. 2011 à 18:38
Alors c'est sans doute un problème lié a ta requête SQL et/ou de la conception de ta table !

Peut-tu mettre la/requetes que tu effectue, pour réaliser le bouclage?
______________________________________________________________________
0
cs_christophedlr Messages postés 267 Date d'inscription samedi 3 janvier 2004 Statut Membre Dernière intervention 23 août 2023 5
20 févr. 2011 à 18:46
Je te copie carrément tout le fichier menu.php (fichier concerné) :
<?php

$filename = $tpl->open('menu.html');

$blockquery = $sql->query('SELECT `id`,`name` FROM `'.TABLE_BLOCK.'` ORDER BY `id` ASC');
while ( $resultblock = $sql->fetch_array($blockquery) )
{
$tpl->assign_block_vars($filename, 'SECTION', array(
'DB_NAME' => $resultblock['name']
) );

$contentquery = $sql->query('SELECT * FROM `'.TABLE_MENU.'` WHERE `block`='.$resultblock['id'].' ORDER BY `id` ASC');
while ( $resultcontent = $sql->fetch_array($contentquery) )
{
$tpl->assign_block_vars($filename, 'CONTENT', array(
'DB_URL' => $resultcontent['url'],
'DB_NAME' => $resultcontent['name']
) );
}
}

$tpl->display($filename);

?>


TABLE_BLOCK c'est ChrisSoftware_block et TABLE_MENU c'est ChrisSoftware_menu.

Au cas où, la structure des deux tables :
CREATE TABLE IF NOT EXISTS `ChrisSoftware_block` (
`id` TINYINT(3) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(50) NOT NULL,
`description` VARCHAR(255) NULL,
`module` TINYINT(3) UNSIGNED NULL
) ENGINE = MYISAM COMMENT "Blocs de menus/modules";

CREATE TABLE IF NOT EXISTS `ChrisSoftware_menu` (
`id` SMALLINT(5) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`block` TINYINT(3) UNSIGNED NOT NULL,
`name` VARCHAR(50) NULL,
`url` VARCHAR(255) NULL,
INDEX(`block`)
) ENGINE = MYISAM COMMENT "Menu";


Mais j'ai déjà copié cette requête dans la console MySQL et elle me retourne les bons résultats, j'en ai donc conclut à un bug du moteur de template, d'autant plus que les mêmes requêtes en dissociant les deux blocs (au lieu qu'ils soient imbriqués), ça fonctionne parfaitement.
0
phpAnonyme Messages postés 392 Date d'inscription mercredi 28 octobre 2009 Statut Membre Dernière intervention 23 mars 2012 55
20 févr. 2011 à 19:20
Ben c'est normal !!! pffff

Dans la deuxième requete tu fais
$contentquery = $sql->query('SELECT * FROM `'.TABLE_MENU.'` WHERE `block`='.$resultblock['id'].' ORDER BY `id` ASC');

Alors que ça devrait être :
$contentquery = $sql->query('SELECT * FROM `'.TABLE_MENU.'` WHERE `block`='.$resultblock['module'].' ORDER BY `id` ASC');


En gros beaucoup de temps perdu pour rien !!!

______________________________________________________________________
0
cs_christophedlr Messages postés 267 Date d'inscription samedi 3 janvier 2004 Statut Membre Dernière intervention 23 août 2023 5
21 févr. 2011 à 09:24
Non non, je te confirme que la requête est bonne, si je met module cela veut dire que je cherche avec un masque sur les modules. Le champ module de la table ChrisSoftware_block permet d'indiquer un éventuel module qui serait dans le menu, il n'aurait donc pas de liens c'est pourquoi par défaut ce champ est NULL.

Là dans ma requête, je cherche bien le champ block de ChrisSoftware_menu ayant pour valeur le numéro du contener (donc l'ID renvoyé par la requête sur la table ChrisSoftware_block).

Donc le problème ne vient pas de la requête. C'est bien le moteur, car si je sépare les deux blocs au lieu qu'ils soient imbriqués, il n'y a aucun soucis, c'est donc bien le moteur de template qui a un soucis.
0
phpAnonyme Messages postés 392 Date d'inscription mercredi 28 octobre 2009 Statut Membre Dernière intervention 23 mars 2012 55
21 févr. 2011 à 12:59
Ecoute soit c'est toi qui ne sait pas expliqué ton problème, soit tu ne sais pas ce que tu veux !
Moi, j'obtiens le résultat!! Celui escompté :

Menu acceuil
-> Lien Mon compte
-> Lien Mes sources
Menu codes
-> Lien Tous les codes
-> Lien Ajouter un code



Brefffffff, il te faut OBLIGATOIREMENT un champs qui fasse le lien entre ces deux tables. Alors si 'module' n'est pas ce lien comme je l'ai supposé alors il te faut crée un autre champs à cet effet.






______________________________________________________________________
0
phpAnonyme Messages postés 392 Date d'inscription mercredi 28 octobre 2009 Statut Membre Dernière intervention 23 mars 2012 55
21 févr. 2011 à 13:10
Donc le problème ne vient pas de la requête. C'est bien le moteur, car si je sépare les deux blocs au lieu qu'ils soient imbriqués, il n'y a aucun soucis, c'est donc bien le moteur de template qui a un soucis.

Au passage, j'utilise celui de l'exemple et non le tiens.



______________________________________________________________________
0
Rejoignez-nous