Les fonctions de
WikiNi manipulant des données relatives à des pages pourraient gagner à sélectionner, positivement ou négativement, les pages sur lesquelles elles portent leur action (je ne sais pas si je suis très clair).
En d'autres termes, il peut être intéressant de généraliser deux paramètres à toutes les fonctions :
- un paramètre "linked_to" permettant de faire porter l'action sur un ensemble particulier de page : les pages liées à une (ou plusieurs ?) pages données. En d'autre termes il s'agit d'étendre la notion de rétrolien à toutes les fonctions. Par exemple, {{textsearch linked_to="LaDocumentation"}} permet d'effectuer une recherche uniquement dans les pages de la documentation.
- un paramètre "exclude" permettant d'exclure des pages d'une fonction donnée. Par exemple si j'exclue la page PagePersonnelleEtPriveeDeCharlesNepote? lors d'un appel à l'action {{recentchanges}}, cette dernière n'apparaitra pas dans la liste produite des derniers changements.
Les applications sont très nombreuses ; je vais tâcher de lister ci-dessous toutes les actions et les handler pour voir les applications possibles.
Applications pour les actions
- ActionInclude : a priori pas d'application...
- ActionListPages : pas d'application pour "linked_to" (il s'agit d'un BackLinks) ; permet d'exclure des pages de test ou des pages perso.
- ActionListUsers : ?
- ActionMyChanges : peut être utile
- ActionMyPages : peut être utile
- ActionOrphanedPages : si les pages sont orphelines "linked_to" ne sert à rien ; en revanche "exclude" peut avoir une utilité
- ActionPageIndex : idem action "listpages"
- ActionRecentChanges : la sélection est très utile pour cette action : "linked_to" permet de lister les derniers changements d'un faisceau de page (par exemple, tous les changements ayant affectés les pages de documentation) ; "exclude" permet d'exclure des pages qui n'ont aucun intérêt à faire partie des derniers changements classiques (pages de test, pages techniques, etc.)
- ActionRecentChangesRSS : idem "recentchanges"
- ActionRecentComments : idem "recentchanges"
- ActionRecentlyCommented : idem "recentchanges"
- ActionRedirect : pas d'application a priori
- ActionTextSearch : la sélection est également très utile pour cette action : "linked_to" me permet de faire une recherche sur un faisceau de page : recherche dans la documentation, recherche "exclude"
- ActionTrail : pas d'application a priori
- ActionUserSettings : pas d'application
- ActionWantedPages : peut être utile : "linked_to" permet par exemple, à un responsable d'une partie du site de vérifier les pages à créer pour la partie qu'il "gère" ; "exclude" permet d'exclure des liens pour lesquels on ne souhaite pas du tout créer de page.
Applications pour les handlers
- show : pas d'application
- referrer : possibilité de supprimer les SPAM ?
- ...
Solution 1 : intégration de la sélection dans chaque requête SQL
Pour que cela soit efficace, il faudrait que ces fonctions soient intégrées au coeur de
WikiNi. On peut partir du code proposé par
ProgFou pour améliorer la fonction recentchanges (quelques modifications cosmétiques par mes soins) :
<?php
function LoadRecentlyChanged($limit=50, $exclude="")
{
$limit= (int) $limit;
if ($pages = $this->LoadAll("select tag, time, user, owner from ".$this->config["table_prefix"]."pages where latest = 'Y' and comment_on = ''".$this->QueryMakeExclude($exclude)." order by time desc limit $limit"))
{
foreach ($pages as $page)
{
$this->CachePage($page);
}
return $pages;
}
}
function QueryMakeExclude($exclude, $field="tag")
{
if (!$exclude) return "";
$tags = explode(";", $exclude);
foreach ($tags as $key => $tag)
{
$tags[$key] = $field." NOT LIKE '".mysql_escape_string($tags[$key])."'";
}
// Return a string like " AND (tag NOT LIKE ThisPage and tag NOT LIKE ThisOtherPage)"
return " AND (" . implode(" and ", $tags) . ")";
}
?>
Deux choses à noter ici :
- l'appel de la fonction CachePage ne me semble pas correct à partir du moment où on ne sélectionne pas toutes les colonnes avec un select * ; cf le code d'utilisation du cache pour en déduire les conséquences qui pourraient être importantes, et le sont peut-être même déjà dans d'autres fonctions
- qu'est-ce que tu proposes ? faire un select * ou supprimer la mise en cache ? -- CharlesNepote
- dans le cas présent je propose de ne pas faire intervenir le cache : si on choisit d'exclure des pages, on ne va probablement pas les charger ensuite (ça mérite probablement une réflexion plus aprofondie)... par contre je proposerai l'inverse pour la fonction d'inclusion ! -- ProgFou
- la fonction mysql_escape_string ne protège pas du %, ce qui est ici une très bonne chose puisque cela nous permet d'exclure des pages en utilisant des masques comme %Prive% ; voir un exemple d'application sur http://tech.refer.org/
--
ProgFou
La fonction de sélection positive reste à écrire : "
QueryRefine?" ? (ou autre nom). Quelque chose dans ce goût là (non testé) :
<?php
function QueryRefine($linked_to, $field="tag")
{
// Usage : $this->QueryRefine("LaDocumentation;LesFAQ", "");
// Create the string to refine the query on pages linking to LaDocumentation and LesFAQ pages
if (!$linked_to) return "";
$result = Array();
foreach (explode(";", $linked_to) as $tag)
{
$linked_pages = $this->LoadPagesLinkingTo($tag);
foreach ($linked_pages as $linked_page)
{
$result[] = $field." LIKE '".mysql_escape_string($linked_page)."'";
}
}
// Return a string like " AND (tag LIKE ThisPage and tag LIKE ThisOtherPage)"
return " AND (" . implode(" and ", $result) . ")";
}
?>
--
CharlesNepote
Je me suis permis de ré-écrire
QueryRefine... ;-)
À noter que chez moi la fonction
LoadPagesLinkingTo accepte aussi un paramètre
exclude. --
ProgFou
- A quoi ça sert puisqu'on a déjà une fonction d'exclusion avec QueryMakeExclude ? -- CharlesNepote
- Je voulais dire que chez moi cette fonction fait aussi appel à QueryMakeExclude, mais je viens de me rendre compte que je n'utilisais pas cette fonctionnalité... Par contre c'était codé directement dans la fonction BackLinks et je l'ai donc simplifiée en recentrant l'exclusion dans le moteur du Wiki. -- ProgFou
J'aimerais bien qu'on essaye d'avancer sur ce sujet qui me paraît très intéressant. Sans se précipiter non plus. Il faudrait, je pense :
- éventuellement trouver un autre nom pour ces fonctions : QueryRefine et QueryMakeExclude me paraissent peu compréhensibles (mais je n'ai rien à proposer :(
- je propose QueryBuildLinkedPagesSelection et QueryBuildPagesExclusion -- ProgFou
- intégrer ces fonctions au CVS ; qu'en pensez-vous ?
- je pense ce n'est pas tant ces fonctions que leur utilisation qu'il étudier pour leur intégration ! ;-) les intégrer au CVS dans le corps ne nous apportera rien dans l'immédiat ; c'est surtout leur imbrication avec les fonctions de base qui apportera une valeur ajoutée -- ProgFou
- rédiger une documentation de quelques lignes pour expliquer :
- comment écrire une action utilisant les paramètres "linked_to" et "exclude"
- chez moi ça consiste tout simplement en ceci : $exclude = $this->GetParameter("exclude"); $pages = $this->LoadRecentlyChanged($max, $exclude))
- comment fabriquer une requête utilisant ces fonctions
- on peut reprendre l'exemple de l'action BackLinks, sauf qu'on utilise % au lieu des expressions régulières de perl
- déployer progressivement ces fonctions dans les actions concernées ; note : il faut que le paramètre des actions impliquant ces fonctions ait toujours le même nom
Qu'en pensez-vous ?
ProgFou, ces fonctions ont semble-t'il déjà été testé chez toi : qu'en est-il ? Y a-t'il des effets de bord ?
- Pour le exclude, aucun souci : ça marche depuis plusieurs mois, et très bien en plus ! :) Pour le linked_to, il faudra tester... -- ProgFou
--
CharlesNepote
Plus j'y repense et plus je me dit qu'un filtre placé au niveau des requêtes SQL peut rapidement devenir gênant, voir dangeureux... Que se passerait-il avec un paramètre
exlude trop long ? De même, si
linked_to contient une (ou plusieurs !) page ayant beaucoup de liens, la requête SQL va rapidement exploser ! Un calcul simple : pour chaque page on aura souvent plus de 20 caractères (par exemple avec "
and tag LIKE 'UneDoc?'"), donc pour 20 liens dans une page ça nous fait déjà 400 caractères... Il va donc faloir trouver une autre solution (sélection à un niveau plus haut), ou bien imposer des limites sur l'usage de ces options... Je continue d'y réfléchir... --
ProgFou
Solution 2 : intégration de la sélection dans la fonction LoadAll
Quelques nouvelles idées :
- implémenter ces post-opérations (sélection & transitivité sur les liens) directement dans la méthode LoadAll (ou dans une fonction appelée juste avant la sortie de celle-ci) et ajouter une méthode (SetQueryRefine ?) pour les activer/désactiver ; exemples : SetQueryRefine('exclude', '%Test%'), SetQueryRefine('linked_to', 'FAQ%'), SetQueryRefine('exclude', '') (désactivation)
- ajouter ces fonctionnalités de manière générique aux actions, comme des hook sur l'interprétation des paramètres des actions (donc dans la méthode Action, au moment de l'interprétation des paramètres) ; le paramètre exclude serait valable pour n'importe quelle action et aurait toujours pour conséquence d'appliquer l'exclusion sur tous les appels de LoadAll ; le paramètre linked_to aurait toujours pour conséquence d'appliquer la restriction aux liens dans les pages indiquées sur tous les appels de LoadAll
--
ProgFou