Articles plagiés par lephpfacile [Résolu]
Article paru, non publié sur Planet Libre
problème avec virtualbox
Déménagement de mon blog
Problème VBox 32/64 bits
Google Wave c'est fini ...
®om
4LW
Admin-Linux
agatzebluz
Aldevar
Another Pinky Punky
AnTav
Antistress
Antoine Meme
Antoine Millet
Antonin Moulart
archi02
arNuméral
Artisan Numérique
Asher256
Aternatik
Aurélien Bompard
Bastnic
Benkemoun
Bilbo Planet
Billux
Biscotte
Blogmotion
bochecha
botchchikii
bouleetbil
Boutor
Breizh ardente
Cairo-Dock
Cameleon
Capof's Space
Captaine74
Carl Chenet
Cedynamix
champtoussel dominique
ChEza
Chicha
Chimrod
Christophe-Marie
Clapico
Corbier
Costalfy
Creasy
CSM 'illovae' Seldon
CyberSDF
dada
dahu_fou
Damien Cougar
Damocles
Daria
David Dup
David Larlet
Davromaniak
Ddmdllt
Des nouvelles de Wikilivres
Desidia
Devil505
Dhoko
DigitalSpirit
djibux
Dorian Dd
Duchatelet
Eddy33
Edouard
Effraie
eMerzh
Emilien Macchi
Emilpoe
Emmanuel Gontcho
Emmanuel Kasper
ephase
Equinoxefr
Eric
Exceed
FACIL
Feilong
fgallaire
Finss
florentg
floruby
Fonctionerd
Framablog
François
Franck Archange
Freeblog
Full Circle Magazine
Fuse
Génération Linux
G3L
Gaëtan Tenshu
Geek de France
Geekfault
Gilir
Grégory Gutierez
Gregory Colpart
Guillaume Kulakowski
Guiona
HacKurx
Hugo
Hugues
Hyla project
Il Palazzo-sama
inalgnu
Influence PC
Jérémy Verda
Jeff
jeremy2491
jeromeg
jesuislibre
JJL
Jonathan Ernst
Jonathan Le Lous
Jopa
Jp Fox
Juky
Julien
Julius
ka.da
Kagou
kamagatos
Kate
Kiddo
KissCoolMan
Labo-Linux
LeDucDuBleuet
Lemarinel
Liberez le tux
Libfy
Libre Astux
Linalis
Littlewing
Louis Roché
lowje
Luc
Macsim
Manu Absolacom
Marco
Marty
Matao
Mathieu Comandon
Maxime Carron
McKey
meepix
Michael Zwyssig
Michauko
Mickaël
Minimumserious
Monitoring-FR
Morot
Motarion
mozillaZine-fr
Mr.Yann
MrTom
Nÿco
Naparuba
Nicofo
Nicolargo
Nicosmos
Nicoz
NiKo
nizarus
Noplay
Olivier Faurax
Olivier Prieur
OLPC France
Omega
Oncle Tom
openSyd
opossum1er
Osku
OxyRadio
Pacodastre
Paquet Fedora du Jour
Pascal Chevrel
pc-kc
Peck
Pfff
Phil
Philippe Scoffoni
Pianopenguin
Pingax
PlayOnLinux
Ploum
Pokemon_JOJO
Poupoul2
PPmarcel
ProfNoel
Rémi Samier
Raphaël Hertzog
Ravomavain
Renaud Littolff
Renault
Respawner
Retouche Libre
Ricard
Robin Millette
RollsRox
Rydgel
Saïmon
Samuel Martin
Sauthier
SckyzO
Scurz
Shnoulle
Silvyn
Skhaen
Slobberbone
Splitsch
StandarT
StephZ
Sylvain
System Linux
Taltan
Tbellemb
Tchouvince
theClimber
TheGlu
TheLinuxFr
Thibaut
Thierry Andriamirado
Thom1
Thomas Bassetto
Tigrou Damien
TitaX
toitoinebzh
Toorop
TrouveTonGull.info
Tuxargon
Tuxicoman
U-Classroom
Ubuntu les jours
Uggy
Ulrich Diplodocus
Une goutte de blog
Uselink
Vanaryon
VELCS
Vetsel
Warren Dumortier
Wattazoum
Wavemaker
Webaaz
Weedfast
Yannig
yeKcim
Yellowiscool
Yoho
Yves Gesnel
Zanko
Zic
Zippy
ZitrouilleNormalement je n'aurais pas eu grand-chose à faire des mésaventures de france.fr qui s'est lamentablement cassé la binette, et en fanfare, le 14 juillet dernier, si ce dernier n'avait pas tourné sous Drupal. Et même sachant ça, cela n'aurait pas été un sujet non plus si depuis le crash, je n'avais pas entendu mille fois la tirade du "Normal, c'est du Drupal, donc ça broute", déclinée dans tous les styles (spipien, wordpression, j'en passe, et des moins mûres).
Pour commencer, je n'ai aucune idée de la manière dont ce site a été construit ni comment il fonctionne. C'est d'ailleurs fou le peu d'information que l'on arrive à glaner sur un projet financé à grand frais sur nos deniers. Pour ce que j'ai pu trouver, le site a coûté 800 000 euros, il a été réalisé par le société modedemploi (merci à Damien Leloup pour l'astuce qui m'a permis de le vérifier), une société très réputée dans le monde Drupal... et l'ensemble tournerait sur 12 machines (je n'ai pas réussi à trouver confirmation formelle de ceci).
En cherchant bien, nous avons malgré tout quelques informations. Cela commence avec une suprenante déclaration d'un responsable du gouvernement (au moins j'aurais appris qu'il y a des gens responsables dans ce gouvernement...) :
(...)lors du lancement de site, le nombre de connexions a atteint la barre des 2.000. Mercredi matin, le cap des 25.000 était franchi, provoquant la paralysie du serveur(...)
Déjà j'ai un peu de mal avec les imprécisions (ou noyage de poisson), car 25000 connexions pour une 1/2 journée (extrapolons donc à 50000 pour la journée entière du mercredi) ça veut dire quoi ? Ce sont des pages servies, des visiteurs uniques ? toutes les connexions (css, images, etc) ? Si ce sont des pages, cela me semble bien peu, et si ce sont des visiteurs uniques, ce n'est pas beaucoup plus brillant.
Sur France Intox, l'extrapolation à 50000 est confirmée par le directeur du SIG :
(...)une surprenante (...)environ 50 000 visiteurs un jour férié.
Déjà j'aime beaucoup le concept de "surprenante affluence" de 50000 visiteurs (uniques j'imagine) pour un site web international, qui représente la France, ouvert un 14 juillet, en pleine période touristique. ici le tragique flirte avec un comique qui ne va pas améliorer le moral lorsque nous recevrons notre prochain appel d'impôt.
Maintenant pour moi la notion de "visiteur unique" est sûrement très intéressante pour la mesure d'audience, mais n'a aucun intérêt d'un point de vue technique. A cet indicateur je préfère le nombre de pages servies par minutes et par serveur. J'ai constaté que pour un site de contenu, à un visiteur unique correspond en gros en moyenne 4 pages servies (je subodore que ce soit bien moins important pour france.fr, chiffrage optimiste donc).
Donc on peut imaginer que le site france.fr s'est étouffé à 200 000 pages servies par 12 machines pour la journée du mercredi 14 juillet, soit 11 pages par minutes et par serveurs (ppms)... Énorme, en effet... Sauf si les 12 bécanes sont en réalité un cluster de TO7 en nano-réseau rescapés du plan "Informatique pour tous", il y a comme un problème...
A titre de comparaison, et avant de parler d'inneficience de Drupal,

