Parcours du blog non orthodoxe

Pour un blog perso j’avais besoin de deux choses :

  1. Que les billets soit affichés, sur la page d’accueil et dans les archives, par ordre lexicographique.
  2. Que les liens « billet suivant » et « billet précédent » suivent aussi cet ordre lexicographique.

Je précise que ce blog n’a pas de catégorie, ni mot-clés, ni pages, ni… En fait il n’a que quelques billets, une page d’archive qui sert aussi à faire une recherche et c’est tout. C’est du épuré de chez épuré, référence à mon billet d’hier.

Pour ma première condition, j’ai modifié les balise <tpl:Entries> de home.html et archive.html en ajoutant l’attribut sortby=”title?asc”. Sauf que ça ne convient pas puisque pour l’instant, les tris dans Dotclear sont alphabétiques et pas lexicographique.

Mais ça tombe bien, Dotclear permet d’ajouter des tris personnels via un behavior dont voilà le code, placé opportunément dans le fichier _public.php de mon thème :

if (!defined('DC_RC_PATH')) { return; }

$core->addBehavior('templateCustomSortByAlias',array('tribePublic','templateCustomSortByAlias'));

class tribePublic
{
	public static function templateCustomSortByAlias($alias)
	{
		// Force sorting on UTF8 collate
		$alias['post']['lextitle'] = 'post_title COLLATE utf8_unicode_ci';
	}

Je précise que ce code devrait a priori fonctionner pour SQLite et MySQL(i) ; pour PostgreSQL il faudrait aller chercher la clause idoine (c’est un poil plus compliqué), mais c’est hors de propos (pour l’instant).

Ensuite, il m’a suffit de remplacer mon sortby=”title?asc” par sortby=”lextitle?asc” dans les deux fichiers template (n’oubliez pas les balises qui se trouvent éventuellement aussi dans le <head>) pour obtenir un joli tri lexicographique de mes billets en page d’accueil et sur ma page d’archive.

<tpl:Entries sortby="lextitle?asc">
	<article>
		…
	</article>
</tpl:Entries>

Pour la seconde condition, j’intercepte et je modifie, toujours via un behavior, les paramètres qui serviront à faire la requête qui va chercher le billet suivant ou précédent. Toujours dans le fichier _public.php de mon thème, j’ai ajouté le code suivant :

…
$core->addBehavior('coreBlogBeforeGetPosts',array('tribePublic','coreBlogBeforeGetPosts'));
…
	public static function coreBlogBeforeGetPosts($params)
	{
		global $_ctx;

		if ($_ctx && $GLOBALS['core']->url->type == 'post') {
			// Check if we looking for next of previous post
			// dcBlog->getNextPost() set some specific values in $params, look for them
			if (($params['limit'] == 1) &&
				(($params['order'] == 'post_dt ASC, P.post_id ASC') || ($params['order'] == 'post_dt DESC, P.post_id DESC')))
			{
				// Switch order by and where clauses from <dt+id> to <title> (using UTF8 collate)
				$dir = ($params['order'] == 'post_dt ASC, P.post_id ASC' ? 'ASC' : 'DESC');
				$sign = ($dir == 'ASC' ? '>' : '<');
				$params['order'] = 'post_title COLLATE utf8_unicode_ci '.$dir;
				$params['sql'] = 'AND ('.
					'P.post_title COLLATE utf8_unicode_ci '.$sign.' "'.$_ctx->posts->post_title.'" '.
					') ';
			}
		}
	}
…

Ici le code est un peu plus complexe car ce behavior (coreBlogBeforeGetPosts), est appelé à plein d’endroit dans Dotclear et il faut déterminer si on est dans l’un des deux cas qui nous intéresse (billet suivant ou précédent dans un contexte de billet seul).

Pour ça, je me base sur les paramètres définis dans la fonction dcBlog->getNextPost() appelée dans les deux cas par les balises template <tpl:EntryNext> et <tpl:EntryPrevious>. C’est pas parfait[1], mais ça fait le job comme on dit !

Je vous remets le code complet ci-dessous, si jamais vous vouliez vous en inspirer chez vous :

<?php
if (!defined('DC_RC_PATH')) { return; }

$core->addBehavior('templateCustomSortByAlias',array('tribePublic','templateCustomSortByAlias'));
$core->addBehavior('coreBlogBeforeGetPosts',array('tribePublic','coreBlogBeforeGetPosts'));

class tribePublic
{
	public static function templateCustomSortByAlias($alias)
	{
		// Force sorting on UTF8 collate
		$alias['post']['lextitle'] = 'post_title COLLATE utf8_unicode_ci';
	}

	public static function coreBlogBeforeGetPosts($params)
	{
		global $_ctx;

		if ($_ctx && $GLOBALS['core']->url->type == 'post') {
			// Check if we looking for next of previous post
			// dcBlog->getNextPost() set some specific values in $params, look for them
			if (($params['limit'] == 1) &&
				(($params['order'] == 'post_dt ASC, P.post_id ASC') || ($params['order'] == 'post_dt DESC, P.post_id DESC')))
			{
				// Switch order by and where clauses from <dt+id> to <title> (using UTF8 collate)
				$dir = ($params['order'] == 'post_dt ASC, P.post_id ASC' ? 'ASC' : 'DESC');
				$sign = ($dir == 'ASC' ? '>' : '<');
				$params['order'] = 'post_title COLLATE utf8_unicode_ci '.$dir;
				$params['sql'] = 'AND ('.
					'P.post_title COLLATE utf8_unicode_ci '.$sign.' "'.$_ctx->posts->post_title.'" '.
					') ';
			}
		}
	}
}

D’une manière générale, pour forcer le driver de base de données à utiliser le tri lexicographique dans les requêtes, pour les tris ou les tests, il faut compléter chacun des noms de champ concerné par la clause COLLATE utf8_unicode_ci — pour SQLite et MySQL(i), postgreSQL demande un peu plus de code.

Enjoy

Note

[1] Il faudra par exemple modifier les contrôles si la fonction d’origine est modifiée.

Ajouter un commentaire

Les commentaires peuvent être formatés en utilisant une syntaxe wiki simplifiée.

Ajouter un rétrolien

URL de rétrolien : https://open-time.net/trackback/13045

Haut de page