From 360c15e402b2ff98c2045ed8830f6dec152577ac Mon Sep 17 00:00:00 2001 From: x2000habouzit Date: Thu, 4 Nov 2004 13:50:44 +0000 Subject: [PATCH] new search engine --- ChangeLog | 36 ++++++---- htdocs/advanced_search.php | 14 +++- htdocs/search.php | 52 ++++++-------- include/search.classes.inc.php | 79 ++++++++++++++++++++-- templates/{search.form.tpl => search.adv.form.tpl} | 49 +++++++------- templates/search.adv.links.tpl | 52 ++++++++++++++ templates/search.quick.form.tpl | 45 ++++++++++++ templates/search.quick.tpl | 54 +++++++++++++++ templates/search.tpl | 75 ++++++++------------ 9 files changed, 333 insertions(+), 123 deletions(-) rename templates/{search.form.tpl => search.adv.form.tpl} (89%) create mode 100644 templates/search.adv.links.tpl create mode 100644 templates/search.quick.form.tpl create mode 100644 templates/search.quick.tpl diff --git a/ChangeLog b/ChangeLog index b7e7727..876a1a0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,32 +1,38 @@ ================================================================================ VERSION 0.9.2 ~20 Nov 2004 -Changes : +New : * Core : - Creation of the Plugin class. -MC - - First instance of the plugin class : class Trombi. (FS#135) -MC - Now only use iso3166 countries, no more `nationalites`. -MC - - A photo change now updates the last time the `fiche` was edited. -MC * Contacts : - - Trombino of the contacts is available ! (FS#138) -MC + - Trombino of the contacts is available. -MC + + * Search+Contacts : + - Married women are now well sorted (by their spouse name). -MC + - Nicer icons. -MC + +Bug/Wish : + + * Core : + - #135 : First instance of the plugin class : class Trombi. -MC + - #158 : A photo change updates last `fiche` edition stamp. -MC * Lists : - - Refusal message is shown on mail moderation page. (FS#138) -MC - - Now supports non-X natively. -MC + - #138 : Refusal message is shown on mail moderation page. -MC + - #161 : Now supports non-X natively -MC * Search : - - Hide SoundEX search when neither name nor second name selected. -MC - - Married women are now well sorted. -MC + - #112,113,126,133,167: google like search + some rewrite. -MC * Search+Contacts : - - Homeland is now a flag. (FS#124) -MC - - Women now have a • (no more dirty gender icons). (FS#122) -MC - - Nicer icons. -MC - + - #124 : Homeland is now a flag. -MC + - #122 : Women now have a • (no more dirty gender icons). -MC Fixes (from 0.9.1 branch) : + * Lists : - Better mails to -owners for reject/discard ops. -MC - Mailman is case sensitive, goto lowercase. -MC @@ -35,7 +41,7 @@ Fixes (from 0.9.1 branch) : ================================================================================ VERSION 0.9.1 25 Oct 2004 -Changes : +New : * Lists : - Auto-moderate/discard mails detected as SPAM by bogofilter. -MC @@ -44,7 +50,7 @@ Changes : - 1-click moderation for accept and reject cases. -MC * Usability : - - All now have title (closes: FS#99). -MC + - #99 : All now have title. -MC * NewsLetter : - Brand New NewsLetter module. -MC @@ -78,7 +84,7 @@ Fixes (from 0.9.0 branch) : ================================================================================ VERSION 0.9.0 15 Oct 2004 -Changes : +New : * First Public Release. -PoT diff --git a/htdocs/advanced_search.php b/htdocs/advanced_search.php index d195c21..7cf1b9c 100644 --- a/htdocs/advanced_search.php +++ b/htdocs/advanced_search.php @@ -18,7 +18,7 @@ * Foundation, Inc., * * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * *************************************************************************** - $Id: advanced_search.php,v 1.24 2004-11-02 07:28:33 x2000habouzit Exp $ + $Id: advanced_search.php,v 1.25 2004-11-04 13:50:44 x2000habouzit Exp $ ***************************************************************************/ require("auto.prepend.inc.php"); @@ -124,15 +124,23 @@ else { LIMIT '.$offset->value.','.$globals->search_results_per_page; $page->mysql_assign($sql, 'resultats', 'nb_resultats','nb_resultats_total'); - $nbpages = ($page->get_template_vars('nb_resultats_total')-1)/$globals->search_results_per_page; $page->assign('offsets',range(0,$nbpages)); + $page->assign('offset',$offset->value); $page->assign('url_args',$fields->get_url()); $page->assign('with_soundex',$with_soundex); $page->assign('mod_date_sort',!empty($_REQUEST['mod_date_sort'])); - $page->assign('offset',$offset->value); $page->assign('perpage',$globals->search_results_per_page); $page->assign('is_admin',has_perms()); + + if(!$page->get_template_vars('nb_resultats_total')) { + form_prepare(); + new ThrowError('il n\'existe personne correspondant à ces critères dans la base !'); + } + if($page->get_template_vars('nb_resultats_total')>800) { + new ThrowError('Recherche trop générale'); + } + } $page->run(); diff --git a/htdocs/search.php b/htdocs/search.php index 1edb12f..4807668 100644 --- a/htdocs/search.php +++ b/htdocs/search.php @@ -18,7 +18,7 @@ * Foundation, Inc., * * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * *************************************************************************** - $Id: search.php,v 1.41 2004-11-03 22:15:21 x2000habouzit Exp $ + $Id: search.php,v 1.42 2004-11-04 13:50:44 x2000habouzit Exp $ ***************************************************************************/ require("auto.prepend.inc.php"); @@ -33,35 +33,19 @@ $page->assign('advanced',0); require_once("applis.func.inc.php"); require_once("geoloc.inc.php"); -if (array_key_exists('rechercher', $_REQUEST)) { +if (array_key_exists('quick', $_REQUEST)) { $page->assign('formulaire',0); $with_soundex = !empty($_REQUEST['with_soundex']); - if ($with_soundex) { - $nameField = new - StringWithSoundexSField('name',array('r.nom1_soundex','r.nom2_soundex','r.nom3_soundex'),''); - $firstnameField = new - StringWithSoundexSField('firstname',array('r.prenom1_soundex','r.prenom2_soundex'),''); - } - else { - $nameField = new NameSField('name',array('r.nom1','r.nom2','r.nom3'),'r.nom1'); - $firstnameField = new StringSField('firstname',array('r.prenom1','r.prenom2'),'r.prenom1'); - } - $promo1Field = new PromoSField('promo1','egal1',array('r.promo'),''); - $promo2Field = new PromoSField('promo2','egal2',array('r.promo'),''); - $fields = new SFieldGroup(true,array($nameField,$firstnameField,$promo1Field,$promo2Field)); + $qSearch = new QuickSearch('quick'); + $fields = new SFieldGroup(true,array($qSearch)); - if (!$nameField->length() && !$firstnameField->length() - && empty($_REQUEST['promo1']) && empty($_REQUEST['promo2'])) + if ($qSearch->isempty()) { new ThrowError('Recherche trop générale.'); } - if (!logged() && empty($_REQUEST['prenom']) && empty($_REQUEST['nom'])) - { - new ThrowError('Il faut au moins entrer un nom ou un prenom.'); - } $offset = new NumericSField('offset'); $sql = 'SELECT SQL_CALC_FOUND_ROWS @@ -73,24 +57,18 @@ if (array_key_exists('rechercher', $_REQUEST)) { a.alias AS forlife, '.$globals->search_result_fields.' c.uid AS contact - FROM '.($with_soundex?'recherche_soundex':'recherche').' AS r + FROM '.($with_soundex?'recherche_soundex':'auth_user_md5').' AS r LEFT JOIN auth_user_md5 AS u ON (u.matricule=r.matricule) LEFT JOIN aliases AS a ON (u.user_id = a.id AND a.type="a_vie") LEFT JOIN contacts AS c ON (c.uid='.((array_key_exists('uid',$_SESSION))?$_SESSION['uid']:0).' AND c.contact=u.user_id) '.$globals->search_result_where_statement.' WHERE '.$fields->get_where_statement().' ORDER BY '.(logged() && !empty($_REQUEST['mod_date_sort']) ? 'date DESC,' :'') - .implode(',',array_filter(array($fields->get_order_statement(),'promo DESC,NomSortKey,prenom'))).' - LIMIT '.$offset->value.','.$globals->search_results_per_page; + .implode(',',array_filter(array($fields->get_order_statement(),'u.promo DESC,NomSortKey,prenom'))).' + LIMIT '.(isset($_REQUEST['lucky']) ? "1" : $offset->value.','.$globals->search_results_per_page); $page->mysql_assign($sql, 'resultats', 'nb_resultats','nb_resultats_total'); - echo mysql_error(); - if (!logged() && - $page->get_template_vars('nb_resultats_total')>$globals->public_max_search_results) - { - new ThrowError('Votre recherche a généré trop de résultats pour un affichage public.'); - } $nbpages = ($page->get_template_vars('nb_resultats_total')-1)/$globals->search_results_per_page; $page->assign('offsets',range(0,$nbpages)); $page->assign('url_args',$fields->get_url()); @@ -99,6 +77,20 @@ if (array_key_exists('rechercher', $_REQUEST)) { $page->assign('offset',$offset->value); $page->assign('perpage',$globals->search_results_per_page); $page->assign('is_admin',has_perms()); + + if (!logged() && + $page->get_template_vars('nb_resultats_total')>$globals->public_max_search_results) + { + new ThrowError('Votre recherche a généré trop de résultats pour un affichage public.'); + } + + if($page->get_template_vars('nb_resultats_total')>800) { + new ThrowError('Recherche trop générale'); + } + + if(!$page->get_template_vars('nb_resultats_total')) { + new ThrowError('il n\'existe personne correspondant à ces critères dans la base !'); + } } else $page->assign('formulaire',1); diff --git a/include/search.classes.inc.php b/include/search.classes.inc.php index 8809255..1643923 100644 --- a/include/search.classes.inc.php +++ b/include/search.classes.inc.php @@ -18,7 +18,7 @@ * Foundation, Inc., * * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * *************************************************************************** - $Id: search.classes.inc.php,v 1.29 2004-11-02 07:28:34 x2000habouzit Exp $ + $Id: search.classes.inc.php,v 1.30 2004-11-04 13:50:45 x2000habouzit Exp $ ***************************************************************************/ require_once("xorg.misc.inc.php"); @@ -49,6 +49,7 @@ $globals->search_result_where_statement = ' LEFT JOIN geoloc_pays AS gp ON (adr.pays = gp.a2) LEFT JOIN geoloc_region AS gr ON (adr.pays = gr.a2 AND adr.region = gr.region)'; + /** classe qui gère les erreurs dans les requêtes des utilisateurs finaux * passe le message d'erreur au template de page et exécute le template */ @@ -125,6 +126,75 @@ class SField { } } +class QuickSearch extends SField { + var $strings; + var $ranges; + + function QuickSearch($_fieldFormName) { + $this->fieldFormName = $_fieldFormName; + $this->get_request(); + } + + function isempty() { + return empty($this->strings) && empty($this->ranges); + } + + function get_request() { + SField::get_request(); + $s = replace_accent(trim($this->value)); + $s = preg_replace('!\d+!', ' ', $s); + $s = preg_replace('! - !', '', $s); + $this->strings = preg_split("![^a-zA-Z\-]+!",$s, -1, PREG_SPLIT_NO_EMPTY); + + $s = trim($this->value); + $s = preg_replace('! *- *!', '-', $s); + $s = preg_replace('!([<>]) *!', ' \1', $s); + $s = preg_replace('![^0-9\-><]!', ' ', $s); + $s = preg_replace('![<>\-] !', '', $s); + $ranges = preg_split('! +!', $s, -1, PREG_SPLIT_NO_EMPTY); + $this->ranges=Array(); + foreach($ranges as $r) { + if(preg_match('!^([<>]\d{4}|\d{4}(-\d{4})?)$!', $r)) $this->ranges[] = $r; + } + } + + function get_where_statement() { + $where = Array(); + foreach($this->strings as $s) { + $where[] = "(r.nom LIKE '%$s%' OR r.epouse LIKE '%$s%' OR r.prenom LIKE '%$s%')"; + } + + $wherep = Array(); + foreach($this->ranges as $r) { + if(preg_match('!^\d{4}$!', $r)) { + $wherep[] = "r.promo=$r"; + } elseif(preg_match('!^(\d{4})-(\d{4})$!', $r, $matches)) { + $p1=min(intval($matches[1]), intval($matches[2])); + $p2=max(intval($matches[1]), intval($matches[2])); + $wherep[] = "(r.promo>=$p1 AND r.promo<=$p2)"; + } elseif(preg_match('!^<(\d{4})!', $r, $matches)) { + $wherep[] = "r.promo<={$matches[1]}"; + } elseif(preg_match('!^>(\d{4})!', $r, $matches)) { + $wherep[] = "r.promo>={$matches[1]}"; + } + } + if(!empty($wherep)) $where[] = '('.join(' OR ',$wherep).')'; + return join(" AND ", $where); + } + + function get_order_statement() { + if(empty($this->strings)) return false; + $order = Array(); + foreach($this->strings as $s) { + $order[] = "(r.nom='$s' OR r.prenom='$s' OR r.epouse='$s')*100 + " + . "(r.nom LIKE '$s%' OR r.prenom LIKE '$s%' OR r.epouse LIKE '$s%')"; + } + $res = join(' + ', $order); + if($res) return "$res DESC"; + } +} + + /** classe de champ numérique entier (offset par exemple) */ class NumericSField extends SField { @@ -198,10 +268,8 @@ class RefSField extends SField { } class RefWithSoundexSField extends RefSField { - function get_request() { - parent::get_request(); - if ($this->value!='') - $this->value=soundex_fr($this->value); + function compare() { + return "='".soundex_fr($this->value)."'"; } } @@ -391,4 +459,5 @@ class SFieldGroup { return (count($url)>0)?implode('&',$url):false; } } + ?> diff --git a/templates/search.form.tpl b/templates/search.adv.form.tpl similarity index 89% rename from templates/search.form.tpl rename to templates/search.adv.form.tpl index 1408938..4f4180b 100644 --- a/templates/search.form.tpl +++ b/templates/search.adv.form.tpl @@ -17,39 +17,40 @@ * Foundation, Inc., * * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * *************************************************************************** - $Id: search.form.tpl,v 1.25 2004-11-03 22:15:22 x2000habouzit Exp $ + $Id: search.adv.form.tpl,v 1.1 2004-11-04 13:50:45 x2000habouzit Exp $ ***************************************************************************} -

- {if $advanced eq "1"} - Recherche avancée - {else} - Recherche simple - {/if} -

+

Recherche avancée

+ {if $error} -

- {$error} -

- {/if} - -{if $advanced} -

[Recherche simple]

-{else} -{min_auth level="cookie"} -

[Recherche avancée]

-{/min_auth} +

{$error}

{/if} -
- +

[Recherche simple]

+ + +
- + - + @@ -69,7 +70,6 @@ -{if $advanced eq "1"} -{/if}
Nom + + {if $smarty.request.name && !$with_soundex && $smarty.request.recherche} + + étendre par proximité sonore + + {/if} +
Prénom + + {if $smarty.request.firstname && !$with_soundex && $smarty.request.recherche} + + étendre par proximité sonore + + {/if} +
Promotion
Sexe @@ -237,7 +237,6 @@

diff --git a/templates/search.adv.links.tpl b/templates/search.adv.links.tpl new file mode 100644 index 0000000..9bbf0eb --- /dev/null +++ b/templates/search.adv.links.tpl @@ -0,0 +1,52 @@ +{*************************************************************************** + * Copyright (C) 2003-2004 Polytechnique.org * + * http://opensource.polytechnique.org/ * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * + *************************************************************************** + $Id: search.adv.links.tpl,v 1.1 2004-11-04 13:50:45 x2000habouzit Exp $ + ***************************************************************************} + + {if $do_title}

Recherche avancée

{/if} + +{if $error} +

{$error}

+{/if} + + + +{* vim:set et sw=2 sts=2 sws=2: *} diff --git a/templates/search.quick.form.tpl b/templates/search.quick.form.tpl new file mode 100644 index 0000000..a10f70f --- /dev/null +++ b/templates/search.quick.form.tpl @@ -0,0 +1,45 @@ +{*************************************************************************** + * Copyright (C) 2003-2004 Polytechnique.org * + * http://opensource.polytechnique.org/ * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * + *************************************************************************** + $Id: search.quick.form.tpl,v 1.1 2004-11-04 13:50:45 x2000habouzit Exp $ + ***************************************************************************} + +

Recherche simple

+ +{if $error}

{$error}

{/if} + + + + + + + +
+
+ +
+ {min_auth level="cookie"} +  Recherche avancée + {/min_auth} +
+ + +
+ +{* vim:set et sw=2 sts=2 sws=2: *} diff --git a/templates/search.quick.tpl b/templates/search.quick.tpl new file mode 100644 index 0000000..a901109 --- /dev/null +++ b/templates/search.quick.tpl @@ -0,0 +1,54 @@ +{*************************************************************************** + * Copyright (C) 2003-2004 Polytechnique.org * + * http://opensource.polytechnique.org/ * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * + *************************************************************************** + $Id: search.quick.tpl,v 1.1 2004-11-04 13:50:45 x2000habouzit Exp $ + ***************************************************************************} + +{include file="search.quick.form.tpl"} + +

Comment faire une recherche ?

+ +

Nom, Prenom, Promo ...

+ +

+La ligne de recherche ci-dessus accepte non seulement que des mélanges de noms et de prénoms ... +mais elle accepte de plus la syntaxe suivante pour les promos : +

+
    +
  • 1990 : signifie appartient à la promo 1990
  • +
  • 1990-2000 : signifie sur la promo 1990 à 2000
  • +
  • <1990 : signifie promos inférieures ou égales à 1990
  • +
  • >1990 : signifie promos supérieures ou égales à 1990
  • +
+

+Ainsi, rechercher tous les "Pierre" sur les promos 1980 à 1990 et sur la promo 2000 se fait avec la recherche : +[ Pierre 1980-1990 2000 ] +

+ +

Astuce pour les noms ...

+

+Parfois on ne sait plus si le nom qu'on recherche s'écrit « Lenormand », « Le Normand » ou « Le-Normand » ... +

+

+Pour éviter ce genre d'écueils, il suffit de chercher [ Le Normand ].
+En effet, le moteur de recherche va alors chercher tous les utilisateurs dont le nom contient 'Le' et 'Normand' +sans distinction de casse et sans tenir compte des accents. +

+ +{* vim:set et sw=2 sts=2 sws=2: *} diff --git a/templates/search.tpl b/templates/search.tpl index 9521846..0b1b03c 100644 --- a/templates/search.tpl +++ b/templates/search.tpl @@ -17,31 +17,22 @@ * Foundation, Inc., * * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * *************************************************************************** - $Id: search.tpl,v 1.23 2004-11-02 07:19:07 x2000habouzit Exp $ + $Id: search.tpl,v 1.24 2004-11-04 13:50:45 x2000habouzit Exp $ ***************************************************************************} {dynamic} -{if $nb_resultats_total >= 800}{assign var='error' value="Recherche trop générale."}{/if} - {if $formulaire==0 and !$error} -

- Résultats + {if !$advanced} + {include file='search.quick.form.tpl'} + {else} + {include file=search.adv.links.tpl do_title=1} + {/if} + +

+ {if $nb_resultats_total==0}Aucune{else}{$nb_resultats_total}{/if} réponse{if $nb_resultats_total>1}s{/if}.

- - - - - -
- {if $nb_resultats_total==0}Aucune{else}{$nb_resultats_total}{/if} réponse{if $nb_resultats_total>1}s{/if}. - - {if $with_soundex==0 && ($smarty.request.prenom || $smarty.request.nom)} - [ - Recherche par proximité sonore]  - {/if} - [Nouvelle recherche] -
+
{section name=resultat loop=$resultats} {if !$resultats[resultat].inscrit || $resultats[resultat].decede}
{/if} @@ -54,50 +45,44 @@ {if !$resultats[resultat].inscrit || $resultats[resultat].decede}
{/if} {/section}
- - - - - -
- {if $nb_resultats_total==0}Aucune{else}{$nb_resultats_total}{/if} réponse{if $nb_resultats_total>1}s{/if}. - - {if $with_soundex==0 && ($smarty.request.prenom || $smarty.request.nom)} - [ - Recherche par proximité sonore]  - {/if} - [Nouvelle recherche] -
+ {if $perpage < $nb_resultats_total}

{if $offset!=0} - Précédent + Précédent   {/if} {section name=offset loop=$offsets} {if $offset!=$smarty.section.offset.index*$perpage} - {$smarty.section.offset.index+1} + {$smarty.section.offset.index+1} {else} - {$smarty.section.offset.index+1} + {$smarty.section.offset.index+1} {/if}   {/section} {if $offset < $nb_resultats_total-$perpage} - Suivant -   + Suivant +   {/if}

{/if} + {min_auth level='cookie'} -

- Astuce -

-

- Si tu survoles une fiche, tu sauras quand elle a été mise à jour la dernière fois ! -

+
+

Astuce

+ + {if $advanced}{include file=search.adv.links.tpl do_title=0}{/if} + +

Si tu survoles une fiche, tu sauras quand elle a été mise à jour la dernière fois !

{/min_auth} {else} - {include file="search.form.tpl"} + {if $advanced} + {include file="search.adv.form.tpl"} + {else} + {include file="search.quick.tpl"} + {/if} {/if} + {/dynamic} + {* vim:set et sw=2 sts=2 sws=2: *} -- 2.1.4