Pour être plus objectif encore, j'ai fait un coup de cat/get/wc sur les logs apache de l'une des machines (la flemme de faire une agrégation tous les logs :-). Résultat : 175000 pages services en 24h, soit donc 120 ppms.
Mes calculs reposant sur une conversion un peu foireuse entre les nombres de visiteurs communiqués et la réalité des pages servies, ils valent ce qu'ils valent, c'est à dire pas grand chose. Cependant cela prouve tout de même qu'il existe des sites Drupaux qui tournent à un bien plus important régime avec bien moins de machines. Donc l'argument de l'inefficience de Drupal me semble un peu fallacieux. Qu'un Drupal brut de coffrage tourne moins vite qu'un SPIP je n'en doute pas une seconde, mais moins vite ne signifie pas obligatoirement beaucoup plus lent.
Ensuite si l'on cherche les causes possibles, nous avons déjà l'erreur de paramétrage de Drupal (genre "Oups, on a laissé le cache en base les gars, la boulette !!") ? J'en doute, cela aurait été réglé depuis une semaine que le site est HS. Nous avons aussi comme cause possible le grand classique du drupal super lourd gavé jusqu'à la trogne de modules boulimiques enquillés à la vas-y-que-je-te-pousse ? J'en doute aussi car ce site est totalement anonyme (à ce que j'ai eu le temps d'en voir). Cela veut dire que très rapidement l'ensemble des pages se trouvent compressées dans le cache frontal et servies sans requête SQL (et ce sans même sans compter sur un reverse-proxy comme Varnish). Et si les intégrateurs avaient oublié d'installer un truc aussi basique que memcache, en une semaine, je gage que cela serait tout de même déjà fait.
Reste la solution la plus simple, l'erreur sur l'architecture technique. Ce n'est en effet pas parce que l'on enquille 12 serveurs que le site va pédaler plus vite (ce n'est pas des rameurs que l'on peut ajouter pour aller plus vite ;-). Cela peut donc être une base de données sous-dimensionnée ou en MyISSAM (problème de lock) qui étoufferait les drupaux lors de la génération initiale des pages en cache, l'oubli d'un réseau privé entre les machines du cluster, etc, etc.
Bref, désolé pour les SPIP & Wordpress (que j'apprécie au demeurant), plein de raisons possibles, mais de par le profil purement anonyme du site, ce n'est clairement pas un problème de Drupal (ou alors les auteurs de ce site sont réellement des savates, ce qui n'est pas exclu).
Je ne vais pas revenir sur mon amour immodéré pour views, ce n'est plus trop la peine. Views est ce qu'il est et il arrive parfois que le choix de l'utiliser ne se pose pas, il est là, enraciné dans un projet, indéboulonnable sous peine d'exploser les charges. Et à chaque modification un peu conséquente c'est la même histoire, un temps de dingue à trifouiller en tout sens cette interface maudite pour obtenir à grand coup de prévisualisation une requête que j'ai en tête depuis le début. Passé un moment, on se lasse d'une telle gymnastique et je me suis donc mis à chercher, sans grande conviction, un moyen d'injecter mes propres requêtes dans Views. Et la bonne nouvelle est que oui, c'est faisable !
Au delà de l'allergie atavique, de nombreuses bonnes raisons peuvent amener à vouloir injecter son propre code SQL. Déjà parce que certains exercices de style deviennent rapidement infaisables avec le générateur de requêtes (imbrications de select, group by complexes, etc.). Ensuite pour gagner du temps, car nombreux sont ceux qui vont tout de même plus vite à écrire du SQL qu'à click-clicker en tout sens. En revanche si certains comptaient par là améliorer les performances de views, qu'ils ne se fassent pas trop d'illusions. La génération de requête n'est pas, et loin de là, le poste le plus dispendieux de l'établissement. La production du markup à travers la jungle de couches passe-plat (styles de vue, style de ligne, etc.) arrive clairement en tête, et les joyeuseries dans la gestion du requêtage (voir le coup du count_query un peu plus loin) ne font que rallonger la sauce.
Avant d'attaquer l'injection de pur code SQL dans nos vues, nous allons nous arrêter sur une technique plus simple qui peut déjà permettre de dynamiser la requête de manière plus complexe qu'avec l'interface graphique. Le principe de base de cette approche est d'exploiter le hook hook_views_query_alter dont le but est de permettre à un module tiers de modifier l'objet requête ($query, classe Query) d'une vue donnée ($view, classe View) avant que le code SQL ne soit généré. Query est une classe de Views qui représente symboliquement la future requête SQL. Vous y trouverez une série de champs contenant tout ce que vous avez défini dans l'interface graphique (relationships, where, orderby, etc).
Le mieux est comme pour un hook_form_alter d'utiliser la commande var_dump(...) pour déterminer ce que vous désirez changer dans la structure. A titre d'exemple, nous pourrions ensuite faire ceci :
function mon_module_views_query_alter(&$view, &$query) {
if($view->name=="ma_vue") {
// A décommenter pour savoir ce que $query contient
// echo "<pre>"; var_dump($query); exit();
if ($_SESSION['tri_par_titre']) {
$query->orderby [0] = 'node_revisions_title DESC';
} else {
$query->orderby [0] = 'users_name ASC';
}
}Modification dynamique de l'objet Query avant génération du code SQL
Ici nous changions donc la clef de tri en fonction du contenu d'une variable de session. Le premier paramètre $views contient l'objet "vue" avec sa propriété $view->name que nous utilisons pour vérifier que l'on modifie bien la bonne vue. Le paramètre $query contient l'objet de classe Query représentant ce que vous avez défini dans l'IHM de Views. Pour info $query est tout simplement le champ $view->query. L'intérêt de le passer en paramètre m'échappe donc un peu.
Cette technique fonctionne bien, mais reste très liée à la manière dont views formalise les requêtes. Voyons comment descendre un cran plus bas niveau.
La méthode la plus simple pour injecter du vrai code SQL dans Views, est lisible ici dans la langue de Shakespeare. Le principe est d'exploiter un autre hook de l'API Views, hook_views_pre_execute. Ce hook étant invoqué juste avant l'appel à db_query nous laisse l'opportunité de changer la requête SQL qui a déjà été généré par Views à partir de l'objet Query. Voyons directement un exemple d'implémentation :
La propriété $view->build_info est un tableau de trois clefs : query pour la requête SQL, count_query pour la même requête "optimisée" (on y reviendra) pour le comptage des éléments, et query_args qui est un tableau d'arguments (penser ici aux paramètres d'une fonction db_query) appliqués aux deux précédentes requêtes.
Vous n'avez donc plus qu'à écraser la valeur de query comme dans l'exemple donné plus haut. La seule contrainte est que les champs exposés dans le select aient les mêmes noms que ceux de la requête qu'aurait produit Views. C'est encore plus vrai si vous reprenez un projet existant et que vous n'avez pas envie d'aller trifouiller dans les templates.
Du coup, un bon point de départ pour notre code SQL nous est fourni par le panneau de prévisulatisation de views. Attention cependant, la requête visible dans ce panneau n'est pas toujours strictement celle qui serait générée par Views (vive la cohérence de cet outil..). La méthode la plus fiable est un petit var_dump($query->build_info['query']) dans le "if" de l'implémentation donnée plus haut.
Si la requête que vous injectez ne renvoie pas le même nombre d'éléments que celle d'origine, vous devez en injecter une seconde dans $query->build_info['count_query']. C'est en effet à ce genre de détail que l'on constate avec effroi l'efficacité de Views qui effectue systématiquement deux requêtes, même lorsqu'aucune pagination ne justifie ce comptage.
Mais plus drole encore, lorsque vous construisez cette requête count_query, ne cherchez pas à placer là-dedans un select count(*) from ... car cela ne marcherait pas. En effet, pour une raison qui me dépasse, Views utilise le champ count_query de la manière la plus barbare qui soit, en l'encapsulant dans un select count(*) from (LA_REQUETE_COUNT_QUERY). Super sympa non ? ;-)
La méthode précédente fonctionne très bien mais me pose un petit problème. Déjà que Views est aussi lent qu'un facteur suisse, l'obliger à générer une requête que l'on sait pertinemment devoir écraser juste après n'est pas très acceptable.
Malheureusement il n'existe pas de hook dans l'API de views pour surcharger la génération du code SQL. Il va donc nous falloir tailler dans le vif et patcher. Le meilleur endroit que j'ai trouvé est le fichier includes/view.inc. Ce dernier contient la classe View, et plus particulièrement la méthode build($display_id = NULL) qui fait très exactement ce qui nous intéresse. En effet, à la ligne 649 (de la version 6.x-2.11) se trouve le code responsable de la génération du code SQL. Nous allons donc modifier cette procédure de sorte à permettre à un module tiers de sa propre mouture :
if($view->name=="ma_vue") {
// Décommenter pour voir à quoi ressemble la requête générée par Views
// echo "<pre>"; var_dump($view->build_info['query']); exit();
$view->build_info['query']=="
SELECT
node.nid AS nid,
node_revisions.title AS node_revisions_title,
users.uid AS users_uid,
users.name AS users_name
FROM bla bla bla";
}
}
En patchant Views
foreach (module_implements('views_query_alter') as $module) {
$function = $module . '_views_query_alter';
$function($this, $this->query);
}
// { YB PATCH - Don't generate queries if it's already done
if (empty($this->build_info['query'])) {
// } YB PATCH
$this->build_info['query'] = $this->query->query();
$this->build_info['count_query'] = $this->query->query(TRUE);
$this->build_info['query_args'] = $this->query->get_where_args();
// { YB PATCH - Allow a module to generate its own SQL
}
// } YB PATCH
On a fait plus complexe comme patch, avouez. Le principe est d'exploiter au maximum le hook_views_query_alter que nous avons rencontré plus haut en permettant non plus de modifier l'objet Query, mais de fournir une requête SQL tout prête. Le hack consiste donc pour Views de vérifier qu'une requête n'a pas déjà été injectée, et lancer sa propre génération le cas échéant. Notez au passage que le module une fois hacké sera plus compliqué à mettre à jour sauf si vous utilisez la technique des patchs.
Pour l'implémentation de ce hook, l'approche est strictement la même que pour la technique précédente (Ici aussi vous avez la même contrainte de devoir générer les mêmes champs en nombre et en nommage que ce qu'aurait fait views) a la nuance prés qu'il est cette fois obligatoire de générer aussi le champ count_query.
function mon_module_views_query_alter(&$view, &$query) {
if($view->name=="ma_vue") {
$view->build_info['query']="
SELECT
node.nid AS nid,
node_revisions.title AS node_revisions_title,
users.uid AS users_uid,
users.name AS users_name
FROM bla bla bla";
$view->build_info['count_query']="SELECT node.nid AS nid FROM bla bla bla";
}
}Injection du requête SQL à la place de celle de Views
Et voilà :) Simple et efficace
J'espère que cette technique vous sera aussi utile qu'à moi. Si vous n'avez aucune contrainte de performance, vous pouvez vous appuyer sur la méthode douce qui a le mérite de laisser Views intact. Mais dans le cas contraire, le petit hack est un prix bien faible à payer pour retrouver enfin sa liberté.
La semaine dernière un de mes clients m'a commandé une modification sur son site sous Drupal pour lequel il avait avec un "très léger" souci de maintenance... Ce site étant réalisé par une vraie société maîtrisant les "best-practice Drupal" (Views et tout le tremblement), j'ai pensé m'en sortir vitesse grand V... Et pourtant, six heures plus tard j'y suis encore. Tellement abasourdi que j'ai besoin de l'écrire.
Le site en question n'a rien de sorcier. Juste une base d'article tout ce qu'il y a de plus standard, et comme seul "exotisme", un menu principal piloté par une taxonomie arborescente à deux niveaux (rubrique/sous-rubrique). Le principe de navigation est assez simple, un menu principal reflète la taxonomie (menu déroulant donc):
Pour en venir au petit pépin de mon client, le site qu'on lui a livré marche parfaitement à un détail près, impossible d'ajouter une nouvelle rubrique/sous-rubrique. Pour ajouter les termes dans le vocabulaire adéquat, pas de soucis, mais pas de menu non plus. Il a bien essayé de régler le problème, tenté d'ajouter une page à la vue correspondante, tenté de faire le menu à la main, rien à faire. C'est là qu'il m'a refilé le bébé...
Souvent quand j'évoque ma manière de travailler avec Drupal, on me rétorque "Ouhlà, tu fais du code custom, c'est pas standard, faut utiliser des modules, sinon comment-ki-font-les-suivants-pour-maintenir". J'étais donc positivement curieux de voir comment un site fait par une société "state of art of drupal" était construit. Et je n'ai pas été déçu du voyage même si je ne sais pas encore bien comment je vais faire celui de retour...
Pour commencer, je me suis pris un usage extensif du module feature. Pour être honnête, j'ai une opinion assez mitigée sur ce générateur de module. Mais utilisé comme cela, je lui confère le titre d'hallucinante usine à gaz au fonctionnement proche de l'enregistreur de macro d'une suite bureautique. En fait features me rappelle le gag du développeur fou à qui on demande de corriger une fonction sensée renvoyer la somme de ses deux arguments. La fonction semble fonctionner, mais lorsqu'on lui donne à manger 1 et 1, elle renvoie 3. Le développeur fou ne tarde pas à trouver la solution en retirant fièrement 1 au résultat final...
Fatures c'est un peu cela. Drupal est in-fichu de proprement gérer un déploiement ? Et bien qu'à cela ne tienne, nous allons créer un générateur de module dans lequel on va injecter du code PHP représentant toute la configuration spécifique pour un site donné (les types de contenu, les champs cck, les vues..). Et comme en standard feature ne connait pas grand chose, on va lui coller features_extra qui va en plus permettre d'y coller les blocs, les menus et la taxo. Et comme un site drupal c'est loin de se limiter à s'y peu, pour le reste, on se démerde à coup de strongarm et du code custom... ah ahhhh !! je ne suis donc pas si seul :-)
Au final on hérite d'une chiée de module qui n'en sont pas vraiment car ils ne s'installent/désinstallent pas normalement, mais uniquement à travers l'interface de features. Ce dernier est alors censé mettre magiquement à jour le site sur lequel les dits modules sont déployés et redéployés. Sauf que c'est un peu de la magie à la Garcimore dès qu'il s'agit de choses un peu complexes comme la suppression d'un champ cck, au hasard...
Entendons nous bien, je suis parfaitement prêt à entendre l'intérêt de feature dans son concept même d'API exportable. Mais en l'état, le fait que ce ne soit qu'un module contribution et pas une api du coeur de drupal fait que sur une installation standard, 80% des paramétrages ne sont pas couvert (en gros dés que l'on sorte de CCK et Views). Du coup l'outil est trop contraignant pour un résultat bien modeste. De plus, lorsque le module généré est, comme pour ce projet, hacké jusqu'à la trogne, on perd tout l'intérêt de la manoeuvre car toute mise à jour de la feature est vouée à l'échec. Il s'agit donc plus de l'usage du module et de son périmètre qui pose problème, que sont idée de dépard.
En conclusion, les "state-of-art-of-drupal", comme moi, font du code (celui nécessaire pour tout ce que feature ne gère pas). Mais ma réelle découverte, c'est qu'ils font surtout du code pour télécommander des modules... Moi pour faire une liste, je fais une requête SQL, un db_query, un template pour formater le résultat de ma callback, et hop, à Créteil... Eux non. Eux ils utilisent Vieeeewzzzzzz, mais pas comme le pekin lambda, eux ils font du views, dans du code. Des milliers, je dis bien des milliers de ligne de code (4500 pour être exact...) pour paramétrer la génération automatique de vues, de pages associées à ces vues, de feeds, etc, etc, etc... Tout cela innocemment collé dans un hook_default_view_views...
Alors cela "fonctionne" finalement ? En bien pour commencer, nous avons un module pour faire la synchronisation entre le vocabulaire des rubriques/sous-rubriques : taxonomy_menu. Bon, pourquoi pas.
Pour gérer la page "front" et ses 3 articles mis en avant, on ajoute le module nodequeue et l'on fabrique une queue par rubrique. Là, la question est "comment fait-on pour associer une queue et une rubrique". En effet, elle est bonne la question... Car en fait on peut pas. Alors les astucieux ont écrit dans un module custom (encore du code !!) une fonction qui permet d'associer les queues au terme de vocabulaire en passant... par un tableau PHP en dur... Là pour le coup mon pov' client, il ne risquait pas de pouvoir ajouter sa rubrique de si tôt.
Ensuite, parmi les 4500 lignes de génération de vues, s'en trouve un millier dédié à fabriquer les vues/pages/feeds associés avec chaque rubrique en mettant ainsi la vue en relation avec le nodequeue qui va bien, grâce à la fonction PHP magique.
Après encore une grosse poignée de centaines lignes pour générer cette fois les vues des sous-rubriques et on est presque arrivé... Là on se dit qu'on aurait pu en profiter pour associer un menu à chaque page de vue ! Mais non, navigation_menu qui est trop super sympa !
En comme la vie serait triste si l'on n'utilisait pas context, on a rajouté quelques centaines de lignes de code supplémentaire pour générer les contextes associés à chaque rubrique et sous-rubriques...
Résultat des courses, views, nodequeue et context dans une interface graphique à faire fondre les plombs à FireFox (imaginez, une vue, 50 sous-rubriques, 100 onglets tout en ajax ;-). Interface qu'il ne faut absolument pas utiliser puisque tout est généré. Du coup l'intérêt de Views est incertain, mon client ne peux pas les modifiers et le développeur, lui s'empêtre dedans..
A ce stade, le client il est sous terre... Car finalement le manuel du "comment ajouter une nouvelle rubrique/sous-rubrique" ressemble à cela :
Maintenant je ne sais pas trop ce que je vais faire. Je me doute bien que mon client ne sera pas très ravi avec la procédure que je viens d'énoncer. La première étape va donc consister à dégager feature/strongarm pour y voir plus clair. Puis j'imagine que je vais mettre en œuvre un truc un peu plus simple.
Donc en somme, si l'idée fonctionne, une usine à gaz avec 4500 lignes de code Views d'un côté, et un petit module custom disons de 100 lignes, pas de vues, et une pure exploitation des fonctionnalités de base de drupal. Sans aucun doute moins sexy ;-)
Il ne faut pas croire que je sois de mauvais esprit ici. j'ai même un certain respect pour la personne qui a servi de référent technique sur ce projet. Mais cette aventure a été instructive à plus d'un titre. Tout d'abord cela me décomplexe lorsqu'on me dit "Bouh, tu fais du code custom, c'est moins facile à maintenir que des modules". C'est sans aucun doute vrai lorsque le besoin est assez simple pour que les modules utilisés se suffisent à eux-même. Mais pousser la logique modulaire au point de télécommander des modules avec des milliers de lignes de code, c'est aberrant. Aberrant car je suis persuadé que mon équivalent "code simple" est cent fois plus lisible (en tout cas il est 100 fois plus documenté...). Ensuite ces modules ont été pensés pour être utilisés à travers des interfaces graphiques. C'est d'ailleurs souvent dommage car j'aurais préféré, même pour views, que l'API précède l'interface pour que tout le monde soit content. Toujours est il que du coup leur paramétrage ressemble plus à un remplissage de formulaire qu'à l'utilisation d'une API propre. Enfin, purée c'est d'une lenteur tout cela. A chaque click on a l'impression de manipuler un 38 tonnes avec des baquettes de tambour... et chaque "frontpage" de rubrique génère, pour un utilisateur authentifié, pas moins de 786 requêtes SQL !!!!!!!!!!
En conclusion, ce que j'en retire c'est que context est un module qui mérite que l'on s'y penche mais je lui reproche sa dépendance à ctools absolument inutile et proprement rédhibitoire. Feature est une plaisanterie. Drupal a un problème de déploiement indéniable et même grave à l'heure d'un usage professionnel de l'outil. Feature n'est donc qu'un emplâtre sur une jambe de bois. C'est lourd, peu stable, et surtout ne couvre pas toutes les fonctionnalités obligeant à recourir à du code custom. Autant utiliser Backup & Migrate. Views est un très bon outil pour le cadre d'usage "wordpress" de drupal (non péjoratif, car j'aime beaucoup wordpress), permettant à un utilisateur peu ou moyennement expérimenté de construire son site rapidement. Dans le cadre d'un usage professionnel par des développeurs professionnels, l'utilisation de cet outil comme API ne m'a clairement pas convaincu. C'est bordélique au possible et je crains le pire lors des changements de version (en gros views3 implique tout à la poubelle, comme ce fût le cas pour Views1).
Drush shell est un projet tout simple dont le but est de fournir à drush une infrastructure d'auto-complètement utilisable notamment avec le shell bash.
<!--break-->Tout d'abord récupérez les sources du module en passant par gitweb. Il suffit ensuite de décompresser l'archive n'importe où pour peu que ce soit accessible par drush (voir la documentation pour savoir où mettre les greffons drush).
Pour tester que l'installation fonctionne, vérifiez, en tapant drush que la commande complete apparaît bien. Si tel est le cas, il ne reste plus qu'à lier le script bash fournit dans le dossier des scripts d'auto-complètement
root#chmod +x /usr/share/local/drush/modules/drush_shell/bash_completion.shroot#ln -s /usr/share/local/drush/modules/drush_shell/bash_completion.sh /etc/bash_completion.d/drush_shell.sh# optionnel, lancer le script à la main pour ne pas avoir à relancer la session. /usr/share/local/drush/modules/drush_shell/bash_completion.sh
Ceci fait, il vous faut relancer votre session pour que le script soit pris en compte (sauf si vous avez lancé le script à la main). Ensuite, vous pouvez normalement bénéficier de l'auto-complètement sur les commandes drush (ex. drush [tab]) et sur les paramètres de certaines commandes (pour l'instant pm-enabled et pm-disabled).
Parti d'une discussion avec Greg Anderson, l'idée de ce module serait à terme d'être intégré à drush. Pour cela il exporte un hook drush_command_complete que n'importe quel autre module peut implémenter pour rajouter de l'auto-complètement à ses propres commandes.
/**
* Implementation of hook_drush_command_complete().
*/
function core_completion_drush_command_complete() {
$args = func_get_args();
switch (count($args)) {
case 2 : // drush commands
switch ($args[1]) {
case 'pm-enable' :
case 'pm-disable' :
drush_bootstrap(DRUSH_BOOTSTRAP_DRUPAL_FULL);
$modules = drush_pm_get_projects();
$needed_status=in_array($args[1], array('pm-enable'))?0:1;
foreach ($modules as $name => $module) {
if ($module->type == 'module' && $module->status==$needed_status) {
$result[]=$name;
}
}
return $result;
break;
}
}
}Exemple de l'implémentation de drush_command_complete
Ce hook reçoit en paramètres tous les arguments de la ligne de commande déjà complétés en commençant par la commande drush elle-même. Ainsi si vous en êtres à drush en c[tab], il recevra drush et en mais pas c qui n'est pas encore complété. La raison à cela est que le complètement (filtrer une liste à partir du début d'un de ses membres) est gérée par le shell lui-même. Le hook fournit donc systématiquement des listes complètes (non filtrés).
Enfin, le hook, s'il reconnaît un séquence command/paramètres à prendre en charge, renverra un simple tableau de chaînes de caractères décrivant la liste des possibles. Sinon, il ne renverra rien.
Comme toujours, il ne faut pas hésiter à donner votre avis, proposer des patchs, des idées, etc.
Pathauto est un module bien pratique permettant de créer automatiquement des alias lisibles par un humain sur les URL internes de Drupal. En terme simples, http://mon_site/node/1234 deviendra par exemple accessible par http://mon_site/le_titre_de_mon_article. Je ne vais pas m'étendre plus avant sur pathauto, le principe de base étant posé et le sujet n'étant clairement pas là.
Le problème de cette automatisation des alias, est que si je change le titre de mon article, l'URL de l'article va elle aussi changer, logique en soit. Logique mais peu pratique car si l'on a distribué cette URL, par exemple via RSS, tous nos visiteurs auront droit à une jolie 404...
<!--break-->

