# Recherche de Smart Elements

La classe SearchElements permet de chercher des Smart Elements sans faire directement du SQL et connaître la structure de la base de données. Cette recherche est basée sur la notion de Smart Structure et les structures associées (Smart Field et héritage).

# Constructeur

use Anakeen\Search\SearchElements;
new SearchElements("SMART_STRUCTURE_LOGICAL_NAME");

# Liste des paramètres

structureName (string|int) :

Identifiant interne ou nom logique de la Smart Structure sur laquelle s'effectue la recherche.
Il peut prendre quelques valeurs particulières qui ne sont pas des identifiants de la Smart Structure:

  • 0 (valeur par défaut): la recherche est alors effectuée sur l'ensemble des Smart Elements quelque soit leur Smart Structure,
  • -1: la recherche est alors effectuée sur les Smart Elements "Smart Structure"

# Méthodes publiques de la classe

# count

    int count()

Cette méthode permet de compter le nombre de résultats après que la recherche ait été effectuée.
Elle retourne un entier représentant le nombre de résultats, ou -1 si la fonction SearchElements::search() n'a pas été exécutée.

Avertissements

La fonction SearchElements::search() doit être exécutée avant la méthode ::count() sinon le résultat retourné est -1.
Si le but est simplement de compter le nombre de résultats, il est préférable d'utiliser la méthode onlycount qui est optimisée pour faire uniquement le décompte et ne nécessite pas de récupérer le résultat de la recherche.

# Exemple

Compte le nombre total de Smart Elements.

use Anakeen\Search\SearchElements;

$searchElement = new SearchElements();
$doc = $searchElement->search();
var_export($searchElement->count());

# onlyCount

    int onlyCount()

