II. ModeliXe▲
II-A. Présentation▲
Le projet▲
ModeliXe est un projet français qui a été transmis à Rémy Trichard en 2004. La liste des contributeurs est longue et j'y ai retrouvé des noms que je connaissais : Sébastien Hordeaux (créateur de Waterpoof/PHPEdit) et Frédéric Bouchery (ancien blogueur aux billets intéressants).
Après un long séjour sur le site personnel de RémyLe site officiel temporaire de ModeliXe, le projet a maintenant migré vers SourceForgeSite officiel de ModeliXe.
Installation▲
Arborescence du projet :
- C:\Web\offline\shared\ModeliXe\ : La bibliothèque et son gestionnaire d'erreurs (ModeliXe.php et ErrorManager.php) ;
- C:\Web\offline\sites\comparatifs\modelixe\ : La classe personnalisée et le script de configuration (MyModeliXe.php et Mxconf.php) ;
- C:\Web\online\comparatifs\ : Les scripts à charger par le navigateur (modelixe-pear-nocache.php, modelixe-xml-nocache.php, modelixe-pear-cache.php et modelixe-xml-cache.php).
Avec la panoplie de contributeurs, je m'attendais à une installation sans douleur. Il n'en a malheureusement pas été ainsi…
Voici comment j'ai procédé : j'ai déclaré dans mon code les deux constantes conseillées, j'ai désactivé les vérifications automatiques et j'ai utilisé les constantes de manière explicite.
define('
MX_GENERAL_PATH
'
,
realpath(dirname(__FILE__)).
'
/
'
);
define('
MX_ERROR_PATH
'
,
'
C:/Web/offline/shared/ModeliXe/
'
);
//Initialisation de l'include_path
$os
=
((stristr(getenv('
SERVER_SOFTWARE
'
),
'
win
'
) ||
stristr(getenv('
SERVER_SOFTWARE
'
),
'
microsoft
'
))?
'
;
'
:
'
:
'
);
$path
=
((defined('
MX_GENERAL_PATH
'
))?
MX_GENERAL_PATH :
''
).
$os
.
((defined('
MX_ERROR_PATH
'
))?
MX_ERROR_PATH :
''
).
$os
.
ini_get('
include_path
'
);
ini_set('
include_path
'
,
$path
);
//Inclusion du fichier de configuration et de Error Manager
require_once('
Mxconf.php
'
);
require_once('
ErrorManager.php
'
);
//Initialisation de l'include_path
//$os = ((stristr(getenv('SERVER_SOFTWARE'), 'win') || stristr(getenv('SERVER_SOFTWARE'), 'microsoft'))? ';' : ':');
//$path = ((defined('MX_GENERAL_PATH'))? MX_GENERAL_PATH : '').$os.((defined('MX_ERROR_PATH'))? MX_ERROR_PATH : '').$os.ini_get('include_path');
//ini_set('include_path', $path);
//Inclusion du fichier de configuration et de Error Manager
require_once(MX_GENERAL_PATH.
'
Mxconf.php
'
);
require_once(MX_ERROR_PATH.
'
ErrorManager.php
'
);
Depuis PHP 5.2, les expressions rationnelles classiques POSIX ne sont plus incluses qu'en PECL (afin de laisser la place à l'extension PCRE), ce qui rend indisponible la fonction ereg() utilisée par la classe de gestion d'erreurs de ModeliXe, ErrorManager. Il faut donc apporter la modification suivante :
ereg('
http://
'
,
$url
)
preg_match('
`http://`
'
,
$url
)
Il est possible que tout le monde n'ait pas de problème avec la version originale de ModeliXe ; seulement, que j'aie rencontré un souci signifie que toutes les configurations ne supportent pas ModeliXe et qu'il est donc préférable d'apporter les modifications mentionnées ici. D'autre part, Julian Dolby serait de cet avis égalementConférence internationale PHP : Analyzable PHP…
Héritage de la classe▲
Voici la classe que je vous propose d'utiliser :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
<?php
//
// Constantes requises par ModeliXe
//
define('MX_GENERAL_PATH'
,
realpath(dirname(__FILE__
)).
'/'
);
define('MX_ERROR_PATH'
,
'C:/Web/offline/shared/ModeliXe/'
);
require(MX_ERROR_PATH.
'ModeliXe.php'
);
class
MyModeliXe extends
ModeliXe
{
var
$caching
;
function
MyModeliXe($template
,
$file
,
$caching
)
{
if
($caching
)
{
$this
->
caching =
TRUE
;
parent
::
ModeliXe($file
,
''
,
''
,
180
);
}
else
{
$this
->
caching =
FALSE
;
parent
::
ModeliXe($file
,
''
,
''
,
0
);
}
//
// Le balisage du gabarit : "pear" ou bien "xml"
//
switch
($template
)
{
case
'pear'
:
case
'xml'
:
$this
->
SetMxFlagsType($template
);
break
;
default
:
$this
->
SetMxFlagsType('xml'
);
break
;
}
//
// Configuration
//
$this
->
SetMxOutputType('xhtml'
);
$this
->
SetMxTemplatePath(MX_GENERAL_PATH.
'templates/'
.
$template
.
'/html/'
);
$this
->
SetMxCachePath(MX_GENERAL_PATH.
'templates/'
.
$template
.
'/cache/'
);
$this
->
SetMxCompress('off'
);
$this
->
SetMxModRewrite('off'
);
$this
->
SetMxSignature('off'
);
//
// Initialisation
//
$this
->
SetModeliXe();
}
function
getHtml($string
)
{
return
htmlentities($string
,
ENT_QUOTES,
'ISO-8859-1'
);
}
}
?>
Le constructeur attend le nom du gabarit (dans mon exemple, il s'agit de « pear » ou bien « xml »), du nom du fichier de gabarit (« *.tpl ») et enfin d'un booléen déterminant si l'on souhaite utiliser le cache.
Le code suivant permet de créer l'objet dans nos scripts :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
<?php
define('MX_TEMPLATE'
,
'pear'
);
// 'pear' ou 'xml'
define('MX_CACHING'
,
TRUE
);
require('C:/Web/offline/sites/comparatifs/modelixe/MyModeliXe.php'
);
$template
=
new
MyModeliXe(MX_TEMPLATE,
'home.tpl'
,
MX_CACHING);
//
// Envoi de données au gabarit
//
$template
->
MxWrite();
?>
II-B. Utilisation▲
ModeliXe propose deux manières d'écrire les éléments du gabarit : en suivant le standard proposé par le groupe PEAR (Smarty) ou bien selon son format natif : XML. C'est pour cette raison que j'ai mis en place deux gabarits.
Je vous présenterai systématiquement les deux notations (les deux gabarits). Les tests seront faits sur les deux versions également.
Les deux versions s'utilisent de la même manière dans le code PHP, grâce à notre classe dérivée.
Variables▲
Les variables sont envoyées dans des éléments « text » du gabarit au moyen de la méthode MxText().
<meta name
=
"generator"
content
=
"<mx:text id="
meta_generator"/>"
/>
<meta name
=
"description"
content
=
"<mx:text id="
meta_description"/>"
/>
<meta name
=
"keywords"
content
=
"<mx:text id="
meta_keywords"/>"
/>
<meta name
=
"MS.LOCALE"
content
=
"<mx:text id="
meta_mslocale"/>"
/>
<meta name
=
"generator"
content
=
"{text id="
meta_generator"}"
/>
<meta name
=
"description"
content
=
"{text id="
meta_description"}"
/>
<meta name
=
"keywords"
content
=
"{text id="
meta_keywords"}"
/>
<meta name
=
"MS.LOCALE"
content
=
"{text id="
meta_mslocale"}"
/>
$template
->
MxText('
meta_generator
'
,
$template
->
getHtml($meta
[
'
generator
'
]
));
$template
->
MxText('
meta_description
'
,
$template
->
getHtml($meta
[
'
description
'
]
));
$template
->
MxText('
meta_keywords
'
,
$template
->
getHtml($meta
[
'
keywords
'
]
));
$template
->
MxText('
meta_mslocale
'
,
$template
->
getHtml($meta
[
'
mslocale
'
]
));
Blocs▲
<mx:
bloc id
=
"subject"
>
<div class
=
"bloc_cours"
>
<div class
=
"titre_cours"
><mx:
text id
=
"title"
/></div>
</div>
<br />
<br />
</mx
:
bloc id
=
"subject"
>
{start id="subject"}
<div class
=
"bloc_cours"
>
<div class
=
"titre_cours"
>
{text id="title"}</div>
</div>
<br />
<br />
{end id="subject"}
$sql
=
'
SELECT id, title
FROM subject
'
;
$subjects
=
mysql_query($sql
) or die(mysql_error());
while($subject
=
mysql_fetch_assoc($subjects
))
{
$template
->
MxText('
subject.title
'
,
$template
->
getHtml($subject
[
'
title
'
]
));
$template
->
MxBloc('
subject
'
,
'
loop
'
);
}
Imbrication▲
<mx:
bloc id
=
"subject"
>
<div class
=
"bloc_cours"
>
<div class
=
"titre_cours"
><mx:
text id
=
"title"
/></div>
<mx:
bloc id
=
"category"
>
<div class
=
"categorie_cours"
><mx:
text id
=
"title"
/></div>
<div class
=
"liste_cours"
>
<ul>
<mx:
bloc id
=
"tutorial"
>
<li>
<a href
=
"<mx:text id="
uri"/>"
><mx:
text id
=
"title"
/></a>
: <mx:
text id
=
"description"
/>
</li>
</mx
:
bloc id
=
"tutorial"
>
</ul>
</div>
<hr />
</mx
:
bloc id
=
"category"
>
</div>
<br />
<br />
</mx
:
bloc id
=
"subject"
>
{start id="subject"}
<div class
=
"bloc_cours"
>
<div class
=
"titre_cours"
>
{text id="title"}</div>
{start id="category"}
<div class
=
"categorie_cours"
>
{text id="title"}</div>
<div class
=
"liste_cours"
>
<ul>
{start id="tutorial"}
<li>
<a href
=
"{text id="
uri"}"
>{text id="title"}</a>
: {text id="description"}
</li>
{end id="tutorial"}
</ul>
</div>
<hr />
{end id="category"}
</div>
<br />
<br />
{end id="subject"}
$sql
=
'
SELECT id, title
FROM subject
'
;
$result
=
mysql_query($sql
) or die(mysql_error());
while($subject
=
mysql_fetch_assoc($result
))
{
$template
->
MxText(
'
subject.title
'
,
$template
->
getHtml($subject
[
'
title
'
]
));
$sql
=
'
SELECT id, title
FROM category
WHERE subject_id =
'
.
$subject
[
'
id
'
];
$categories
=
mysql_query($sql
) or die(mysql_error());
while($category
=
mysql_fetch_assoc($categories
))
{
$template
->
MxText(
'
subject.category.title
'
,
$template
->
getHtml($category
[
'
title
'
]
));
$sql
=
'
SELECT id, uri, title, description
FROM tutorial
WHERE category_id =
'
.
$category
[
'
id
'
];
$tutorials
=
mysql_query($sql
) or die(mysql_error());
while($tutorial
=
mysql_fetch_assoc($tutorials
))
{
$template
->
MxText(
'
subject.category.tutorial.uri
'
,
$template
->
getHtml($tutorial
[
'
uri
'
]
));
$template
->
MxText(
'
subject.category.tutorial.title
'
,
$template
->
getHtml($tutorial
[
'
title
'
]
));
$template
->
MxText(
'
subject.category.tutorial.description
'
,
$template
->
getHtml($tutorial
[
'
description
'
]
));
$template
->
MxBloc('
subject.category.tutorial
'
,
'
loop
'
);
}
$template
->
MxBloc('
subject.category
'
,
'
loop
'
);
}
$template
->
MxBloc('
subject
'
,
'
loop
'
);
}
Alternance▲
Il nous faut utiliser la méthode déjà mentionnée ci-dessus du modulo :
<a href
=
"<mx:text id="
uri"/>"
><mx:
text id
=
"title"
/></a>
:
<span style
=
'color: <mx:text id="style"/>;'
><mx:
text id
=
"description"
/></span>
Segmentation du gabarit▲
ModeliXe a opté pour une solution similaire à celle de Smarty. En effet, le fichier de gabarit « maître » contient des blocs (en notation PEAR ou XML) qui indiquent à quel endroit il faut fusionner le gabarit externe :
{start id="header"}{end id="header"}
Le code PHP doit ensuite savoir à quel endroit il peut trouver le gabarit à fusionner :
$template
=
new MyModeliXe(MX_TEMPLATE,
'
home.tpl
'
,
MX_CACHING);
$template
->
MxBloc('
header
'
,
'
modi
'
,
$template
->
mXTemplatePath.
'
header.tpl
'
);
$template
->
MxBloc('
footer
'
,
'
modi
'
,
$template
->
mXTemplatePath.
'
footer.tpl
'
);
Le paramètre « modi » signifie que l'on souhaite remplacer le bloc du gabarit par un gabarit externe.
Les variables du gabarit fusionné sont décalées dans un espace de noms interne (le handle version ModeliXe), ici « header » :
$template
->
MxText('
header.meta_generator
'
,
$template
->
getHtml($meta
[
'
generator
'
]
));
$template
->
MxText('
header.meta_description
'
,
$template
->
getHtml($meta
[
'
description
'
]
));
$template
->
MxText('
header.meta_keywords
'
,
$template
->
getHtml($meta
[
'
keywords
'
]
));
$template
->
MxText('
header.meta_mslocale
'
,
$template
->
getHtml($meta
[
'
mslocale
'
]
));
Dans le gabarit, cette distinction est automatique. Seul le code PHP est affecté.
Gestion du cache▲
ModeliXe gère automatiquement le cache des informations dynamiques du gabarit, il n'y a donc pas à trop s'en occuper.
Cependant, il ne peut pas éviter les appels à la base de données. Il peut seulement éviter de fusionner le gabarit et les variables PHP en réutilisant le fichier mis en cache. Cela n'évite pas les appels à la base de données, or c'est l'opération la plus coûteuse.
Il nous faut donc utiliser un système permettant de savoir si le fichier est déjà en cache. Selon le cas, nous nous connecterons à la base de données ou nous réutiliserons le document existant.
if($template
->
MxCheckCache())
{
//
// Mettre ici les requêtes de récupération des données, l'envoi des données au gabarit, etc.
//
}
Cet appel est le même pour tous les segments du document, puisqu'il n'y a qu'un seul fichier de cache pour tout le document final. Cela ne nous empêche pas de pouvoir appeler cette méthode dans chacun de nos scripts, si nécessaire.
ModeliXe ne produit qu'un seul fichier de cache qui est le document complet final. Il ne semble pas en mesure de gérer le cache par parties.
II-C. Mon avis▲
Avantages▲
De nombreuses personnes connues ont participé à l'élaboration de ModeliXe, ce qui donne un a priori favorable.
Il a une gestion du cache.
Inconvénients▲
La configuration de ModeliXe repose sur des constantes du scope global plutôt que sur des constantes de classes.
Le gabarit en XML est trompeur, dans la mesure où des variables doivent parfois être insérées dans le document à l'intérieur des propriétés des balises du gabarit : pourquoi écrire ces variables avec une syntaxe XML à cet endroit ?
<meta
name
=
"generator"
content
=
"<mx:text id="
meta_generator
"/>"
/>
Conclusion▲
ModeliXe me semble peu intéressant, dans la mesure où il n'apporte pas de nouveauté par rapport aux autres solutions, le support est à l'abandon et la communauté est inexistante.
Un résumé est disponible en fin d'article.