Le hic c'est que cela ne marche pas... En effet, lorsque pour l'article sur CodeMirror un contributeur m'a fait remarquer que j'avais écrit "codeminor" dans le titre, la correction a eu pour effet de perdre l'ancienne URL malgré la sélection du mode "qui va bien". Une vérification dans la base de donnée permet de valider cela :
gaston$select dst from url_alias where src='node/367';pid | src | dst | language------+----------+------------------------------------------------+----------1376 | node/367 | articles/codemirror-lediteur-de-contenu-ultime | frgaston$Vérification des URLS pour un article
Pas cool... Et j'ai mis pas mal de temps avant de me rendre compte que le soucis ne venait en réalité pas de pathauto en lui-même, mais de sa traduction française. Plutôt qu'un long discours, je vais simplement supprimer toute traduction sur pathauto :
gaston$delete from locales_target where lid in (select lid from locales_source where location like '%pathauto%');gaston$Vérification des URLS pour un article

Une fois le bon réglage rétabli, le titre de l'article remodifié, une petite vérification en base pour vérifier que cette fois cela fonctionne :
gaston$select dst from url_alias where src='node/367';pid | src | dst | language------+----------+------------------------------------------------+----------1376 | node/367 | articles/codeminor-lediteur-de-contenu-ultime | fr1401 | node/367 | articles/codemirror-lediteur-de-contenu-ultime | frgaston$Vérification des URLS pour un article
C'est bon, cette fois j'ai bien deux alias pour le même article, celui de PID le plus élevé étant celui qui sera utilisé par défaut.
Que dire en conclusion ? Ce n'est au fond qu'un bug même si cette fois il s'agit de la traduction et que les effets peuvent être graves pour un site à forte enthropie de contenus.
Mais tout ceci me fait penser à une reflexion plus ancienne sur la notion même de paramétrage pour Drupal, et sur notre douloureuse dépendance vis à vis d'interfaces plus ou moins complexes, plus ou moins bien gaulées, avec cette très agaçante impossibilité de pouvoir visualiser, dupliquer, et déployer la configuration d'un site Drupal (et donc de ses modules)...
Peut-être est-ce mon background d'unixien qui parle ici, mais pour synthétiser, je trouve très problématique deux points en particuliers :
En somme, je pense qu'il est grand temps pour Drupal d'imposer à tous les modules une véritable API de serialisation lui permettant de lire et d'écrire ses réglages sans qu'il lui soit possible d'y déroger. C'est d'ailleurs assez choquant pour qui pratique l'architecture logiciel de laisser une telle liberté à des greffons. Maintenant, je comprend qu'il n'est pas facile de rattraper les dégâts avec plus de 3000 modules existants... Mais tant qu'à tout casser à chaque version majeur de Drupal (ce qui est aussi un vrai problème !) et ainsi obliger une quasi ré-écriture des modules, rajouter cela n'est pas la mer à boire.
De cette manière, la table variable cesserait peut-être d'être un véritable dépotoir et Drupal pourrait supprimer les réglages d'une module désinstallé. Cela implique aussi de fournir aux modules un moyen propre de gérer les données temporaires (ex. date de dernier CRON) ce qui éviterais de coller cela dans variable, une fois encore, qui fini par ressemble à la tristement célèbre registry de Windows.
Une piste de solution serait de fonctionner comme le très bien conçu gconf de Gnome. L'idée étant que toutes les applications fournissent le schema XSD de leurs réglages, et que ces réglages sont dés lors stockés au format XML. Ce ne serait le bonheur ? Vérifier les réglages d'un module d'un simple coup d'oeil ? Créer un nouveau site en répliquant les paramétrages éprouvés et testés d'un autre site par simple copier-coller ? Pouvoir stoquer toute la configuration de Drupal dans un dépôt de version comme GIT ou SVN et pouvoir déployer un site avec seulement des fichiers texte ? Et ce même sur un site existant, qui contient déjà du contenu, sans risque de perdre un article ? Un vrai déploiement quoi ! Pas une usine à gaz, à la features...
Je ne sais pas pour vous, mais moi ça me fait rêver...
Pathauto est un module bien pratique permettant de créer automatiquement des alias lisibles par un humain sur les URL internes de Drupal. En terme simples, http://mon_site/node/1234 deviendra par exemple accessible par http://mon_site/le_titre_de_mon_article. Je ne vais pas m'étendre plus avant sur pathauto, le principe de base étant posé et le sujet n'étant clairement pas là.
Le problème de cette automatisation des alias, est que si je change le titre de mon article, l'URL de l'article va elle aussi changer, logique en soit. Logique mais peu pratique car si l'on a distribué cette URL, par exemple via RSS, tous nos visiteurs auront droit à une jolie 404...

