Skip to content
Snippets Groups Projects
  • efalcy's avatar
    Historique & Recherche vide · 72f59a12
    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);
	}
}