-
efalcy authored
Historique : optimise le stockage en session Recherche vide : considere la recherche vide comme une recherche '*' (et la recheche '*' recherche sur tout le catalogue)
72f59a12
MoteurRecherche.php 14.43 KiB
<?php
/**
* Copyright (c) 2012, Agence Française Informatique (AFI). All rights reserved.
*
* AFI-OPAC 2.0 is free software; you can redistribute it and/or modify
* it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
* the Free Software Foundation.
*
* There are special exceptions to the terms and conditions of the AGPL as it
* is applied to this software (see README file).
*
* AFI-OPAC 2.0 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 AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
* along with AFI-OPAC 2.0; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
class Class_MoteurRecherche {
use Trait_Singleton;
private $ix; // Classe d'indexation
private $limite_facettes = " limit 15000"; // limite pour le calcul des facettes
private $_translate;
protected $all_facettes;
protected $_notices_not_shown = false;
protected $fil_ariane;
protected $rubriques;
public function __construct() {
$this->ix = new Class_Indexation();
$this->_translate = Zend_Registry::get('translate');
}
public function createReqForIsbn($expression) {
if ($this->_isISBN($expression)) {
$cls = new Class_Isbn($expression);
$isbn = $cls->getAll();
if ($isbn["isbn10"]) {
$this->setCondition("(isbn='".$isbn["isbn10"]."' or isbn='".$isbn["isbn13"]."')");
return true;
} elseif($isbn["ean"]) {
$this->setCondition("ean='".$isbn["ean"]."'");
return true;
}
}
return false;
}
public function visitCodeRebond($code_rebond) {
$this->visitFacette($code_rebond);
}
public function setErreur($message) {
$this->erreur["statut"] = 'erreur';
$this->erreur["erreur"] = $this->_translate->_($message);
}
public function visitExpression($expression,$pertinence,$tri) {
// Analyse de l'expression
$expression = trim($expression);
if ($expression == '*') {
return;
}
// Recherche par isbn (1 seul mot et isbn ou ean valide)
$recherche = '';
if (!$mode_isbn = $this->createReqForIsbn($expression)) {
$mots = $this->ix->getMots($expression);
foreach ($mots as $mot) {
$mot = $this->ix->getExpressionRecherche($mot);
if ($mot) {
$this->nb_mots++;
if ($recherche !='')
$recherche .= ' ';
$recherche .= ($pertinence ? ' ' : '+') . $mot;
}
}
$recherche = trim($recherche);
if (!$recherche) {
$this->setErreur(("Il n'y aucun mot assez significatif pour la recherche"));
return ;
}
if ($pertinence == true)
$against=" AGAINST('".$recherche."')";
else
$against=" AGAINST('".$recherche."' IN BOOLEAN MODE)";
$this->setCondition("MATCH(titres,auteurs,editeur,collection,matieres,dewey)".$against);
}
if ($tri and $tri!="*" and !$pertinence or $mode_isbn==true) {
}
else
{
$filtre_against=str_replace("+"," ",$against);
$filtre_against=str_replace("IN BOOLEAN MODE","",$filtre_against);
$this->select_notices="id_notice,MATCH(alpha_titre) ".$filtre_against." as rel1, ";
$this->select_notices.="MATCH(alpha_auteur)".$filtre_against." as rel2 ";
$this->select_notices.="from notices ";
$this->order_by=" order by (rel1 * 1.5)+(rel2) desc";
}
}
public function setCondition($condition) {
if ($this->conditions <> '')
$this->conditions.=' and ';
$this->conditions .= $condition;
}
public function visitAnneeDebutFin($annee_debut,$annee_fin) {
if($annee_debut) $this->setCondition("annee >='".$annee_debut."'");
if($annee_fin) $this->setCondition("annee <='".$annee_fin."'");
}
public function visitCoteDebutFin($cote_debut, $cote_fin) {
if ($cote_debut)
$this->setCondition(" cote >='" . strtoupper($cote_debut) . "'");
if ($cote_fin)
$this->setCondition(" cote <= '". strtoupper($cote_fin) . "'");
}
public function visitTypeDoc($type_doc) {
$this->setCondition(" type_doc in(".$type_doc.")");
}
public function visitFacette($facette) {
$this->all_facettes .= ' +'.$facette;
}
public function visitFiltre($filtre) {
$this->all_facettes .= ' +('.implode(' ', $filtre).') ';
}
public function visitClesNotices($cles_notices) {
foreach($cles_notices as $notice) {
if(!trim($notice)) continue;
if(isset($in_sql)) $in_sql .=","; else $in_sql = '';
$in_sql.="'".$notice."'";
}
$this->setCondition("notices.clef_alpha in(".$in_sql.")");
}
public function visitMatiere($matiere_id) {
if (!$matiere = Class_Matiere::getLoader()->find($matiere_id))
continue;
if ('' != ($sous_vedettes = trim($matiere->getSousVedettes())))
$valeur .= str_replace(' ', ' M', ' ' . $sous_vedettes);
}
public function visitAnnexe($annexe) {
$this->all_facettes .= ' +Y'.$annexe;
// $this->conditions.=" And MATCH(facettes) AGAINST('+Y".$annexe."' IN BOOLEAN MODE)";
}
public function visitNouveaute($nouveaute) {
$date = date('Y-m-d',mktime(0, 0, 0, date("m")-$nouveaute, date("d"), date("Y")));
$this->setCondition("date_creation >'".$date."'");
}
public function visitTextInput($name,$operateur,$type_recherche,$valeur,$pertinence) {
if($type_recherche == "commence")
$recherche = $this->ix->alphaMaj($valeur);
else {
$recherche="";
$mots=$this->ix->getMots($valeur);
foreach($mots as $mot)
{
$mot=$this->ix->getExpressionRecherche($mot);
if($mot)
{
if($pertinence) $recherche.=" ".$mot;
else $recherche.=" +".$mot;
}
}
}
$recherche=trim($recherche);
if(!$recherche) return ;
if (!$operateur) $operateur='and';
if($this->conditions) $this->conditions.=" ".$operateur." ";
elseif(striPos($operateur,"NOT")) $this->conditions.="not ";
// Type de recherche
if($type_recherche == "fulltext") {
$this->conditions.="MATCH(".$name.") AGAINST('".$recherche."' IN BOOLEAN MODE)";
}
else $this->conditions.=$name." like '".$recherche."%'";
}
//------------------------------------------------------------------------------------------------------
// Recherche Avancée
//------------------------------------------------------------------------------------------------------
function lancerRecherche($criteres_recherche) {
$this->criteres_recherche=$criteres_recherche;
$tri = $criteres_recherche->getTri();
$this->conditions = '';
$this->all_facettes = '';
$this->select_notices = "id_notice from notices ";
$this->nb_mots = 0;
$ret = array('nb_mots' => null,
'statut' => '',
'nombre' => 0);
if (($tri > "") && ($tri !== '*'))
$this->order_by=" order by ".$tri;
else
$this->order_by = '';
$criteres_recherche->acceptVisitor($this);
if (!empty($this->fil_ariane))
$ret["fil_ariane"]=$this->fil_ariane;
if (!empty($this->rubriques))
$ret["rubriques"] = $this->rubriques;
if ($this->_notices_not_shown)
{
$ret["statut"]="erreur";
$ret["erreur"]='';
return $ret;
}
if ($this->all_facettes) {
$this->setCondition("MATCH(facettes) AGAINST('".trim($this->all_facettes)."' IN BOOLEAN MODE)");}
$where='';
if ($this->conditions)
$where="Where ".$this->conditions;
// Finalisation des requetes
$req_notices = "Select ".$this->select_notices.$where.$this->order_by;
$req_comptage = "Select count(*) from notices ".$where;
$req_facettes = "Select id_notice,type_doc,facettes from notices ".$where.$this->limite_facettes;
// Lancer les requetes
$nb=fetchOne($req_comptage);
$ret['statut'] = '';
if(!$nb)
{
$ret["statut"]="erreur";
$ret["erreur"]=$this->_translate->_("Aucun résultat trouvé");
$this->addStatEchec(2,$criteres_recherche->getCriteres());
return $ret;
}
if (!empty($this->erreur))
{
$ret['statut']=$this->erreur['statut'];
$ret['erreur']=$this->erreur['erreur'];
}
$ret["nombre"]=$nb;
$ret["req_liste"]=$req_notices;
$ret["req_facettes"]=$req_facettes;
$ret['nb_mots'] = $this->nb_mots;
return $ret;
}
public function visitRubrique($indice,$fil) {
if ($indice=='guidee') {
$rubriques_tmp=['X1','X2'];
$this->_notices_not_shown=true;
$indice='';
}
else
$rubriques_tmp=$this->getRubriquesGuidees($indice);
$this->all_facettes .= ' +'.$indice.'*';
$this->fil_ariane=$this->getFilAriane($fil,$indice);
// Tableau des rubriques
if($rubriques_tmp)
{
$codification = Class_Codification::getInstance();
foreach($rubriques_tmp as $rubrique)
{
$libelle=$codification->getLibelleFacette($rubrique);
$url=$this->criteres_recherche->getUrlCriteresWithFacettes();
$url['rubrique'] = $rubrique;
$url = $this->addFilArianeInUrl($url,$this->fil_ariane['fil']);
$this->rubriques[]=["libelle" => $libelle,"url" => $url];
}
}
}
public function addFilArianeInUrl($url,$fil_ariane)
{
if ($fil_ariane && !empty($fil_ariane))
$url['fil'] = $fil_ariane;
else unset($url['fil']);
return $url;
}
//------------------------------------------------------------------------------------------------------
// recup des rubriques guidees
//------------------------------------------------------------------------------------------------------
private function getRubriquesGuidees($tag)
{
$rubrique=$tag[0];
$id=substr($tag,1);
$items=[];
// Rubriques racine
if($rubrique == "X")
{
$this->_notices_not_shown = true;
switch(intval($id))
{
case 1: // dewey
$liste=Class_Dewey::getIndices("root");
foreach($liste as $indice) $items[]="D".$indice["id_dewey"];
break;
case 2: // pcdm4
$liste=Class_Pcdm4::getIndices("root");
foreach($liste as $indice) $items[]="P".$indice["id_pcdm4"];
break;
}
}
// Dewey
if($rubrique == "D")
{
$liste=Class_Dewey::getIndices($id);
if(!$liste) return $items;
foreach($liste as $indice) $items[]="D".$indice["id_dewey"];
}
// Pcdm4
if($rubrique == "P")
{
$liste=Class_Pcdm4::getIndices($id);
if(!$liste) return $items;
foreach($liste as $indice) $items[]="P".$indice["id_pcdm4"];
}
return $items;
}
// ----------------------------------------------------------------
// Fil d'ariane pour le catalogue guidé
// ----------------------------------------------------------------
private function getFilAriane($fil,$rubrique) {
$fil_ariane = '';
$ret = ['rubriques' => []];
$elems =[];
if($fil) {
$fil = str_replace('guidee','',$fil);
$elems=explode(";",$fil);
}
if ($rubrique)
$elems[]=$rubrique;
$ret["liens"][]=["libelle" => $this->_translate->_("Accueil"),
"url" => $this->criteres_recherche->getUrlRetourRechercheInitiale()];
$url = $this->criteres_recherche->getUrlCriteresWithFacettes();
foreach($elems as $elem)
{
$url_rubrique = $this->addFilArianeInUrl($url,$fil_ariane);
if(!$elem) continue;
$url_rubrique['rubrique'] = $elem;
$fil_ariane.=";".$elem;
$libelle=Class_Codification::getInstance()->getLibelleFacette($elem);
$ret["liens"][]=array("libelle" => $libelle,"url" => $url_rubrique);
if($elem == $rubrique) break;
}
$ret["fil"]=$fil_ariane;
return $ret;
}
public function fetchAll($req) {
return Zend_Registry::get('sql')->fetchAll($req);
}
function getFacettes($req,$preferences) {
// Preferences
$p_facette=array("nombre" => $preferences["facettes_nombre"],"actif" => $preferences["facettes_actif"],"types" => "T".$preferences["facettes_codes"]);
$p_facette["nombre"]=$p_facette["nombre"]*2; // pour afficher les n suivants
$p_tag=array("actif" => $preferences["tags_actif"],"types" => $preferences["tags_codes"],"nombre" => $preferences["tags_nombre"]);
if(!$p_facette["actif"] and !$p_tag["actif"]) return array();
// Lecture des notices
$rows = $this->fetchAll($req);
$facettes = array();
foreach($rows as $notice)
{
$items = array_filter(explode(" ",trim($notice["facettes"])));
foreach($items as $item)
{
$type=substr($item,0,1);
if (!array_key_exists($type, $facettes))
$facettes[$type] = array();
if (!array_key_exists($item, $facettes[$type]))
$facettes[$type][$item] = 0;
$facettes[$type][$item]++;
}
}
// Constituer le tableau des facettes
$table=array();
for($i=0; $i<strlen($p_facette["types"]); $i++)
{
$type=$p_facette["types"][$i];
if (!array_isset($type, $facettes)) continue;
arsort($facettes[$type]);
$sorted[$type]=true;
$table["facettes"][$type]["titre"]=Class_Codification::getInstance()->getNomFacette($type);
$nb=0;
foreach($facettes[$type] as $clef => $nombre)
{
$nb++;
if($nb > $p_facette["nombre"]) break;
$table["facettes"][$type][$nb]["id"]=$clef;
$table["facettes"][$type][$nb]["libelle"]=Class_Codification::getInstance()->getLibelleFacette($clef);
$table["facettes"][$type][$nb]["nombre"]=$nombre;
}
}
if(!$p_tag["actif"]) return $table;
// Constituer le tableau des tags
$nb=0;
while(true)
{
// On cherche le plus fort pour chaque type
$controle=array("nombre" => 0);
$yen_a_plus=true;
for($i=0; $i<strlen($p_tag["types"]); $i++)
{
$type=$p_tag["types"][$i];
if (!array_isset($type, $facettes)) continue;
$yen_a_plus=false;
if(!isset($sorted[$type])) {
arsort($facettes[$type]);
$sorted[$type]=true;
}
$lig=array_slice($facettes[$type],0,1);
$compare=array_values($lig);
if($compare[0] > $controle["nombre"])
{
$controle["nombre"]=$compare[0];
$controle["type"]=$type;
$controle["clef"]=$lig;
}
}
// Si max atteint ou plus de facettes c'est fini
if($yen_a_plus == true) break;
$nb++;
if($nb > $p_tag["nombre"]) break;
// On depile l'item des facettes et on empile dans le resultat
foreach($controle["clef"] as $clef => $nombre);
array_shift($facettes[$controle["type"]]);
$table["tags"][$nb]["id"]=$clef;
$table["tags"][$nb]["libelle"]=Class_Codification::getInstance()->getLibelleFacette($clef);
$table["tags"][$nb]["nombre"]=$nombre;
}
return $table;
}
// ----------------------------------------------------------------
// Stats : recherches infructueuses
// ----------------------------------------------------------------
private function addStatEchec($type_recherche,$criteres)
{
$criteres=addslashes(serialize($criteres));
sqlExecute("insert into stats_recherche_echec(type_recherche,criteres) values($type_recherche,'$criteres')");
}
protected function _isISBN($value) {
return (false == strpos($value, ' ')) && 9 < strlen($value);
}
}