Le hic c'est que cela ne marche pas... En effet, lorsque pour l'article sur CodeMirror un contributeur m'a fait remarquer que j'avais écrit "codeminor" dans le titre, la correction a eu pour effet de perdre l'ancienne URL malgré la sélection du mode "qui va bien". Une vérification dans la base de donnée permet de valider cela :
gaston$select dst from url_alias where src='node/367';pid | src | dst | language------+----------+------------------------------------------------+----------1376 | node/367 | articles/codemirror-lediteur-de-contenu-ultime | frVérification des URLS pour un article
Pas cool... Et j'ai mis pas mal de temps avant de me rendre compte que le soucis ne venait en réalité pas de pathauto en lui-même, mais de sa traduction française. Plutôt qu'un long discours, je vais simplement supprimer toute traduction sur pathauto :
gaston$delete from locales_target where lid in (select lid from locales_source where location like '%pathauto%');Vérification des URLS pour un article

Une fois le bon réglage rétabli, le titre de l'article remodifié, une petite vérification en base pour vérifier que cette fois cela fonctionne :
gaston$select dst from url_alias where src='node/367';pid | src | dst | language------+----------+------------------------------------------------+----------1376 | node/367 | articles/codeminor-lediteur-de-contenu-ultime | fr1401 | node/367 | articles/codemirror-lediteur-de-contenu-ultime | frVérification des URLS pour un article
C'est bon, cette fois j'ai bien deux alias pour le même article, celui de PID le plus élevé étant celui qui sera utilisé par défaut.
Que dire en conclusion ? Ce n'est au fond qu'un bug même si cette fois il s'agit de la traduction et que les effets peuvent être graves pour un site à forte enthropie de contenus.
Mais tout ceci me fait penser à une reflexion plus ancienne sur la notion même de paramétrage pour Drupal, et sur notre douloureuse dépendance vis à vis d'interfaces plus ou moins complexes, plus ou moins bien gaulées, avec cette très agaçante impossibilité de pouvoir visualiser, dupliquer, et déployer la configuration d'un site Drupal (et donc de ses modules)...
Peut-être est-ce mon background d'unixien qui parle ici, mais pour synthétiser, je trouve très problématique deux points en particuliers :
En somme, je pense qu'il est grand temps pour Drupal d'imposer à tous les modules une véritable API de serialisation lui permettant de lire et d'écrire ses réglages sans qu'il lui soit possible d'y déroger. C'est d'ailleurs assez choquant pour qui pratique l'architecture logiciel de laisser une telle liberté à des greffons. Maintenant, je comprend qu'il n'est pas facile de rattraper les dégâts avec plus de 3000 modules existants... Mais tant qu'à tout casser à chaque version majeur de Drupal (ce qui est aussi un vrai problème !) et ainsi obliger une quasi ré-écriture des modules, rajouter cela n'est pas la mer à boire.
De cette manière, la table variable cesserait peut-être d'être un véritable dépotoir et Drupal pourrait supprimer les réglages d'une module désinstallé. Cela implique aussi de fournir aux modules un moyen propre de gérer les données temporaires (ex. date de dernier CRON) ce qui éviterais de coller cela dans variable, une fois encore, qui fini par ressemble à la tristement célèbre registry de Windows.
Une piste de solution serait de fonctionner comme le très bien conçu gconf de Gnome. L'idée étant que toutes les applications fournissent le schema XSD de leurs réglages, et que ces réglages sont dés lors stockés au format XML. Ce ne serait le bonheur ? Vérifier les réglages d'un module d'un simple coup d'oeil ? Créer un nouveau site en répliquant les paramétrages éprouvés et testés d'un autre site par simple copier-coller ? Pouvoir stoquer toute la configuration de Drupal dans un dépôt de version comme GIT ou SVN et pouvoir déployer un site avec seulement des fichiers texte ? Et ce même sur un site existant, qui contient déjà du contenu, sans risque de perdre un article ? Un vrai déploiement quoi ! Pas une usine à gaz, à la features...
Je ne sais pas pour vous, mais moi ça me fait rêver...
Depuis mes débuts sous Drupal (ça commence à dater un peu ;-), je cherche l'arme ultime pour éditer des contenus. Idéalement j'aurais préférer rédiger mes articles en directement HTML, mais faire cela dans un pauvre TextArea n'est pas une activité des plus joyeuses. Alors j'ai essayé les fameux éditeurs visuels (aka wysiwyg comme TinyMCE, FCKEditor, etc.) mais ces usines à gaz sont bien trop lourdes à mon goût et le code produit aussi vilain qu'ingérable. J'en ai eu tellement marre que j'en étais finalement rendu à utiliser ce bon vieux gedit, puis plus tard une combinaison entre gedit et WebDav (c'est d'ailleurs uniquement pour cela que j'avais bidouillé ce module). C'est la solution que j'ai utilisé pendant quelques années. Il y bien un bref épisode avec markitup mais rédiger des articles en HTML, sans colorisation revient peu ou prou à se passer d'éditeur.
Et puis ce matin, sans trop y croire, j'ai encore tenté une recherche chez l'ami googueule pour un html javascript editor highlighting, et cette fois, je suis tombé sur une "nouveauté", le projet codemirror...
CodeMirror est un éditeur non-wysiwyg permettant de travailler directement sur le code source d'un document comme MarkItUp. Mais à la différence de ce dernier, il ne se contente pas d'ajouter des fonctionnalités sur un simple TextArea, mais, comme TinyMCE, implémente un éditeur visuel complet qui le remplace, avec comme premier impact, la colorisation syntaxique.
Voilà donc enfin un éditeur de code HTML écrit en javascript qui est à la fois léger, performant, capable de coloriser en temps réel des documents complexes (CSS et JS embarqué dans du HTML, code PHP, etc.), autorisant la correction orthographique (un must me concernant ;-), et fournissant des aides à la rédactions basiques mais efficaces (principalement une auto-indentation du code source, la correspondance sur les balises ouvrantes/fermantes, fonction de sauvegarde par Ctrl-S, etc.). L'outil serait presque parfait s'il intégrait la possibilité de définir des raccourcis clavier pour accélérer certains balisages (gras, ancres, liens, etc.). Mais je gage qu'il ne doit pas être très sorcier de le faire évoluer dans ce sens, l'essentiel étant déjà là.
La mise en oeuvre dans Drupal est loin d'être compliquée grâce au très bon module wysiwyg. Bien évidement, codemirror ne fait pas parti de ce que ce module fournit en standard, mais ajouter de nouveaux éditeurs est terriblement simple. Cela commence par le téléchargement de codemirror et son installation dans le dossier sites/all/libraries/codemirror de sorte à ce que l'on ai bien les dossiers css, js, calés juste en dessous.
Ensuite, je me suis simplement basé sur le code source fournit pour l'éditeur markitup. J'ai donc dupliqué editors/markitup.inc en editors/codemirror.inc, rechercher/remplacer markitup par codemirror puis à modifier un peu le fichier de sorte à le faire causer avec codemirror. Cela a principalement consisté à remplacer la fonction wysiwyg_codemirror_editor par le code suivant :
/**
* Plugin implementation of hook_editor().
*/
function wysiwyg_codemirror_editor() {
$editor['codemirror'] = array(
'title' => 'codemirror',
'vendor url' => 'http://marijn.haverbeke.nl/codemirror/',
'download url' => 'http://github.com/marijnh/CodeMirror',
'library path' => wysiwyg_get_path('codemirror'),
'libraries' => array(
'' => array(
'title' => 'Source',
'files' => array('js/codemirror.js'),
),
),
'version callback' => 'wysiwyg_codemirror_version',
'themes callback' => 'wysiwyg_codemirror_themes',
'settings callback' => 'wysiwyg_codemirror_settings',
'plugin callback' => 'wysiwyg_codemirror_plugins',
'versions' => array(
'1.0' => array(
'js files' => array('codemirror.js'),
'css files' => array('codemirror.css'),
),
),
);
return $editor;
}fonction wysiwyg_codemirror_editor
Le code se comprend facilement lorsqu'il est lu après la page de documentation de codemirror.
La version 1.0 est fausse, j'ai fait cela vite, vous pouvez bien évidement améliorer cela. Dans la même veine de "vite fait mal fait", la seconde fonction modifié dans le fichier :
function wysiwyg_codemirror_version($editor) {
return "1.0"; // ben voyons... :)
}modification (sale) de la fonction wysiwyg_codemirror_version
Enfin, une version toute aussi minimaliste de wysiwyg_codemirror_settings pour fournir au code javascript le chemin vers la librairie codemirror :
function wysiwyg_codemirror_settings($editor, $config, $theme) {
$settings = array(
'root' => base_path() . $editor['library path'] . '/',
);
return $settings;
}modification de la fonction wysiwyg_codemirror_settings
Il y aurait sûrement pas mal de chose à changer mais en l'état, ça fonctionne. Deuxième étape, créer le fichier editors/js/codemirror.js sur le même principe que le précédent : en dupliquant markitup.js et en cherchant/remplaçant par codemirror. Ensuite il ne reste plus qu'à fournir le code d'attachement qui va bien :
var editor = CodeMirror.fromTextArea(params.field, {
path: settings.root+"js/",
parserfile: ["parsexml.js", "parsecss.js", "tokenizejavascript.js", "parsejavascript.js", "parsehtmlmixed.js"],
stylesheet: [settings.root+"css/xmlcolors.css",settings.root+"css/csscolors.css",settings.root+"css/jscolors.css",settings.root+"css/main.css"],
continuousScanning: 500,
autoMatchParens:true,
lineNumbers: true,
indentUnit:2,
tabMode: "spaces",
reindentOnLoad: true,
height: "350px",
})
}
/**
* Detach a single or all editors.
*/
Drupal.wysiwyg.editor.detach.codemirror = function(context, params) {
}
})(jQuery)
Vous noterez l'absence de code de détachement qu'il me reste à écrire... Il n'y a maintenant plus qu'à ajouter une petit feuille de style pour la route dans editors/css/codemirror.css histoire d'améliorer un peu le visuel :
.CodeMirror-line-numbers {
width: 2.2em;
color: #aaa;
background-color: #eee;
text-align: right;
padding-right: .3em;
font-size: 10pt;
font-family: monospace;
padding-top: .4em;
}
.editbox {
border:1px solid #CCC;
}fichier codemirror.css