Cette méthode retourne le nombre de Smart Elements trouvés par la requête (-1 en cas d'erreur), et ce, sans récupérer ces Smart Elements dans la base de données.

Avertissements

Un nouvel appel à la base de données est effectué à chaque appel; ceci écrase le précédent résultat fait par search() ou le précédent onlyCount.

# Exemple

Recherche le nombre total de Smart Elements existants.

use Anakeen\Search\SearchElements;

$searchElement = new SearchElements();
var_export($searchElement->onlyCount());

# excludeInheritedStructures

excludeInheritedStructures(bool $excludeInheritedStructures);

Cette méthode indique que la recherche ne doit pas s'effectuer sur les Smart Element qui appartiennent à des Smart Structures filles (qui héritent de cette Smart Structure)

# Exemple

Recherche les utilisateurs qui sont directement des Smart Element de la SmartStructure "IUSER".

<?php
use Anakeen\Search\SearchElements;

$searchElement = new SearchElements("IUSER");
$searchElement->excludeInheritedStructures(true);
$res = $searchElement->search()->getResults();
foreach ($res as $key => $data) {
  printf("%d) %-10s : %s\n", $key, $data->getTitle(), $data->getRawValue(\SmartStructure\Fields\Iuser::us_mail));
}

# join

    void join( string $join)

Cette méthode permet de faire une jointure; elle permet d'ajouter des critères provenant d'une autre table de manière à établir des filtres complexes.

# Liste des paramètres

join (string)

join

Avertissements

Les restrictions suivantes s'appliquent aux jointures:

  • une seule jointure est possible par searchElements,
  • on ne peut pas utiliser la jointure dans le seul but d'établir une recherche plus précise, mais pour enrichir les résultats,
  • on ne peut pas faire de jointure sur la table en cours.

# Exemple

Recherche dans la Smart Structure "ZOO_ANIMAL" tous les gardiens dont le prénom est "Jean"

use Anakeen\Search\SearchElements;
$searchElement = new SearchElements("DEVCLIENT");
$searchElement->join("client_email::text = iuser(us_mail)");
$searchElement->addFilter("iuser.us_fname = 'Jean'");
$doc = $searchElement->search();

# isExecuted

    bool isExecuted()

Cette méthode permet de vérifier que la requête a été envoyé à la base de données.
Elle retourne true si la requête a été envoyée, false sinon.

# Exemple

use Anakeen\Search\SearchElements;
$searchElement = new SearchElements("DEVCLIENT");
$searchElement->join("client_email::text = iuser(us_mail)");
$searchElement->addFilter("iuser.us_fname = 'Jean'");
$doc = $searchElement->search();
var_export($doc->isExecuted());

# returnsOnly

    void returnsOnly(array $returns)

La fonction retourne tous les éléments d'un Smart Element initialisés à null sauf les éléments mentionnés dans le tableau returns.

Cette méthode permet d'accélérer le traitement de la requête en indiquant un sous-ensemble de Smart Fields ou de propriétés. Ceci a deux avantages:

  • Moins de données transférées entre la base de données et le serveur,
  • Moins de consommation mémoire.

L'inconvénient est que les Smart Elements retournés ne sont pas complets. Ceci implique que ces Smart Elements ne peuvent pas faire l'objet de modification.

Avertissements

Si le mode est retour d'objet Smart Elements, les documents retournés sont marqués "incomplet" (doctype='I').
Ils ne peuvent pas être modifiés par la méthode SmartElements::store().

# Liste des paramètres

returns

Indique une liste de propriétés ou de Smart Fields à récupérer.
Si returns est vide, les 4 propriétés élémentaires du Smart Element sont retournées:

  • id,
  • title,
  • fromid,
  • doctype.

# Exemple

use Anakeen\Search\SearchElements;
$s = new SearchElements("IUSER");
$s->setOrder('initid');
$s->returnsOnly(array('us_login'));
$s->search();

print "Résultats :\n";
$documentList = $s->getResults();
foreach ($documentList as $doc) {
  printf($doc->us_login . '\n');
}

# setSlice

    bool setSlice( int|string $slice )

Cette méthode permet de définir le nombre maximal de résultats retournés.
Cette méthode retourne true si le paramètre est appliqué, false sinon.

INFO

Le paramètre n'est pas appliqué s'il n'est pas un entier ou s'il n'est pas ALL.

Avertissements

La méthode ::count() retourne le nombre de résultats et ne peut pas excéder la valeur du paramètre $slice.
Il faut toujours définir un ordre à la recherche afin de garantir une fenêtre de résultat non ambiguë.

# Liste des paramètres

setSlice (int|string)

nombre maximum de résultats retournés. Ce nombre peut-être soit un entier positif, soit ALL, qui indique que tous les résultats sont retournés.

# Exemple

Retourner les 10 premiers résultats.

use Anakeen\Search\SearchElements;
$searchElement = new SearchElements("IUSER");
$searchElement->setOrder('us_login, initid');
$searchElement->setSlice(5);
$res = $searchElement->search()->getResults();
foreach ($res as $key => $data) {
  printf("%d) %-10s : %s\n", $key, $data->getTitle(), $data->getRawValue(\SmartStructure\Fields\Iuser::us_lname));
}

# setStart

    bool setStart( int $start )

Cette méthode permet de définir que la récupération des Smart Elements commence après le nième trouvé.
Soit, tous les Smart Elements avant le $start sont ignorés du résultat de la recherche.

Cette méthode retourne true si le paramètre a été appliqué, false sinon. Dans le cas où $start n'est pas de type int, alors le paramètre n'est pas appliqué et la méthode retourne false.

# Liste des paramètres

start (int)

Définit le nième Smart Element après lequel la recherche commence.

# Exemple

Rechercher des utilisateurs et retourner les résultats du 10ième au 35ième Smart Element.

use Anakeen\Search\SearchElements;
$searchElement = new SearchElements("IUSER");
$searchElement->setOrder('us_login, initid');
$searchElement->setSlice(5);
$searchElement->setStart(3);
$res = $searchElement->search()->getResults();
foreach ($res as $key => $data) {
  printf("%d) %-10s : %s\n", $key, $data->getTitle(), $data->getRawValue(\SmartStructure\Fields\Iuser::us_lname));
}

Dans cet exemple, les 9 premiers utilisateurs ne font pas partie du résultat.

# setOrder

    void setOrder( string $order, string $orderbyLabel = '' )

Les résultats de la recherche peuvent être ordonnés à l'aide de la méthode setOrder() qui permet de spécifier les Smart Fields en fonction desquels seront triés les résultats.

Avertissements

Cette fonction ne produit pas de message d'erreur si les Smart Fields passés ne sont pas valides.

# Liste des paramètres

order (string)

Une chaîne de caractères contenant la liste des colonnes (séparées par une virgule) en fonction desquelles le résultat est ordonné.
Le nom des colonnes peut être suffixé par un espace et le mot-clef 'asc' ou 'desc' afin de spécifier l'ordre du tri: ASCendant ou DEScendant (par défault, la colonne est triée dans l'ordre ascendant).

