The 2008-02-10 at 20:42 by Loïc d'Anterroches filed under News.
Juste en passant, un très bon article sur les actions dans les formulaires. Les actions par exemple sauvegarder et annuler. Ce site propose un joli paquet d’articles de qualité.
C’est en anglais, bonne lecture et ne venez pas me dire ensuite que vous venez de passer 5h à lire et que vous être maintenant à la bourre !
The 2008-02-10 at 19:32 by Loïc d'Anterroches filed under News.
Si certains d’entre vous veulent me rencontrer dans un café/resto, je serai à Copenhague du 12 au 15 et à Berlin du 16 au 17. À Berlin, je vais bien entendu aller voir mon photographe favori ou peut-être viendra t’il à la maison. À Copenhague, je vais retrouver mes anciens collègues et amis de CAPEC et Atomistix.
Cela sera dense, mais j’arriverai bien à libérer du temps pour d’autres rencontres. Si cela vous botte, laissez-moi un email sur titoo (at) users.sourceforge.net.
The 2008-02-09 at 19:29 by Loïc d'Anterroches filed under News.
et Apple ne vous le dira pas. Si vous vous souvenez, j’ai eu le plaisir de travailler pour Atomistix une société proposant un logiciel de simulation de structures atomiques. Entre autre, cela permet de faire la simulation de disques SSD. Le problème de ces disques et qu’ils ne sont pas adaptés aujourd’hui pour une utilisation quotidienne dans votre ordinateur. Ou plutôt, ils sont adaptés si vous considérez comme normal de changer de disque tous les ans.
Et oui, le grand problème de la mémoire flash est la stabilité dans le temps après un grand nombre d’opérations d’écriture. C’est d’ailleurs pour cela que les appareils utilisant de la mémoire flash utilisent des algorithmes pour écrire de manière plus ou moins aléatoire l’information sur toute la surface disponible. Cela permet par exemple de ne pas toujours utiliser la surface du début de la carte (si par exemple vous n’utilisez qu’en moyenne 50Mo de votre carte de 2Go dans votre appareil photo numérique).
La stabilité est aujourd’hui entre 10 000 et 100 000 cycles d’écriture. C’est pas énorme… Pour en savoir plus, un article intéressant sur le blog de Lenovo.
The 2008-02-07 at 22:54 by Loïc d'Anterroches filed under News.
Vous avez compris, je joue avec puppet.
Pour Céondo, je fais de l’hébergement de services web. Il faut que ces services tournent tranquillement 24h/24 et 7j/7 toute l’année. Jusque là tout va bien, c’est normal. Maintenant, que se passe t’il si votre centre de données (datacenter, le lieu où sont vos serveurs) crâme ? Vous savez, la foudre au mauvais endroit au mauvais moment, un problème hardware ou une erreur humaine.
Pour pouvoir assurer la qualité de service, il faut donc avoir une infrastructure qui repose sur au moins 2 centres.
Voici donc l’architecture que je suis en train de mettre en place.
Le but est de fonctionner ainsi :
Pour le moment, j’ai un serveur applicatif, 2 serveurs de backup et un serveur de contrôle. Je suis en train de monter un deuxième serveur applicatif dans un autre centre de données et je dois passer le serveur actuel sous contrôle du puppetmaster. Cela représente un investissement assez important mais une fois bien mis en place et testé régulièrement, cela devrait me permettre de dormir tranquillement la nuit, en sachant que si cela plante grave, mon téléphone sonne et je peux en un clique passer sur le backup ou simplement attendre un peu.
The 2008-02-07 at 13:50 by Loïc d'Anterroches filed under News.
C’est long, c’est très long d’écrire les recettes pour Puppet, mais au final c’est satisfaisant de savoir que l’on ne fait les choses qu’une fois et que par la suite il est facile de dupliquer ou mettre à jour un serveur très facilement.
Voici par exemple une recette pour PostgreSQL (il peut certainement y avoir des erreurs dedans) :
class postgresql {
package { "postgresql-8.2": ensure => installed }
group {"postgres":
ensure => present,
require => Package["postgresql-8.2"],
}
user {"postgres":
ensure => present,
require => Group["postgres"],
}
# Init the pgdata directory
file {"/home/pgdata":
owner => "postgres",
group => "postgres",
ensure => directory,
require => User["postgres"],
}
file {"/home/pgdata/main":
owner => "postgres",
group => "postgres",
ensure => directory,
require => File["/home/pgdata"],
}
exec {"initdb":
command => "/usr/lib/postgresql/8.2/bin/initdb -D /home/pgdata/main -E UTF-8",
group => "postgres",
user => "postgres",
creates => "/home/pgdata/main/base",
require => File["/home/pgdata/main"],
}
# Symlink the new pgdata directory correctly
file {"/etc/postgresql/8.2/main/pgdata":
ensure => "/home/pgdata/main",
require => Exec["initdb"],
}
# Get the configuration file
file {"/etc/postgresql/8.2/main/postgresql.conf":
owner => "postgres",
group => "postgres",
mode => 644,
source => "puppet://puppet/files/postgresql.conf",
require => File["/etc/postgresql/8.2/main/pgdata"],
}
file {"/etc/postgresql/8.2/main/pg_hba.conf":
owner => "postgres",
group => "postgres",
mode => 644,
source => "puppet://puppet/files/pg_hba.conf",
require => File["/etc/postgresql/8.2/main/pgdata"],
}
service {"postgresql-8.2":
ensure => running,
enable => true,
# check for the main cluster here
pattern => "/usr/lib/postgresql/8.2/bin/postgres -D /home/pgdata/main -c config_file=/etc/postgresql/8.2/main/postgresql.conf",
require => User["postgres"],
subscribe => [File["/etc/postgresql/8.2/main/pgdata"],
File["/etc/postgresql/8.2/main/postgresql.conf"],
File["/etc/postgresql/8.2/main/pg_hba.conf"],
Package["postgresql-8.2"]
],
}
service {"postgresql-8.2-old":
ensure => stopped,
pattern => "/usr/lib/postgresql/8.2/bin/postgres -D /var/lib/postgresql/8.2/main -c config_file=/etc/postgresql/8.2/main/postgresql.conf",
require => User["postgres"],
before => Exec["initdb"],
provider => base,
subscribe => Package["postgresql-8.2"],
}
}
Cette recette assure que le paquet de postgresql est installé et fait quelques accrobaties pour changer la position des données de /var/lib vers /home/pgdata. Ce sont ces accrobaties qui prennent du temps à définir car il faut qu’elles fonctionnent quelque soit le niveau d’installation du serveur. Par exemple, si initdb a déjà été lancé, il ne faut pas le relancer, etc…
Notez que la configuration est stockée sur mon serveur puppet, cela veut dire que si je mets à jour la configuration sur le serveur central puppet, mon serveur commandé va se mettre à jour automatiquement et redémarrer postgresql tout aussi automatiquement.
The 2008-02-06 at 12:42 by Loïc d'Anterroches filed under News.
Puppet, marionnette en Français, est un logiciel permettant de centraliser la configuration de vos serveurs.
Le principe est d’avoir un serveur central (oui, un point unique de défaillance, mais on peut toujours en avoir un autre au cas où) qui distribue les mises à jour de configuration aux autres serveurs/systèmes que vous gérez. Toutes les 30 minutes, chaque serveur va venir interroger le serveur central et vérifier si sa configuration doit changer.
Vous pouvez facilement avoir des configurations différentes pour chacun des serveurs. Par exemple, vous pouvez dire que le serveur 1.chezvous.com disposera de apache, php et mysql et le serveur 2.chezvous.com aura python, apache et mysql. Vous pourrez avoir donc 2 éléments de configuration communs pour les deux serveurs.
L’application est plutôt bien codée et facile à installer car disponible en paquets pour Debian/Ubuntu.
Je suis en train de l’utiliser pour réduire l’installation d’un nouveau serveur pour ConfOrganizer à :
En gros, 3 étapes avec le minimum d’intervention humaine.
The 2008-02-06 at 09:30 by Loïc d'Anterroches filed under News.
Pour ceux que cela intéresse, j’ai mis en paquet pour Ubuntu Gutsy le server web nginx. Téléchargez le paquet nginx_0.5.35-2ceondo1_i386.deb.
Le paquet est complètement basé sur le paquet venant de debian sid, mais j’ai changé les options de compilation pour ne pas inclure :
Le paquet est disponible sur le reacteur de Céondo. Grosso modo, ce serveur sera utilisé dans le futur pour distribuer les contributions de Céondo Ltd qui ne méritent pas un projet à part entière sur SourceForge ou équivalent.
The 2008-01-09 at 19:55 by Loïc d'Anterroches filed under News.
Comment détruire votre plan de travail. Prenez un virus de gastro bien rebel, soupoudrez la maison, mettez au lit la mère et le petit bout de chou, laissez le père assurer l’intendance. Toutes mes excuses aux uns et aux autres, cette semaine je me consacre à l’essentiel de l’essentiel. Heureusement c’est sur la bonne voie.
Pour la première fois, j’ai appris qu’un hôpital près de chez nous a interdit les visites des malades par des proches pour tenter de contrôler l’épidémie qui se répendait dans l’établissement !
The 2008-04-11 at 07:22 by Loïc d'Anterroches filed under News.
Les fêtes de fin d’année c’est chouette, c’est l’occasion de retrouver la famille et les amis d’une manière détendue et bien entendu, de bien manger et bien boire.
Je vous souhaite à toutes et tous le meilleur pour cette année à venir, qu’elle vous apporte ce que vous attendez au niveau matériel mais bien plus encore au niveau de vos relations avec vos proches, amis, famille.
Pour moi, l’année 2007 fut merveilleuse, il y a bien entendu eu des bas, mais je retiens bien plus de hauts et de plaisir avec les gens qui m’entourent qu’autre chose. Pour ce que je vois de 2008, cela risque fort d’être encore un très bon millésime.
The 2007-12-15 at 11:10 by Loïc d'Anterroches filed under News.
Selon Le Figaro, il y aura bientôt des mouchards de police sur les ordinateurs. Cette idée de mettre des logiciels espions sur les ordinateurs des particuliers a aussi été proposée en Allemagne. Cela a donné le slogan Stasi 2.0 ou Staatssicherheit version 2. La Stasi était l’organe de surveillance et contrôle de la population de l’ex RDA.
Dans tous les cas, cela me fait rire, car de toute façon, les personnes surveillées pourront toujours utiliser Linux ou Windows avec un bon logiciel anti-spyware. Par contre, cela pose réellement le problème du renseignement à l’échelle d’une vie numérique où tout un chacun peut utiliser des méthodes de cryptage de haute qualité. Que peuvent faire les services secrets qui ont un réel besoin d’avoir accès à certaines informations ? Il semble que la NSA a essayé d’influencer un nouveau standard, pour mettre en place une porte cachée, je ne sais pas ce qui se fait en France/Europe.
La question pose vraiment le problème de l’équilibre entre vie privée et sécurité et seul l’avenir nous dira quelle sera la réponse.
The 2007-11-30 at 11:41 by Loïc d'Anterroches filed under News.
Si vous avez un serveur sous Linux et que vous voulez voir l’évolution de votre configuration. Je vous conseille d’utiliser git, ce tutoriel devrait vous aider.
L’intérêt de git contrairement à CVS ou subversion, c’est qu’il est rapide, léger et surtour dans ce cas précis, il ne crée qu’un seul répertoire .git à la racine du projet que vous suivez.
Donc dans mon cas, j’ai simplement fait :
Installation et configuration de git :
# apt-get install git-core # git config --global user.name "Mon nom" # git config --global user.email moi@yourdomain.example.com
Initialisation de mon dépôt pour suivre les modifications de configuration dans /etc :
# cd /etc # git init # git add . # git commit
et maintenant, quand je modifie quelque chose dans ma configuration, je passe en root et je fais :
# git add . # git commit
Je donne un bon message pour me souvenir de ce que j’ai fait. Et voilà ! Cela veut aussi dire que si je fais un truc stupide dans ma configuration, je peux revenir facilement à la version d’avant, donc plus besoin de garder des fichiers .conf.YYYYMMDD ou .conf.back de partout.
Autre chose, quand je fais git log je peux tranquillement voir l’historique de mes modifications et donc me souvenir de ce que j’ai fait et si j’ai mis de bons commentaires, je peux aussi savoir ce qu’il me reste à faire !
Note : Toutes les commandes sont lancées en root, c’est uniquement parce que la configuration du serveur appartient à cet utilisateur.
The 2007-11-24 at 13:18 by Loïc d'Anterroches filed under News.
Message de service, je mets à jour la version de Plume CMS qui fait tourner ce site, comme je passe vers une version expérimentale, cela risque fort de bugger, ne vous inquiétez donc pas, c’est normal !
The 2008-05-13 at 19:06 by Loïc d'Anterroches filed under News.
En voulant éditer la configuration d’un groupe :
Error: Exception thrown while generating page java.lang.OutOfMemoryError: MemoryError: Unable to resize ULIST to 40: Out of memory at org.clearsilver.CS._parseFile(Native Method) at org.clearsilver.CS.parseFile(CS.java:58) at com.google.clearsilver.base.PageBase.go(PageBase.java:486) at com.google.clearsilver.base.PageServlet.handleRequest(PageServlet.java:44) at com.google.clearsilver.base.PageServlet.doGet(PageServlet.java:33) at javax.servlet.http.HttpServlet.service(HttpServlet.java:689) at javax.servlet.http.HttpServlet.service(HttpServlet.java:802) at com.google.gse.HttpConnection.runServlet(HttpConnection.java:534) at com.google.gse.HttpConnection.run(HttpConnection.java:458) at com.google.gse.DispatchQueue$WorkerThread.run(DispatchQueue.java:299)
Par contre, c’est intéressant de voir la taille de la pile et le nom des fonctions… Et manifestement, Java cela bouffe de la mémoire ! java.lang.OutOfMemoryError: MemoryError: Unable to resize ULIST to 40: Out of memory.
C’est le troll du matin :-)
The 2007-11-17 at 11:28 by Loïc d'Anterroches filed under News.
Et hop, je disais que j’avais un truc foireux dans les gabarits, le truc est parti. Maintenant, au lieu de faire un simple echo dans le gabarit, je fais un Pluf_Template_SafeEcho. Cette fonction fait la vérification suivante :
$param = (string) $param; et le passer à la moulinette htmlspecialchars.
Le changement est compatible avec l’utilisation standard actuelle des filtres. Le filtre unsafe prend une chaîne de caractères et la marque comme sûre pour l’affichage. C’est ainsi que l’on peut faire un {$form|unsafe} dans le code pour afficher le contenu d’un formulaire.
The 2007-11-17 at 10:32 by Loïc d'Anterroches filed under News.
Je disais que je devais améliorer la gestion des formulaires pour faire la génération automatique d’un formulaire pour un modèle. C’est maintenant chose faite et le résultat est déjà dans l’application exemple. Voici maintenant ce que vous pouvez faire :
public function updateItem($request, $match)
{
Pluf::loadFunction('Pluf_Shortcuts_GetObjectOr404');
Pluf::loadFunction('Pluf_Shortcuts_GetFormForModel');
$item = Pluf_Shortcuts_GetObjectOr404('Todo_Item', $match[1]);
$new_data = $item->getData();
if ($request->method == 'POST') {
$form = Pluf_Shortcuts_GetFormForModel($item, $request->POST);
if ($form->isValid()) {
$item = $form->save();
Pluf::loadFunction('Pluf_HTTP_URL_urlForView');
$url = Pluf_HTTP_URL_urlForView('Todo_Views::viewList',
array($item->list));
return new Pluf_HTTP_Response_Redirect($url);
}
} else {
$form = Pluf_Shortcuts_GetFormForModel($item, $item->getData());
}
return Pluf_Shortcuts_RenderToResponse('edititem.html',
array('page_title' => 'Edit a todo item',
'item' => $item,
'form' => $form));
}
En 14 lignes de code, vous avez l’édition complète d’un élément Todo_Item. Dans le dépôt vous avez le code documenté. C’est d’ailleurs tellement générique que cela va être possible de faire une vue standard pour l’édition d’un modèle, du CRUD. Cela va bientôt arriver…
The 2007-11-16 at 12:01 by Loïc d'Anterroches filed under News.
Là, à l’instant, je viens de tomber sur un os. Arg. Je suis en train de développer la génération automatique d’un formulaire à partir d’un modèle. Tout avance bien, sauf un petit bug dans le rendu du formulaire. Je mets donc :
{$form|debug}
dans le code de mon gabarit, histoire d’afficher le contenu du formulaire. Et là… bing : Fatal error: Call to undefined method Pluf_Form_Model. En fait, le gabarit protège automatiquement les variables, donc quand j’inclus ce code dans le gabarit, le code PHP correspondant est :
<?php echo var_export(Pluf_Template_htmlspecialchars($t->_vars['form'])); ?>
Avec Pluf_Template_htmlspecialchars qui va convertir le formulaire en chaîne de caractères et faire les échappements, puis l’export pour afficher le contenu. Cela ne marche donc pas du tout. Il faudrait pouvoir faire un échappement conditionel à la fin et non au début.
Pour le moment, soit {$var|filtre1|filtre2|filtre3}, cela correspond en PHP à echo filtre3(filtre2(filtre1(htmlspecialchars($var)))). Cela permet de faire la chose suivante : {$form|unsafe} qui va échapper le code puis le dééchapper : echo un_htmlspecialchars(htmlspecialchars($var)).
Ce qu’il faudrait, c’est savoir si un filtre ou simplement la fonction __toString d’un modèle retourne une chaîne sûre ou non. On pourrait dire que par défaut une chaîne est non sûre, mais que si la chaîne est en pratique un object Pluf_SafeString alors le contenu est sûre. Donc au lieu de faire un echo à la fin, on aurait un special echo qui automatiquement ferait la vérification et passerait à la moulinette ou pas la chaîne.
Il faut que je regarde de plus près cela…
The 2007-11-15 at 19:27 by Loïc d'Anterroches filed under News.
Hier, je faisais savoir que je n’étais pas particulièrement heureux de la gestion des URLs dans Pluf, aujourd’hui, je viens donc de fixer le problème en utilisant encore une fois une approche similaire à celle de Django.
Si vous avez regardé le code du gestionnaire des choses à faire, vous avez pu constater que l’URL d’une vue est utilisée à plusieurs endroits :
Maintenant, la définition de cet URL est à un endroit unique, la correspondance vue <-> URL.
Prenons le cas de l’ajout d’une chose à faire, la vue correspond à la méthode addItem de la class Todo_Views. Et dans la correspondance vue <-> URL on a :
$ctl[] = array('regex' => '#^/list/(\d+)/item/add/$#',
'priority' => 4,
'base' => Pluf::f('todo_base'),
'model' => 'Todo_Views',
'method' => 'addItem');
L’URL en pratique n’est défini que par une expression régulière : #^/list/(\d+)/item/add/$#. Vous pouvez voir le parenthèse qui capture l’id de la liste dans laquelle la chose à faire va être ajouté. Quand je veux utiliser cet URL dans l’action de mon formulaire, je me retrouve avec cette expression régulière et l’id de la liste.
L’expression régulière ici est faite pour extraire l’id de la liste étant donné un URL. On a donc :
/list/23/item/add/ + regex = id de la liste (23)
Maintenant je veux :
/list/23/item/add/.
J’ai donc créé une fonction Pluf_HTTP_URL_buildReverseUrl($url_regex, $params=array()) qui, étant donné l’expression régulière de l’URL et les paramêtres qui seraient extraits par cette expression régulière, reconstitue l’URL.
Donc maintenant, pour obtenir l’URL d’une vue dans le code, je fais simplement :
$url = Pluf_HTTP_URL_urlForView('Todo_Views::addItem', array($list->id));
Cela va directement chercher l’expression régulière dans la définition des vues courantes et passer le tout à mon fonction qui va reconstituer l’URL. Dans un gabarit, c’est tout aussi simple :
<form method="POST" action="{url 'Todo_Views::addItem', array($list.id)}">
Le mieux maintenant, c’est que j’ai défini une fonction qui permet de prendre la correspondance vues <-> URLs d’une application, d’ajouter un préfixe et ainsi de pouvoir l’inclure au sein d’une autre application.
Si vous regardez maintenant le code de l’application exemple, il n’y a presque plus de redondance. La seule chose qui reste à faire, c’est d’extraire du modèle de données Todo_Item ou Todo_List un formulaire de création ou de modification. Pour le moment, il faut encore les définir manuellement et ce n’est pas bien. Voilà du travail pour demain !
The 2007-11-14 at 21:36 by Loïc d'Anterroches filed under News.
Finalement, je viens de mettre à jour l’application de démonstration de Pluf. C’est un gestionnaire de todo lists. Les choses à retenir sont les suivantes :
Le code est divisé en 3 parties :
Je ne suis pas content de la gestion des URLs. Suivez un peu les commentaires de la discussion sur Pluf et Jelix et vous comprendrez vite. Dans le cas de Pluf l’URL est codé à la fois dans la gestion des URLs et dans les vues. Ce n’est pas bien, cela casse le principe de non duplication de l’information. Je vais devoir améliorer ce point dans les jours à venir.
The 2007-11-12 at 20:26 by Loïc d'Anterroches filed under News.
Un lecteur m’a posé la question de savoir que choisir entre Jelix et Pluf. Je n’ai pas de réponse toute faite, car le choix d’un framework est une question de goût. Voici par contre mon avis. Il est bien entendu biaisé puisque je suis le créateur de Pluf. Voici donc une présentation de Pluf et quelques points très limités de Jelix. Je ne connais que peu Jelix.
L’histoire de Pluf est étroitement liée avec mon utilisation du framework Django écrit en Python. En effet, j’ai eu besoin de développer une application complexe avec la contrainte de devoirs utiliser PHP. Je ne pouvais pas utiliser un autre langage. J’ai alors décidé de réimplémenter les éléments que j’appréciais (et apprécie toujours) de Django en PHP.
Avec Pluf vous avez un ORM qui permet de facilement faire des choses genre :
$auteur = new Auteur(); $auteur->nom = 'Loïc'; $auteur->create(); $article = new MonArticle(); $article->titre = 'Mon titre'; $article->contenu = 'Ici un long contenu...'; $article->auteur = $auteur; $article->create(); // Maintenant on recherche les articles écrits par // cet auteur. $articles = $auteur->get_monarticle_list(); assert($articles[0]->id == $article->id);
Les class Auteur et MonArticle doivent simplement étendre la
class de base Pluf_Model. Cela vous donne directement le stockage
possible dans une base de données SQLite, MySQL ou
PostgreSQL.
Après l’ORM, vous avez des vues pour afficher les données et un
controlleur pour faire la sélection de la vue en fonction de
l’URL. Par exemple, vous pouvez dire que l’URL /article/32/
correspond à la méthode afficherArticle de votre class
MesVues. Vous avez un contrôle complet des URL et de leur format
car vous les définissez avec une simple expression régulière. Voici un
extrait :
$ctl[] = array('regex' => '#^/article/(\d+)/$#',
'priority' => 4,
'model' => 'MesVues',
'method' => 'afficherArticle');
La priorité permet de mettre en avant les URL les plus utilisés pour éviter de passer à travers toutes les expressions régulières.
Maintenant pour afficher une page, on peut simplement mettre dans la méthode afficherArticle :
function afficherArticle($request, $match)
{
$article = new MonArticle($match[0]);
$ct = $article->title."\n\n".$article->contenu;
return new Pluf_HTTP_Response($ct, 'text/plain');
}
Voici une méthode très simple qui renvoie même pas de l’HTML, mais simplement le titre et le contenu de l’article. Il n’y a même pas de vérification si l’article demandé existe. Pour faire le contrôle on peut utiliser un raccourci.
function afficherArticle($request, $match)
{
Pluf::loadFunction('Pluf_Shortcuts_GetObjectOr404');
$article = Pluf_Shortcuts_GetObjectOr404('MonArticle', $match[0]);
$ct = $article->title."\n\n".$article->contenu;
return new Pluf_HTTP_Response($ct, 'text/plain');
}
Dans ce cas là, cela voudrait dire que si l’article n’existe pas dans la base de données, une exception de type 404 va être lancée et une erreur 404 sera affichée, sinon la page normale sera affichée.
Le fait d’avoir un objet $request et un objet Pluf_HTTP_Response permet d’avoir des méthodes pour modifier la requête avant la vue et modifier la réponse après la vue. Ce sont les middlewares, ils permettent de faire la gestion des sessions, la validation du code, afficher des informations de debuggage, etc.
Pluf est très léger et permet de facilement utiliser des librairies venant de PEAR.
Avec ceci, vous avez la base de Pluf. Pluf n’impose rien d’autre et en fait vous n’avez même pas besoin d’utiliser tous ces éléments, vous pouvez utiliser juste l’ORM ou juste le dispatcher. Pluf est très léger et généralement vous aurez un process d’environ 2 Mo pour une vue avec l’ORM, le dispatcher, etc.
Maintenant, ce que j’aime dans JELIX. En fait, 2 choses, le système de templates. Tellement sympa que je l’ai repris et étendu pour l’utiliser dans Pluf. L’autre, c’est le principe d’un objet réponse qui assure que la réponse sera toujours comme voulu soit de l’HTML, XML ou Jason.
Le problème que j’ai avec JELIX (note que j’utilise des composants développés par Laurent Jouanneau dont j’apprécie la qualité du code) c’est l’utilisation importante des fichier XML pour ensuite générer dynamiquement des fichiers PHP (alors que PHP 5 permet de faire cela proprement et facilement sans passer par XML) ainsi que l’utilisation importante de conventions qui je trouve "personellement" lourdes :
Par exemple pour supporter un site avec de multiples langues, on se retrouve dans le code avec :
ma_fonction ()
{
$chaine = jLocale::get("bar~foo.buttons.save");
}
là où avec Pluf on a simplement:
ma_fonction ()
{
$chaine = __('Sauvegarder');
}
Par ailleurs l’utilisation importante de ce concept de selecteurs rend le code pour moi difficile à lire et surtout cela devient difficile de faire cohabiter des modules venant de différents auteurs car il faut alors maintenir une configuration pour Jelix et une pour les autres modules qui utilisent normalement des chemins normaux vers les fichiers.
L’autre chose qui m’ennuie c’est le fait d’imposer une structure très particulière pour la position des fichiers .php sur le serveur comment gérer cela avec les modules venant d’autres frameworks ou de PEAR ? C’est possible mais cela ajoute de la complexité.
Dans le cas de Pluf. Une classe MonProject_MaClasse est simplement
dans le fichier MonProjet/MaClasse.php avec le répertoire MonProjet
dans un répertoire qui est dans le PATH de PHP. Mais on peut toujours
faire un "include_once ‘/mon/fichier/class.php’". C’est d’ailleurs la
convention retenue par PEAR pour la version 2 de PEAR.
Maintenant, l’important c’est d’essayer les deux en faisant une petite application. Cela permet de "sentir" si on aime ou pas. En effet, c’est souvent beaucoup une question de goût…
The 2007-11-06 at 10:48 by Loïc d'Anterroches filed under News.
Aujourd’hui, je codais tranquillement quand tout d’un coup, ma validation automatique de mes pages avec tidy me dit :
Warning: <img> escaping malformed URI reference
Oups, étonnant comme message d’erreur. Je regarde mon code :
<img src="logo-conforganizer.png" longdesc="Powered by ConfOrganizer, the conference management and organization software." alt="ConfOrganizer logo" />
Tout semble normal. J’enlève l’attribut longdesc et voilà que l’erreur disparaît. En fait, l’attribut longdesc est un lien vers une information contenant plus de détails sur l’image. Bon, alors comme je ne souhaite pas créer une page pour chacune de mes descriptions, j’ai décidé d’inclure le contenu du lien dans le lien avec le protocole data.
Le résultat :
<img src="logo-conforganizer.png" longdesc="data:text/html;charset=utf-8,Powered%20by%20ConfOrganizer%2C%20the%20conference%20management%20and%20organization%20software." alt="ConfOrganizer logo" />
Si vous voulez en savoir plus sur data: Wikipédia parle du schéma data.