Histoire de bien valider le concept, cet article a été entièrement écrit avec codemirror et force est d'avouer que toutes les fonctionnalités annoncées sont bien au rendez-vous. Tout d'abord c'est rapide, tant à l'initialisation (pas d'effet moches au lancement comme TinyMCE ou CKEditor), qu'à l'usage (pas de texte à la traîne de vos doigts). L'auto-indentation (placement automatique du curseur à la bonne position lorsque l'on ouvre une balise) et la correspondance des balises marche elles aussi très bien. Le projet est assez jeune (l'historique démarre en 2009, et nous en sommes à la 0.67), mais est plus que prometteur, en espérant qu'arrive les raccourcis clavier, et pourquoi pas, l'auto-complètement des balises.
En attendant, égoïstement, j'ai enfin trouvé mon éditeur sans compromis :)
Depuis mes débuts sous Drupal (ça commence à dater un peu ;-), je cherche l'arme ultime pour éditer des contenus. Idéalement j'aurais préférer rédiger mes articles en directement HTML, mais faire cela dans un pauvre TextArea n'est pas une activité des plus joyeuses. Alors j'ai essayé les fameux éditeurs visuels (aka wysiwyg comme TinyMCE, FCKEditor, etc.) mais ces usines à gaz sont bien trop lourdes à mon goût et le code produit aussi vilain qu'ingérable. J'en ai eu tellement marre que j'en étais finalement rendu à utiliser ce bon vieux gedit, puis plus tard une combinaison entre gedit et WebDav (c'est d'ailleurs uniquement pour cela que j'avais bidouillé ce module). C'est la solution que j'ai utilisé pendant quelques années. Il y bien un bref épisode avec markitup mais rédiger des articles en HTML, sans colorisation revient peu ou prou à se passer d'éditeur.
Et puis ce matin, sans trop y croire, j'ai encore tenté une recherche chez l'ami googueule pour un html javascript editor highlighting, et cette fois, je suis tombé sur une "nouveauté", le projet codemirror...
<!--break-->CodeMirror est un éditeur non-wysiwyg permettant de travailler directement sur le code source d'un document comme MarkItUp. Mais à la différence de ce dernier, il ne se contente pas d'ajouter des fonctionnalités sur un simple TextArea, mais, comme TinyMCE, implémente un éditeur visuel complet qui le remplace, avec comme premier impact, la colorisation syntaxique.
Voilà donc enfin un éditeur de code HTML écrit en javascript qui est à la fois léger, performant, capable de coloriser en temps réel des documents complexes (CSS et JS embarqué dans du HTML, code PHP, etc.), autorisant la correction orthographique (un must me concernant ;-), et fournissant des aides à la rédactions basiques mais efficaces (principalement une auto-indentation du code source, la correspondance sur les balises ouvrantes/fermantes, fonction de sauvegarde par Ctrl-S, etc.). L'outil serait presque parfait s'il intégrait la possibilité de définir des raccourcis clavier pour accélérer certains balisages (gras, ancres, liens, etc.). Mais je gage qu'il ne doit pas être très sorcier de le faire évoluer dans ce sens, l'essentiel étant déjà là.
La mise en oeuvre dans Drupal est loin d'être compliquée grâce au très bon module wysiwyg. Bien évidement, codemirror ne fait pas parti de ce que ce module fournit en standard, mais ajouter de nouveaux éditeurs est terriblement simple. Cela commence par le téléchargement de codemirror et son installation dans le dossier sites/all/libraries/codemirror de sorte à ce que l'on ai bien les dossiers css, js, calés juste en dessous.
Ensuite, je me suis simplement basé sur le code source fournit pour l'éditeur markitup. J'ai donc dupliqué editors/markitup.inc en editors/codemirror.inc, rechercher/remplacer markitup par codemirror puis à modifier un peu le fichier de sorte à le faire causer avec codemirror. Cela a principalement consisté à remplacer la fonction wysiwyg_codemirror_editor par le code suivant :
/**
* Plugin implementation of hook_editor().
*/
function wysiwyg_codemirror_editor() {
$editor['codemirror'] = array(
'title' => 'codemirror',
'vendor url' => 'http://marijn.haverbeke.nl/codemirror/',
'download url' => 'http://github.com/marijnh/CodeMirror',
'library path' => wysiwyg_get_path('codemirror'),
'libraries' => array(
'' => array(
'title' => 'Source',
'files' => array('js/codemirror.js'),
),
),
'version callback' => 'wysiwyg_codemirror_version',
'themes callback' => 'wysiwyg_codemirror_themes',
'settings callback' => 'wysiwyg_codemirror_settings',
'plugin callback' => 'wysiwyg_codemirror_plugins',
'versions' => array(
'1.0' => array(
'js files' => array('codemirror.js'),
'css files' => array('codemirror.css'),
),
),
);
return $editor;
}fonction wysiwyg_codemirror_editor
Le code se comprend facilement lorsqu'il est lu après la page de documentation de codemirror.
La version 1.0 est fausse, j'ai fait cela vite, vous pouvez bien évidement améliorer cela. Dans la même veine de "vite fait mal fait", la seconde fonction modifié dans le fichier :
function wysiwyg_codemirror_version($editor) {
return "1.0"; // ben voyons... :)
}modification (sale) de la fonction wysiwyg_codemirror_version
Enfin, une version toute aussi minimaliste de wysiwyg_codemirror_settings pour fournir au code javascript le chemin vers la librairie codemirror :
function wysiwyg_codemirror_settings($editor, $config, $theme) {
$settings = array(
'root' => base_path() . $editor['library path'] . '/',
);
return $settings;
}modification de la fonction wysiwyg_codemirror_settings
Il y aurait sûrement pas mal de chose à changer mais en l'état, ça fonctionne. Deuxième étape, créer le fichier editors/js/codemirror.js sur le même principe que le précédent : en dupliquant markitup.js et en cherchant/remplaçant par codemirror. Ensuite il ne reste plus qu'à fournir le code d'attachement qui va bien :
var editor = CodeMirror.fromTextArea(params.field, {
path: settings.root+"js/",
parserfile: ["parsexml.js", "parsecss.js", "tokenizejavascript.js", "parsejavascript.js", "parsehtmlmixed.js"],
stylesheet: [settings.root+"css/xmlcolors.css",settings.root+"css/csscolors.css",settings.root+"css/jscolors.css",settings.root+"css/main.css"],
continuousScanning: 500,
autoMatchParens:true,
lineNumbers: true,
indentUnit:2,
tabMode: "spaces",
reindentOnLoad: true,
height: "350px",
})
}
/**
* Detach a single or all editors.
*/
Drupal.wysiwyg.editor.detach.codemirror = function(context, params) {
}
})(jQuery)
Vous noterez l'absence de code de détachement qu'il me reste à écrire... Il n'y a maintenant plus qu'à ajouter une petit feuille de style pour la route dans editors/css/codemirror.css histoire d'améliorer un peu le visuel :
.CodeMirror-line-numbers {
width: 2.2em;
color: #aaa;
background-color: #eee;
text-align: right;
padding-right: .3em;
font-size: 10pt;
font-family: monospace;
padding-top: .4em;
}
.editbox {
border:1px solid #CCC;
}fichier codemirror.css