orderbyLabel (string)

Une chaîne de caractères contenant le nom d'une des colonnes spécifiées dans l'argument #1 (sans le suffixe de tri 'asc' ou 'desc') et pour laquelle le tri doit être fait non pas sur la valeur du Smart Field, mais sur le label ou le titre.
Les Smart Fields actuellement supportés pour l'ordonnancement par le label ou le titre sont:

  • les Smart Fields de type enum
  • les Smart Fields de type 'docid("X")' déclarés avec une option 'doctitle=auto' ou 'doctitle=xxx'.

Pour les énumérés, les libellés peuvent être différents suivant la locale. L'ordre est alors différent suivant la langue choisir lors de la connexion de l'utilisateur.

# Exemple

  • Exemple de tri en fonction d'un Smart Field entier:
use Anakeen\Search\SearchElements;
$searchElement = new SearchElements("IUSER");
$searchElement->setOrder('initid desc');
$res = $searchElement->search()->getResults();
foreach ($res as $key => $data) {
  printf("%d) %-10s : %s\n", $key, $data->getTitle(), $data->getRawValue(\SmartStructure\Fields\Iuser::us_lname));
}
  • Exemple de tri en fonction de deux Smart Fields:
use Anakeen\Search\SearchElements;
$searchElement = new SearchElements("IUSER");
$searchElement->setOrder('us_login asc,initid desc');
$res = $searchElement->search()->getResults();
foreach ($res as $key => $data) {
  printf("%d) %-10s : %s\n", $key, $data->getTitle(), $data->getRawValue(\SmartStructure\Fields\Iuser::us_lname));
}

# useCollection

    bool useCollection(int $dirid)

Cette méthode permet de définir que la recherche a pour base une collection, seul les Smart Elements contenus dans cette collection sont trouvés. Elle retourne true si le paramètre a pu être appliqué, false sinon. Si jamais la référence passée en entrée n'est pas valide, la fonction retourne false et enregistre un message d'erreur sur l'objet (voir searchSmartData::getError).

La collection indiquée en entrée dans la fonction peut être soit un dossier, une recherche ou encore un rapport.

Avertissements

Lorsque la collection indiquée en entrée est une recherche spécialisée, il est impossible d'utiliser la méthode SearchElements::addFilter().

# Liste des paramètres

dirid (string|int)

La fonction prend en entrée la référence vers une collection que ça soit par son nom logique ou par son identifiant.

# Exemple

  • Récupérer le contenu d'un dossier
use Anakeen\Search\SearchElements;
$folderName = "PRF_ADMIN_DIR"; // identifiant d'un Smart Element recherche ou dossier

$searchElement = new SearchElements();
$searchElement->useCollection($folderName);
$res = $searchElement->search();

# setLatest

    bool setLatest(bool $latest)

Cette méthode indique si la recherche ne doit retourner que la dernière révision des documents. Elle retourne true si le paramètre est appliqué, false sinon.

# setDistinct

    bool setDistinct(bool $distinct)

Cette méthode indique si les résultats retournés comprennent toutes les révisions trouvées ou pas (false indique que tous les résultats sont renvoyés). Elle retourne true si le paramètre est appliqué, false sinon.

Avertissements

Cette propriété n'a de sens que si latest est à false.

# useTrash

    string useTrash(string $trash)

Cette méthode indique si la recherche doit chercher aussi dans les Smart Elements supprimés.
La propriété doctype est à Z si le document est supprimé. La méthode retourne :

  • no: les Smart Elements supprimés sont exclus,
  • also: les Smart Elements supprimés sont inclus,
  • only: seul les Smart Elements supprimés sont inclus.