Histoire de bien valider le concept, cet article a été entièrement écrit avec codemirror et force est d'avouer que toutes les fonctionnalités annoncées sont bien au rendez-vous. Tout d'abord c'est rapide, tant à l'initialisation (pas d'effet moches au lancement comme TinyMCE ou CKEditor), qu'à l'usage (pas de texte à la traîne de vos doigts). L'auto-indentation (placement automatique du curseur à la bonne position lorsque l'on ouvre une balise) et la correspondance des balises marche elles aussi très bien. Le projet est assez jeune (l'historique démarre en 2009, et nous en sommes à la 0.67), mais est plus que prometteur, en espérant qu'arrive les raccourcis clavier, et pourquoi pas, l'auto-complètement des balises.
En attendant, égoïstement, j'ai enfin trouvé mon éditeur sans compromis :)
Depuis mes débuts sous Drupal (ça commence à dater un peu ;-), je cherche l'arme ultime pour éditer des contenus. Idéalement j'aurais préférer rédiger mes articles en directement HTML, mais faire cela dans un pauvre TextArea n'est pas une activité des plus joyeuses. Alors j'ai essayé les fameux éditeurs visuels (aka wysiwyg comme TinyMCE, FCKEditor, etc.) mais ces usines à gaz sont bien trop lourdes à mon goût et le code produit aussi vilain qu'ingérable. J'en ai eu tellement marre que j'en étais finalement rendu à utiliser ce bon vieux gedit, puis plus tard une combinaison entre gedit et WebDav (c'est d'ailleurs uniquement pour cela que j'avais bidouillé ce module). C'est la solution que j'ai utilisé pendant quelques années. Il y bien un bref épisode avec markitup mais rédiger des articles en HTML, sans colorisation revient peu ou prou à se passer d'éditeur.
Et puis ce matin, sans trop y croire, j'ai encore tenté une recherche chez l'ami googueule pour un html javascript editor highlighting, et cette fois, je suis tombé sur une "nouveauté", le projet codemirror...
CodeMirror est un éditeur non-wysiwyg permettant de travailler directement sur le code source d'un document comme MarkItUp. Mais à la différence de ce dernier, il ne se contente pas d'ajouter des fonctionnalités sur un simple TextArea, mais, comme TinyMCE, implémente un éditeur visuel complet qui le remplace, avec comme premier impact, la colorisation syntaxique.
Voilà donc enfin un éditeur de code HTML écrit en javascript qui est à la fois léger, performant, capable de coloriser en temps réel des documents complexes (CSS et JS embarqué dans du HTML, code PHP, etc.), autorisant la correction orthographique (un must me concernant ;-), et fournissant des aides à la rédactions basiques mais efficaces (principalement une auto-indentation du code source, la correspondance sur les balises ouvrantes/fermantes, fonction de sauvegarde par Ctrl-S, etc.). L'outil serait presque parfait s'il intégrait la possibilité de définir des raccourcis clavier pour accélérer certains balisages (gras, ancres, liens, etc.). Mais je gage qu'il ne doit pas être très sorcier de le faire évoluer dans ce sens, l'essentiel étant déjà là.
La mise en oeuvre dans Drupal est loin d'être compliquée grâce au très bon module wysiwyg. Bien évidement, codemirror ne fait pas parti de ce que ce module fournit en standard, mais ajouter de nouveaux éditeurs est terriblement simple. Cela commence par le téléchargement de codemirror et son installation dans le dossier sites/all/libraries/codemirror de sorte à ce que l'on ai bien les dossiers css, js, calés juste en dessous.
Ensuite, je me suis simplement basé sur le code source fournit pour l'éditeur markitup. J'ai donc dupliqué editors/markitup.inc en editors/codemirror.inc, rechercher/remplacer markitup par codemirror puis à modifier un peu le fichier de sorte à le faire causer avec codemirror. Cela a principalement consisté à remplacer la fonction wysiwyg_codemirror_editor par le code suivant :
/**
* Plugin implementation of hook_editor().
*/
function wysiwyg_codemirror_editor() {
$editor['codemirror'] = array(
'title' => 'codemirror',
'vendor url' => 'http://marijn.haverbeke.nl/codemirror/',
'download url' => 'http://github.com/marijnh/CodeMirror',
'library path' => wysiwyg_get_path('codemirror'),
'libraries' => array(
'' => array(
'title' => 'Source',
'files' => array('js/codemirror.js'),
),
),
'version callback' => 'wysiwyg_codemirror_version',
'themes callback' => 'wysiwyg_codemirror_themes',
'settings callback' => 'wysiwyg_codemirror_settings',
'plugin callback' => 'wysiwyg_codemirror_plugins',
'versions' => array(
'1.0' => array(
'js files' => array('codemirror.js'),
'css files' => array('codemirror.css'),
),
),
);
return $editor;
}fonction wysiwyg_codemirror_editor
Le code se comprend facilement lorsqu'il est lu après la page de documentation de codemirror.
La version 1.0 est fausse, j'ai fait cela vite, vous pouvez bien évidement améliorer cela. Dans la même veine de "vite fait mal fait", la seconde fonction modifié dans le fichier :
function wysiwyg_codemirror_version($editor) {
return "1.0"; // ben voyons... :)
}modification (sale) de la fonction wysiwyg_codemirror_version
Enfin, une version toute aussi minimaliste de wysiwyg_codemirror_settings pour fournir au code javascript le chemin vers la librairie codemirror :
function wysiwyg_codemirror_settings($editor, $config, $theme) {
$settings = array(
'root' => base_path() . $editor['library path'] . '/',
);
return $settings;
}modification de la fonction wysiwyg_codemirror_settings
Il y aurait sûrement pas mal de chose à changer mais en l'état, ça fonctionne. Deuxième étape, créer le fichier editors/js/codemirror.js sur le même principe que le précédent : en dupliquant markitup.js et en cherchant/remplaçant par codemirror. Ensuite il ne reste plus qu'à fournir le code d'attachement qui va bien :
var editor = CodeMirror.fromTextArea(params.field, {
path: settings.root+"js/",
parserfile: ["parsexml.js", "parsecss.js", "tokenizejavascript.js", "parsejavascript.js", "parsehtmlmixed.js"],
stylesheet: [settings.root+"css/xmlcolors.css",settings.root+"css/csscolors.css",settings.root+"css/jscolors.css",settings.root+"css/main.css"],
continuousScanning: 500,
autoMatchParens:true,
lineNumbers: true,
indentUnit:2,
tabMode: "spaces",
reindentOnLoad: true,
height: "350px",
})
}
/**
* Detach a single or all editors.
*/
Drupal.wysiwyg.editor.detach.codemirror = function(context, params) {
}
})(jQuery)
Vous noterez l'absence de code de détachement qu'il me reste à écrire... Il n'y a maintenant plus qu'à ajouter une petit feuille de style pour la route dans editors/css/codemirror.css histoire d'améliorer un peu le visuel :
.CodeMirror-line-numbers {
width: 2.2em;
color: #aaa;
background-color: #eee;
text-align: right;
padding-right: .3em;
font-size: 10pt;
font-family: monospace;
padding-top: .4em;
}
.editbox {
border:1px solid #CCC;
}fichier codemirror.css

Histoire de bien valider le concept, cet article a été entièrement écrit avec codemirror et force est d'avouer que toutes les fonctionnalités annoncées sont bien au rendez-vous. Tout d'abord c'est rapide, tant à l'initialisation (pas d'effet moches au lancement comme TinyMCE ou CKEditor), qu'à l'usage (pas de texte à la traîne de vos doigts). L'auto-indentation (placement automatique du curseur à la bonne position lorsque l'on ouvre une balise) et la correspondance des balises marche elles aussi très bien. Le projet est assez jeune (l'historique démarre en 2009, et nous en sommes à la 0.67), mais est plus que prometteur, en espérant qu'arrive les raccourcis clavier, et pourquoi pas, l'auto-complètement des balises.
En attendant, égoïstement, j'ai enfin trouvé mon éditeur sans compromis :)
Ceci étant dit, rien n'est encore fait, mais il semblerait que nous en prenions clairement le chemin.
Pour une part, il est clair que CVS peut être considéré à juste titre comme un gestionnaire de version pour le peu archaïque. Et il ne faut pas s'en étonner, ce système a tout de même plus de 20 ans !
Pour revenir à nos moutons, nous étions beaucoup à nous demander quand drupal.org se déciderait à basculer le dépôt des modules contribution (et du core) sur quelque chose de plus moderne, comme au hasard, subversion. Manque de bol, la grande mode des gestionnaires de version distribués est passée par là, et subversion nous est passé sous le nez au profit de GIT.
Alors qu'est-ce qu'un
La gestion décentralisée de version permet donc à chacun, y compris de petites équipes, de travailler sur les sources d'un projet tout en laissant à d'autre le choix d'intégrer ou pas les modifications au sein du projet central. C'est en quelque sorte la notion de fork généralisé. Ce concept est très intéressant pour permettre à toute une communauté de s'exprimer sur des projets d'envergure comme le noyau Linux, ou dans une moindre mesure, Drupal Core. C'est d'ailleurs Torvald, après une saga autour du gestionnaire de version propriétaire BitKeeper, qui a écrit les premières moutures de GIT. Mais
Entendons nous bien, je n'ai absolument rien contre ce type de gestionnaire, et encore moins contre GIT que j'envisage d'adopter pour mes propres projets. Mais autant je peux comprendre ce choix dans le cas du core de Drupal, autant pour la myriade de modules contribs, maintenus à grand peine par de petits développeurs dans leur coin (dont je fais parti) qui n'ont pas que cela à foutre de jongler d'un gestionnaire à l'autre. Et si l'on met ceci en perspective du fait que l'adoption massive de Subversion en entreprise est enfin concrétisée, GIT un choix que je trouve un peu... lourd.
D'autant plus lourd que ce produit, comme son concept de base, est très jeune. Cela veut dire apprendre un nouveau mode de fonctionnement pour ceux qui ont déjà eu du mal à passer à SVN, mais cela implique aussi une maturité plus faible sur des plate-formes comme