# getFamily

    SmartStructure getFamily()

Cette méthode retourne la Smart Structure sur laquelle la recherche est effectuée.

# excludeConfidential

    bool excludeConfidential( bool $exclude = true)

Il est possible de marquer des Smart Elements comme confidentiels; ceux-ci sont alors trouvés dans les recherches mais ne sont pas consultables si l'utilisateur n'en a pas le droit.
Cette méthode permet d'exclure ces Smart Elements si l'utilisateur n'a pas le droit confidential sur les Smart Elements recherchés.

Avertissements

Si la recherche est faite avec l'utilisateur "admin" cette méthode est sans effet car "admin" a tous les droits.
Par défaut, la méthode ::search() retourne les Smart Elements confidentiels, même ceux auxquels l'utilisateur n'a pas le droit confidential.

# Liste des paramètres

exclude (bool)

si la valeur est à true alors les Smart Elements confidentiels sont exclus, si la valeur est à false ils sont inclus.
Un objet SearcheElements les inclut par défaut.

# Exemple

Cette exemple retourne les Smart Elements accessibles:

  • les Smart Elements non confidentiels,
  • les Smart Elements confidentiels où l'utilisateur possède les privilèges suffisants.
use Anakeen\Search\SearchElements;
$searchElement = new SearchElements();
$searchElement->excludeConfidential(true);
$searchElement->search();

$res = $searchElement->getSearchInfo();
print_r($res);

# addFilter

    void addFilter(string|ElementSearchFilter $filter, string|int|double $value)

Cette méthode permet de configurer la requête SQL qui va être générée. Elle prend en argument un fragment de SQL et les associe pour créer la requête.

Avertissements

Les variables sont encodées avec la fonction pg_espace_string afin de construire correctement les filtres et afin d'éviter l'injection SQL.
Si les variables contiennent du texte, celui-ci doit être encodé en UTF-8.
Cette méthode n'est pas utilisable conjointement avec une recherche spécialisée en tant que collection de base.

# Liste des paramètres

filter

Cette partie doit être soit une chaîne de caractères contenant du SQL, soit une chaîne formatée; celle-ci est alors complétée avec les valeurs passées dans les arguments suivants.

Attention

Les points suivants sont à prendre en compte:

  • injections SQL: le premier argument de la méthode addFilter est ajouté tel quel dans la requête SQL, il est donc possible qu'il puisse déclencher une injection SQL.
    Les données doivent être échappées ( par exemple à l'aide de pg_escape_string)

  • gestion de la multiplicité: les valeurs des Smart Fields multiples (premier et second niveau de multiplicité) sont stockées avec des caractères d'échappement.
    La création d'une requête les prenant en compte nécessite l'utilisation d'opérateurs propre à postgreSQL; il existe plusieurs manières d'aborder le problème:

    • recherche à base d'expression régulières: "ATTRNAME ~ E'\\\\y%s\\\\y'": il faut remplacer ATTRNAME par le nom du Smart Field.
      Limitation : l'opérateur utilisé est une expression régulière avec le séparateur de mot \y cela peut engendrer des faux positifs si jamais la valeur contient elle-même des séparateurs de mot.
      Ce type de recherche permet de faire les filtres les plus simples (un parmi, etc...) avec le risque d'avoir des faux positifs.

    • recherche à base de conversion en array postgres, deux cas sont à prendre ne compte:

      • le Smart Field a un(1) niveau de multiplicité: (regexp_split_to_array(ATTRNAME, E\'\\n\')),
      • le Smart Field a deux(2) niveaux de multiplicité: (regexp_split_to_array(replace(ATTRNAME, \'<BR>\', E\'\\n\'),E\'\\n\'))
        Dans les deux cas, il faut remplacer ATTRNAME par le nom du Smart Field. La comparaison se fait ensuite à l'aide des opérateurs propres aux tableaux.
        Ce type de recherche est plus coûteux en ressources que le premier type mais permet de faire des recherches plus complexes ( a des éléments en commun, est contenu par, etc...) et limite le risque de faux positif.

value (string|int|double)

Valeurs qui sont concaténées à la partie filter à l'aide de la fonction sprintf.

Note

Cet argument peut être répété autant de fois que souhaité.

Attention

  • Les paramètres passés par value sont échappés à l'aide de la fonction pg_escape_string.
  • Dans le cas d'utilisation d'un opérateur à base d'expression régulière, il faut utiliser la fonction preg_quote sans quoi les valeurs peuvent rendre l'expression régulière invalide.

# Exemple

Recherche de Smart Elements dont le Smart Field firstname est égal à "Jean" et le Smart Field lastname à "Dupont":

$searchElement = new \Anakeen\Search\SearchElements("IUSER");
$searchElement->addFilter("us_fname = '%s' AND us_lname = '%s'", "Jean", "Dupont");
$res = $searchElement->search()->getResults();
foreach ($res as $key => $value) {
  printf("user id is : %d", $key);
}

Recherche de Smart Elements dont le Smart Field firstname est égal à "Arthur" et le Smart Field lastname à "O'Connor":

use Anakeen\Search\SearchElements;
$searchElement = new SearchElements("IUSER");
$searchElement->addFilter("us_fname = '%s'", "Arthur");
$searchElement->addFilter("us_lname = '%s'", "O'Connor");

Recherche de Smart Elements dont une des valeurs du Smart Field multivalué actors contient "John Wayne":

use Anakeen\Search\SearchElements;
$searchElement = new SearchElements("FILM");
$searchElement->addFilter("actors ~* E'%s'", preg_quote("John Wayne"));

Attention

L'expression ci-dessus peut engendrer des faux positifs, par exemple, si acteur contient John Wayne Junior il est aussi trouvé car \y désigne un séparateur de mot et espace est un séparateur de mot.

# overrideAccessControl

    bool overrideAccessControl()

Par défaut, la méthode ::search() ajoute un filtre permettant de ne retourner que les Smart Elements que l'utilisateur courant peut voir. Cette méthode permet de ne pas tenir compte du droit view;
tous les Smart Elements existants sont alors retournés que l'utilisateur courant ait ou pas le droit de les voir. Elle retourne alors true si le paramètre est appliqué, false sinon.

# Exemple

Soit FILM, une Smart Structure décrivant les caractéristiques de films. Compter le nombre total de film :

use Anakeen\Search\SearchElements;

$searchElement = new SearchElements("FILM");
$searchElement->overrideAccessControl();
$numberOfUsers = $searchElement->onlyCount();

INFO

Si la méthode overrideAccessControl() n'était pas appelée, le compte retourné serait le nombre de films que l'utilisateur en cours a le droit de voir.

    array|null|Anakeen\Search\SearchElements search()

Cette méthode exécute la recherche. Elle construit la requête SQL nécessaire en utilisant les paramètres de la Smart Structure recherchée et les conditions insérées par les différentes méthodes.
La valeur de retour dépend du type de recherche:

  • Résultats bruts: le retour est alors un tableau array, si la préparation de la recherche a échoué alors le résultat est un tableau vide.

  • Résultats Smart Elements: le retour est alors l'objet SearchElements lui-même ou null si la préparation de la recherche a échoué.

    Avertissements

    Par défaut, certains types de documents sont exclus des résultats de la recherche. Ces exclusions sont modifiables par les méthodes ::excludeConfidential(), ::overrideAccessControl(), ::useTrash() et ::setDistinct().

# Exemple

  • Recherche simple de tous les dossiers que l'utilisateur courant peut voir.
$searchElement = new Anakeen\Search\SearchElements("DIR");

$list = $searchElement->search()->getResults();
foreach ($list as $docid => $doc) {
  printf("(%d) %s (%s)", $docid, $doc->getTitle(), $doc->getRawValue(\SmartStructure\Fields\Dir::ba_title));
}
  • Recherche avec capture d'erreurs de tous les dossiers que l'utilisateur courant peut voir.
try {
  $searchElement = new Anakeen\Search\SearchElements("DIR");

  $list = $searchElement->search()->getResults();
  foreach ($list as $docid => $doc) {
    printf("(%d) %s (%s)", $docid, $doc->getTitle(), $doc->getRawValue(\SmartStructure\Fields\Dir::ba_title));
  }
} catch (\Anakeen\Database\Exception $e) {
  printf("Database Error: [%s]\n", $e->getMessage());
} catch (\Anakeen\Search\Exception $e) {
  printf("Search error: [%s]\n", $e->getMessage());
}

# getResults

    Anakeen\Search\ElementList getResults()

Cette méthode retourne un objet ElementList associé à l'objet SearchElements. Ce dernier permet d'itérer sur les résultats obtenus par l'objet SearchElements.

Avertissements

L'exécution de la méthode SearchElements::search n'est pas nécessaire avant l'utilisation de ::getResults.
Si cette méthode est appelée avant l'itération, elle ne sera pas exécutée lors de l'itération.
Dans le cas contraire, la méthode SearchElements::search sera appelée dès le début de l'itération.

# Exemple

  • Récupération de la liste des Smart Elements de la Smart Structure "DIR"
use Anakeen\Search\SearchElements;
$searchElement = new SearchElements("DIR");

$searchElement->search();

$list = $searchElement->getResults();

foreach ($list as $docid => $doc) {
  printf(
    "(%d) %s (%s)\n",
    $docid,
    $doc->getTitle(),
    $doc->getRawValue(\SmartStructure\Fields\Dir::ba_desc, "Pas de description")
  );
}

# rewind

    SearchElements rewind()

Cette méthode réinitialise les résultats de la recherche initialisée par la méthode SearchElements::search() et SearchElements::onlyCount().
Elle permet d'ajouter un nouveau filtre afin de relancer une nouvelle itération.

Avertissements

L'utilisation de SearchElements::rewind() durant une itération réinitialise le pointeur mais ne refait pas la requête.

# Exemple

use Anakeen\Search\SearchElements;
$searchElement = new searchElements("IUSER");

foreach ($searchElement->getResults() as $document) {
    printf("Title : %s \n\t date : %s \n", $document->getTitle(), $document->getTextualAttrValue(\SmartStructure\Fields\Iuser::us_accexpiredate));
}

$searchElement->addFilter("%s > '%s'", \SmartStructure\Fields\Iuser::us_accexpiredate, date('Y-m-d', strtotime("-1 year")));

$searchElement->rewind();

foreach ($searchElement->getResults() as $document) {
    printf("Title : %s \n\t date : %s \n", $document->getTitle(), $document->getTextualAttrValue(\SmartStructure\Fields\Iuser::us_accexpiredate));
}
}

# getSearchInfo

    array getSearchInfo()

Cette méthode permet d'avoir des informations sur l'exécution de la recherche. Elle retourne un array qui contient les clefs suivantes :

  • count: nombre de résultats de la requête,
  • query: requête SQL générée,
  • error: message d'erreur, si il y a eu une erreur lors de la préparation de la requête,
  • delay: temps d'exécution de la requête.

Note

Si la méthode search() n'a pas été exécutée alors une chaîne vide est retournée.

# Exemple

Recherche des cinq premiers dossiers:

use Anakeen\Search\SearchElements;
$searchElement = new SearchElements("IUSER");

$searchElement->setSlice(5);
$searchElement->setOrder("initid");
$searchElement->search();

print_r($searchElement->getSearchInfo());

# getNextElement

    Element|array|null getNextElement()

Cette méthode permet d'itérer sur la liste des Smart Elements trouvés par la recherche.
La valeur de retour peut être:

  • array: si le type de recherche n'est pas object,
  • Element: si le type de recherche est object,
  • null: si tous les Smart Elements ont été parcourus.

# Exemple

  • Itération sur tous les Smart Elements
use Anakeen\Search\SearchElements;
$searchElement = new SearchElements();

$searchElement->search();

while (($el = $searchElement->getNextElement())) {
  print $el->getTitle() . "\n";
}
print $searchElement->getSearchInfo();
  • Récupération du premier dossier qui a été créé
use Anakeen\Search\SearchElements;
$searchElement = new SearchElements("DIR");
$searchElement->setSlice(1);
$searchElement->setOrder("initid");

$searchElement->search();

if ($searchElement->count() > 0) {
  $firstFolder = $searchElement->getNextElement();
}
print $firstFolder->id;