# Mécanismes de recherche

La recherche de Smart Elements est une fonctionnalité essentielle à la gestion des Smart Elements. Cette recherche permet de trouver des Smart Elements sur divers critères tels que:

  • critère d'appartenance à une Smart Structure,
  • critère sur les propriétés de Smart Elements,
  • critère sur les Smart Fields des Smart Elements,
  • critère sur les droits du Smart Element,
  • critère sur l'appartenance à un dossier,
  • critère sur les relations entre Smart Elements,
  • critère sur les activités ou état lié à un cycle de vie.

Les chapitres suivants détaillent les techniques permettant d'effetuer des recherches de Smart Elements.

# Recherche de Smart Elements

# Recherche de Smart Elements issus d'une même Smart Structure

La recherche de Smart Elements en fonction d'une Smart Structure est réalisée avec la classe SearchElements.

# Récupération du résultat de la recherche

Par défaut les résultats suivants sont exclus:

  • Les Smart Elements supprimés (doctype = 'Z'),
  • Les Smart Elements figés (locked = -1),
  • Les Smart Elements temporaires (doctype = 'T'),
  • Les Smart Elements archivés (archiveid is null),
  • Les Smart Elements non visibles par l'utilisateur courant (droit view).

# Retour de Smart Elements

La méthode SearchElements::getResults() retourne un objet itérable Anakeen\Search\ElementList.

  • Avec une boucle foreach
use Anakeen\Search\SearchElements;

$searchElement = new SearchElements("IUSER");
$res = $searchElement->search()->getResults();
foreach ($res as $key => $data) {
  printf("%d) %-10s : %s\n", $key, $data->getTitle(), $data->getRawValue(\SmartStructure\Fields\Iuser::us_mail));
}
  • Avec une boucle while en utilisant la méthode SearchElements::getNextElement()
use Anakeen\Search\SearchElements;

$searchElement = new SearchElements("IUSER");
$res = $searchElement->search();
$i = 0;
while (($r = $res->getNextElement())) {
  printf("$i) %-10s : %s\n", $r->getTitle(), $r->getRawValue(\SmartStructure\Fields\Iuser::us_mail));
  $i++;
}

# Retour d'objets Smart Element

Il est possible d'appliquer les méthodes des objets sur les retours de Smart Elements (exemple: SmartElement::getRawValue).

use Anakeen\Search\SearchElements;

$searchElement = new SearchElements("IUSER");
$searchElement->addFilter("us_extmail is not null");
$searchElement->search();

$c = $searchElement->count();
print "count $c\n";
$i = 0;
while (($r = $searchElement->getNextElement())) {
  printf("$i)" . $r->getTitle() . "(" . $r->getRawValue(\SmartStructure\Fields\Iuser::us_mail) . ")\n");
  $i++;
}

Sécurité

Les objets Smart Element sont retournés non contrôlés. Le store ne vérifiera pas les droits d'accès.

Il faut utiliser la méthode disableAccessControl pour activer les droits.

# Utilisation des itérateurs

Pour récupérer la liste des Smart Elements, il est aussi possible d'utiliser un itérateur PHP afin de parcourir la liste des Smart Elements.

use Anakeen\Search\SearchElements;

$searchElement = new SearchElements("IUSER");
$searchElement->addFilter("us_extmail is not null");
$searchElement->setSlice(15);
$searchElement->search();
$res = $searchElement->getResults();
foreach ($res as $key => $el) {
  print "$key)" . $el->getTitle() . "(" . $el->getRawValue("us_mail", "nomail") . ")\n";
}

La méthode getResults() retourne une objet ElementList qui implémente l'interface Iterator. Il est ainsi possible d'utiliser le résultat dans une boucle classique foreach.

# Recherche avec des critères sur des Smart Fields du Smart Element

Dans le cas où une Smart Structure d'appartenance est précisée, il est possible d'utiliser les Smart Fields de cette Smart Structure comme critères.

use Anakeen\Search\SearchElements;

$s = new SearchElements("IUSER"); // recherche sur les Smart Elements de la Smart Structure IUSER
$s->addFilter("us_fname ~* 'jean'"); // prénom contient Jean
$res = $s->search()->getResults();
foreach ($res as $key => $el) {
  print "$key)" . $el->getTitle() . "(" . $el->getRawValue("us_mail", "nomail") . ")\n";
}

L'exemple ci-dessus montre la recherche de toutes les personnes dont le prénom contient jean. Les filtres ajoutés au moyen de la méthode addFilter() établissent une conjonction de conditions (opérateur and). Pour établir une disjonction, il faut l'écrire manuellement en SQL en utilisateur l'opérateur or.
Les opérateurs SQL utilisés doivent être compatibles avec les types des Smart Fields stockés en base de données.

use Anakeen\Search\SearchElements;

$s = new SearchElements("IUSER"); // recherche sur les Smart Elements de la Smart Structure IUSER
$s->addFilter("us_fname ~* 'jean|patrick'"); // prénom contient jean ou patrick
// mail fini par .org ou nom commençant par CO
$s->addFilter("(us_mail ~ '\.org$') or (us_lname ~ '^CO')");
$res = $s->search()->getResults();
foreach ($res as $key => $el) {
  print "$key)" .
    $el->getTitle() .
    "(" .
    $el->getRawValue("us_mail", "nomail") .
    ":" .
    $el->getRawValue("us_lname") .
    ")\n";
}

Note

Les types docid sont enregistrées au format text dans la base de données.

# Recherche dans un array

Pour une Smart Structure avec un tableau contenant une liste de valeur, le filtre PostgreSQL suivant permet de filtrer les Smart Elements dont une des valeurs est égale à une valeur précise:

use Anakeen\Search\SearchElements;

$s = new SearchElements("IUSER"); // recherche sur les Smart Elements de la Smart Structure IUSER
$s->addFilter("'Main Group' ~ ANY(us_group)");
$res = $s->search()->getResults();
$c = $s->count();
print $c . " results\n";
foreach ($res as $item) {
  print $item->getTitle();
}

# Recherche avec jointure

Il est possible d'ajouter des critères portant sur une autre table en utilisant un mécanisme de jointure. Ce mécanisme ne permet pas de récupérer des données provenant de cette autre table mais permet de les utiliser comme critère de recherche.
Exemple: recherche des Smart Elements qui ont dans l'historique un ordre de suppression émis par l'utilisateur courant.

use Anakeen\Search\SearchElements;

$s = new SearchElements();
$s->useTrash("only");
$s->join("id = dochisto(id)");
$s->addFilter("dochisto.uid = %d", "Administrators");
$s->addFilter("dochisto.code = 'DELETE'");
$s->setDistinct(true);
$result = $s->search()->getResults();
foreach ($result as $item) {
  print $item->getTitle();
}

Il est notamment possible d'utiliser, entre autres, les tables dochisto,docutag ou docrel pour établir un critère de jointure.

Attention

On ne peut utiliser qu'un seul ordre join par requête.

Il est aussi possible de créer un critère sur une Smart Structure liée :

use Anakeen\Search\SearchElements;

$s = new SearchElements("DEVBILL");
$s->join("bill_author::int = devperson(id)");
$s->addFilter("devperson.dev_firstname = 'Jack'");
$result = $s->search()->getResults();
$c = $s->count();
print $c . " results";
foreach ($result as $item) {
  print $item->getTitle();
}

Dans l'exemple décrit on recherche les factures DEVBILL dont l'auteur est une personne DEVPERSON nommé Jack.

Attention

Bien lier les deux Smart Structures à travers l'identificateur initial (initid) dans le cas des relations créées avec les options par défaut.

# Recherche de Smart Structure

Pour rechercher des Smart Structures, il faut utiliser la valeur -1 lors de la construction de l'objet recherche.

use Anakeen\Search\SearchElements;

$s = new SearchElements(-1);
$result = $s->search()->getResults();
foreach ($result as $r) {
  print $r->getTitle();
}

# Recherche de Smart Element depuis leur identifiant

Dans le cas ou vous disposez d'une liste d'identifiant de Smart Element, il faut utiliser l'itérateur de Smart Element.

use Anakeen\Search\ElementList;

$dl = new ElementList();
$dl->addElementIdentifiers(array(97519, 97514, 97515, 97513));
foreach ($dl as $item) {
  print $item;
}

La méthode ElementList::addElementIdentifiers() permet de renseigner la liste des identifiants de Smart Element.
Si dans la liste un ou plusieurs identifiant sn'ciste pas alors l'itérateur ne les retourne pas. Dans ce cas le nombre de Smart Elements retourné est inférieur au nombre d'identifiants données.
Par défaut seuls les Smart Elements que l'utilisateur a le droit de voir sont retournés.
Si vous voulez affiner les critères de recherche vous pouvez le faire en utilisant la recherche stockée dans l'itérateur.

use Anakeen\Search\ElementList;

$el = new ElementList();
$el->addElementIdentifiers(array(97519, 97514, 97515, 97513));
$el->getSearchElement()->addFilter("title ~ 'HANOUZET'");
$el->getSearchElement()->overrideAccessControl();
foreach ($el as $r) {
  print $r->getTitle();
}

Cela ne retournera que les Smart Elements dont le titre contient HANOUZET parmi les quatre Smart Elements donnés sans tenir compte des droits de visibilités. Il est aussi possible d'utiliser la fonction de callback pour l'appliquer à l'ensemble de la liste (voir ElementList::listMap()).

# Recherche de Smart Element contenu dans une collection

La classe SearchElements permet de faire des recherches dans une collection spécifique (dossier ou recherche) au moyen de la méthode SearchElements::useCollection().
Cette recherche n'est pas récursive par défaut, c'est à dire qu'elle ne recherche que dans la collection indiquée.
Lorsque la collection est un dossier, il est possible de faire des recherches récursives à l'aide de la méthode SearchSmartData::setRecursiveSearch(). Le niveau de profondeur de la recherche est ensuite défini au moyen de la propriété SearchSmartData::folderRecursiveLevel, positionné à 2 par défaut.

Note

Le setRecursiveSearch fait référence au niveau de récursivité. Par exemple, folderRecursiveLevel=0 veut dire que l'on recherche dans le dossier, alors que folderRecursiveLevel=1 indique de rechercher dans le dossier et ses sous-dossiers.

Lorsque la collection est une recherche, il n'est pas possible de faire la recherche récursivement.

use Anakeen\Search\SearchElements;

$s = new SearchElements();
$s->useCollection("MASK");
$r = $s->search();

# Recherche en fonction des droits

# Recherche sans tenir compte des droits

Par défaut, seuls les Smart Elements que l'utilisateur a le droit de voir sont retournés. Pour retourner tous les Smart Elements sans vérifier les droits, il faut utiliser la méthode overrideAccessControl().

use Anakeen\Search\SearchElements;

$s = new SearchElements("DEVBILL");
$s->overrideAccessControl();

Note

Si la recherche est faite sour l'identité admin, aucun droit n'est vérifié.

# Recherche et Smart Elements confidentiels

Les Smart Elements confidentiels sont les Smart Elements dont la propriété confidential est égale à 1. L'accès à ces Smart Elements doit être contrôlé par l'application qui décide quelles parties elle veut montrer. À la différence du droit voir (view) des Smart Elements, la recherche retourne les Smart Elements confidentiels par défaut. Le filtrage est à faire du côté de l'application avec un post-traitement. Cependant, il est possible de rajouter un filtre permettant de ne pas retourner les Smart Elements confidentiels que l'utilisateur n'a pas le droit de voir. Pour cela, il faut appeler la méthode excludeConfidential().

use Anakeen\Search\SearchElements;

$s = new SearchElements("DEVBILL");
$s->excludeConfidential();
$s->search();

# Recherche sur les propriétés du Smart Element

# Recherche et révision

Par défaut, seule la dernière révision du Smart Element est retournée. Pour chercher sur l'ensemble des révisions, il faut mettre la propriété latest à false.

use Anakeen\Search\SearchElements;

$s = new SearchElements("DEVBILL");
$s->setLatest(false); // toutes les révisions

Si la propriété locked = -1, cela indique que le Smart Element est figé.

# Recherche sur les propriétés

Cet exemple, montre la recherche de Smart Element par le titre. Ici, tout type de Smart Element est retourné si son titre contient 'jean' en majuscule ou minuscule. Les opérateurs utilisables sont les opérateurs SQL de PostgreSQL.

use Anakeen\Search\SearchElements;

$s = new SearchElements();
$s->addFilter("title ~* 'jean'");
$res = $s->search()->getResults();
foreach ($res as $r) {
  print $r->getTitle();
}

# Rechercher sur les états d'un Smart Element lié à un cycle de vie

La recherche des Smart Elements en fonction de leur activité ou de leur état est faite en filtrant sur la propriété state. La clef correspondante est l'identifiant indiqué dans les propriétés e1 et e2 du cycle. La recherche suivant l'activité est forcément effectuée sur les dernière révisions.

use Anakeen\Search\SearchElements;
use Anakeen\SmartElementManager;

$doc = SmartElementManager::getDocument("WDOC_BILL"); // Cycle DEVBILL
$s = new SearchElements("DEVBILL");
$s->addFilter("state = '%s'", $doc->getFirstState()); // recherche des Smart Elements étant dans la première activité
$s->search();

La recherche sur l'état est effectuée sur les révisions passées.

use Anakeen\Search\SearchElements;
use Anakeen\SmartElementManager;
use SmartStructure\Fields\Devbill as bill;

$doc = SmartElementManager::getDocument("WDOC_BILL");
$s = new SearchElements("DEVBILL");
$s->addFilter("state = '%s'", bill::bill_author);
$s->setLatest(false);
$s->addFilter("locked = -1"); // révisions passées uniquement
$s->search();

# Recherche des relations d'un Smart Element

Pour trouver les Smart Elements qui ont lié à un autre,, il faut utiliser la classe DocRel. La méthode DocRel::getIRelations() donne la liste des Smart Elements liés vers un Smart Element.

use Anakeen\SmartElementManager;

$doc = SmartElementManager::getDocument(98452);
$docrel = new \DocRel($doc->initid);
$toMeRelation = $docrel->getIRelations();
$fromMeRelation = $docrel->getRelations();

print "\n#------------------ Relation vers moi\n";
print_r($toMeRelation);
print "\n#------------------ Relation depuis moi\n";
print_r($fromMeRelation);

La méthode DocRel::getIRelations() retourne les caractéristiques des Smart Elements liés.

  • sinitid : Identifiant initial source (celui qui pointe vers la cible),
  • cinitid : Identifiant initial cible (la cible pointé par la source),
  • stitle : Titre de la source,
  • ctile : Titre de la cible,
  • sicon : Icône de la source,
  • cicon : Icône de la cible,
  • type : Type de lien (nom du Smart field ayant établi le lien),
  • doctype : doctype du Smart Element source.

Résultats:

#------------------Relation vers moi Array()




#------------------Relation depuis moi Array(
Array(
  [0] => Array(
    [sinitid] => 98111
    [cinitid] => 97755
    [ctitle] => EVERS Léana SOUFFLET NEGOCE
    [cicon] => devclient.png
    [stitle] => Bill0003
    [sicon] => devbill.png
    [type] => bill_clients
    [doctype] => F
  )
  [1] => Array(
    [sinitid] => 98111
    [cinitid] => 97745
    [ctitle] => RELAIX Alexandre SYSTEME U CENTRALE NATIONALE
    [cicon] => devclient.png
    [stitle] => Bill0003
    [sicon] => devbill.png
    [type] => bill_clients
    [doctype] => F
  )
  [2] => Array(
    [sinitid] => 98111
    [cinitid] => 97626
    [ctitle] => ADAMZIK Jack
    [cicon] => devperson.png
    [stitle] => Bill0003
    [sicon] => devbill.png
    [type] => bill_author
    [doctype] => F
  )
)

Pour exploiter les résultats, il est aussi possible d'utiliser un objet ElementList.

use Anakeen\Search\ElementList;
use Anakeen\SmartElementManager;

$doc = SmartElementManager::getDocument(98111);
$docrel = new \DocRel();
$docrel->sinitid = $doc->initid;
$fromMeRelation = $docrel->getRelations();
$ids = array_map(function ($r) {
  return $r["sinitid"];
}, $fromMeRelation);
$dl = new ElementList();
$dl->addElementIdentifiers($ids);
foreach ($dl as $r) {
  printf("%s %s '%d'\n", $doc->getFamilyDocument()->getTitle(), $doc->getTitle(), $doc->id);
}

Résultat

Bill Bill0003 ADAMZIK Jack '98111'

L'objet $dl contient alors les Smart Elements pointant vers la cible.

# Callback et itérateur

# Callback sur un itérateur

Il est possible d'appliquer une fonction sur chacun des Smart Elements d'une liste de Smart Elements provenant d'un itérateur.

use Anakeen\Search\SearchElements;

$s = new SearchElements("IUSER");
$s->addFilter("us_extmail is not null");
$s->search();
$dl = $s->getResults();
$test = 1;
$callback = function (&$doc) use ($test) {
  if ($test) {
    $doc->lock();
  }
};
$dl->listMap($callback);
foreach ($dl as $docid => $doc) {
  print "$docid)" . $doc->getTitle() . "(" . $doc->getPropertyValue("locked") . ")\n";
}

Dans cet exemple, l'ensemble des Smart Elements est verrouillé.

Attention

La fonction de mapping est appelée sur chacun des Smart Elements lors de l'itération. S'il n'y a pas d'itération, la fonction de mapping n'est pas appelée.

# Callback sur un itérateur avec filtrage

La fonction de callback permet aussi d'exclure des Smart Elements de l'itérateur. Si la méthode retourne le booléen false, alors le Smart Element est exclu de la liste. Tout autre retour que le booléen false retournera le Smart Element, même s'il n'y a pas de retour explicite.

use Anakeen\Search\SearchElements;

$s = new SearchElements("IUSER");
$s->search();
$dl = $s->getResults();
$callback = function (&$doc) {
  if (!$doc->isLocked()) {
    $doc->lock();
    return true;
  }
};
$dl->listMap($callback);
foreach ($dl as $docid => $doc) {
  print "$docid)" . $doc->getTitle() . "(" . $doc->getPropertyValue("locked") . ")\n";
}

Cet exemple ne verrouillera que les Smart Elements non verrouillés et ne retournera que les Smart Element venant d'être verrouillés.

# Compter le nombre de résultats

Le nombre de résultats peut être obtenu avec la méthode SearchSmartData::count() après avoir effectué la recherche (appel SearchSmartData::search()).

use Anakeen\Search\SearchElements;

$s = new SearchElements("IUSER");
$s->search();
$c = $s->count();
print $c . " results";

Si seul le nombre vous intéresse, la méthode SearchSmartData::count() n'est pas la plus performante, car la requête est lancée et l'ensemble des résultats st récupéré. Pour des performances accrues, il faut utiliser la méthode SearchElements::onlyCount(). Ceci effectue la recherche en ne retournant que le nombre de Smart Elements correspondants.

use Anakeen\Search\SearchElements;

$s = new SearchElements("IUSER");
$s->search();
$c = $s->onlyCount();
print $c . " results";

Attention

Le premier appel à une des méthodes de SearchSmartData::search() ou SearchElements::onlyCount() lance une requête au serveur de base de données. Le résultat est mis en cache pour être exploité par les itérateurs.

use Anakeen\Search\SearchElements;

$s = new SearchElements("IUSER");
// Pas d'appel à SearchSmartData::search()
$c = $s->onlyCount(); // retourne le nombre de résultats
print $c . " results";
$s->addFilter("cdate > '%s'", date("Y-m-d"));
$s->search(); // relance la recherche

# Traitements des erreurs

Si la requête échoue suite à des erreurs SQL (souvent liées à un filtre mal formé), une exception de type Anakeen\Database\Exception ou Anakeen\Search\Exception est retournée. Ces deux type d'erreur hérite de Anakeen\Exception.

use Anakeen\Search\SearchElements;

try {
  $s = new SearchElements("IUSER");
  $s->addFilter("us_extmail is not null");
  $s->addFilter("pas bon"); // Ici une erreur de filtre
  $r = $s->search();
} catch (\Anakeen\Exception $e) {
  print $e->getMessage();
}

Résultat :

{"success":true,"data":"","messages":[]}{DB0005} query prepare error : ERROR:  syntax error at or near "bon"
LINE 1: ...cked != -1) and (us_extmail is not null) and (pas bon) ORDER...
                                                             ^

select doc128.*  from  doc128  where   (doc128.doctype != 'Z') and (doc128.doctype != 'T') and (doc128.locked != -1) and (us_extmail is not null) and (pas bon) ORDER BY title LIMIT ALL OFFSET 0;

La classe SearchElements permet de récupérer les informations sur la requête afin de débugguer votre recherche. Ces informations sont consultables avec la méthode SearchSmartData::getSearchInfo() après avoir exécuté la recherche.

use Anakeen\Search\SearchElements;

$s = new SearchElements("IUSER");
$s->addFilter("us_extmail is not null");
$s->search();
print $s->getSearchInfo();

Résultat :

[ debuginfo: Anakeen\Search\Internal\SearchSmartData: private ] => Array
(
    [ count ] => 862
    [ query ] => selectdoc128.\*fromdoc128where(doc128.doctype!='Z')and(doc128.doctype!='T')and(doc128.locked!=-1)and(us_extmailisnotnull)ORDERBYtitleLIMITALLOFFSET0;
    [ error ] =>
    [ delay ] => 0.013s
)

# Recherche détaillé

# Enregistrement d'une recherche détaillée

# Création d'une recherche par Smart Structure

La recherche détaillée (Smart Structure DSEARCH) a pour but de rechercher des Smart Elements d'une Smart Structure donnée. Elle permet aussi d'être utilisée depuis l'interface graphique ou depuis la classe SearchElements pour avoir une liste de Smart Elements suivant des critères préétablis.

$rd = SEManager::createDocument("DSEARCH");
$rd->setValue(dsearch::se_famid, "IUSER");
$rd->store();

$s = new SearchElements();
$s->useCollection($rd->initid);
$dl = $s->getResults();
foreach ($dl as $d) {
  print $d->getTitle();
}

L'affectation des critères est effectuée, en valorisant les Smart Fields du tableau se_t_detail de la Smart Structure DSEARCH.

use Anakeen\Core\SEManager;
use Anakeen\Search\SearchElements;
use SmartStructure\Fields\Dsearch as dsearch;

$rd = SEManager::createDocument("DSEARCH");
$rd->setAttributeValue(dsearch::se_famid, "IUSER");
$rd->setAttributeValue(dsearch::ba_title, "Search Active Users with email");
$criteria = array(
  array(
    dsearch::se_attrids => \SmartStructure\Fields\Iuser::us_status,
    dsearch::se_funcs => "=",
    dsearch::se_keys => "A"
  ),
  array(
    dsearch::se_attrids => \SmartStructure\Fields\Iuser::us_status,
    dsearch::se_funcs => "=",
    dsearch::se_keys => ""
  )
);
$rd->setAttributeValue(dsearch::se_t_detail, $criteria);
$rd->store();

$s = new SearchElements();
$s->useCollection($rd->initid);
$dl = $s->getResults();
foreach ($dl as $d) {
  print $d->getTitle();
}

# Enregistrement d'une recherche détaillée avec SearchElements

La recherche détaillée peut aussi être enregistrée avec une requête arbitraire. La méthode SearchHooks::addStaticQuery() permet de modifier la requête issue des critères du Smart Element recherche.

use Anakeen\Core\SEManager;
use SmartStructure\Fields\Dsearch as dsearch;

$s = new \Anakeen\Search\Internal\SearchSmartData("IUSER");
$s->addFilter("us_extmail is not null");
$sql = $s->getOriginalQuery();
$rd = SEManager::createDocument("DSEARCH");
$rd->setValue(dsearch::ba_title, "my Search");
$rd->store();
/**
 * @var \Anakeen\SmartStructures\Search\SearchHooks $mySearch
 */
$mySearch = SEManager::getDocument($rd->initid);
$mySearch->addStaticQuery($sql);

Dans ce cas, le Smart Element produit s'il est modifié par l'interface, perd ses caractéristiques spécifiques au dépend des nouveaux critères présents sur l'interface graphique.
La méthode SearchHooks::addStaticQuery() ne peut être utilisée que si le Smart Element est déjà enregistré en base de données.
La requête SQL enregistrée ne doit pas tenir compte des droits. Ces critères de droits sont ajoutés par l'utilisation de la recherche détaillé.

# Utilisation de méthodes dans l'interface de recherche détaillée

Lors de la création d'une recherche détaillé, il est possible de choisir pour un critère une méthode comme valeur.
Exemple: ma_date > ::getDate(-7)

Cet exemple indique que le critère est la date courante -7 jours. La méthode SmartElement::getDate() est une méthode statique de la classe SmartElement.
Les méthodes utilisables dans les recherches détaillées sont les méthodes de la classe de la Smart Structure sur laquelle porte la recherche qui ont un commentaire ( au format DocBlock et qui contiennent les tags @searchLabel et @searchType). Vous pouvez ainsi déclarer votre propre méthode, utilisable comme critère de recherche dans le fichier méthode de votre Smart Structure et ajouter les commentaires DocBlock adéquats. Cette méthode est généralement statique car elle ne doit pas faire appel à des valeurs de Smart Element. Par contre vous pouvez utiliser des paramètres de la Smart Strucure. La valeur de retour de cette méthode est utilisé comme valeur du critère. Cela ne peut être appliqué que sur des opérateurs nécessitant une seule valeur. Cette méthode spécifique est utilisable pour des recherches détaillées portant sur la Smart Structure en question.

Exemple de déclaration de méthode :

/**
 * Get a random integer between 1 and 10
 *
 * @searchLabel Random integer between 1 and 10
 * @searchType int
 * @searchType double
 * @searchType money
 */
public function getRandomNumber() {
    return mt_rand(1, 10);
}

Le tag @searchLabel permet de spécifier le libellé qui est présenté lors de l'affichage de la liste des méthodes compatibles (traduit en fonction de la locale de l'utilisateur).
Le tag @searchType permet de spécifier les types de Smart Fields sur lesquels cette méthode est utilisable. L'interface de composition des critères de lla recherche détaillée ne présentera alors que les méthodes compatibles avec le Smart Field du critère.
Pour des besoins plus complexes de sélection des méthodes compatibles, vous pouvez surcharger la méthode SmartElement::getSearchMethods() pour enlever ou ajouter des méthodes à la liste générée par défaut. Les méthodes que vous ajoutez devront aussi avoir les tags @searchLabel et @searchType positionné.

Exemple de surcharge de SmartElement::getSearchMethods():

public function getSearchMethods($attrId, $attrType) {
    $methods = parent::getSearchMethods($attrId, $attrType);
    if ($attrType == 'date' || $attrType == 'timestamp') {
        /*
         * Ajouter avant-hier et après-demain
         * pour les attributs de type 'date' et 'timestamp'
         */
        $methods = array_merge(
            $methods,
            array(
                array(
                    'label' => _("Day before yesterday"),
                    'method' => '::getDate(-2)'
                ),
                array(
                    'label' => _("Day after tomorrow"),
                    'method' => '::getDate(2)'
                )
            )
        );
    }
    return $methods
}

# Rapports

Les rapports (Smart Structure REPORT) héritent de la Smart Structure recherche détaillée (Smart StructureDSEARCH).

# Création d'un rapport

# Critères de recherche

L'enregistrement de la requête est identique à celle de la recherche détaillée.

use Anakeen\Core\SEManager;
use Anakeen\Search\SearchElements;
use SmartStructure\Fields\Dsearch as dsearch;

$rd = SEManager::createDocument("REPORT");
$rd->setAttributeValue(dsearch::ba_title, "Report with toview Tag");
$rd->setAttributeValue(dsearch::se_famid, "IUSER");
$rd->setAttributeValue(dsearch::ba_title, "Report Active Users with email");
$criteria = array(
  array(
    dsearch::se_attrids => \SmartStructure\Fields\Iuser::us_status,
    dsearch::se_funcs => "=",
    dsearch::se_keys => "A"
  ),
  array(
    dsearch::se_attrids => \SmartStructure\Fields\Iuser::us_extmail,
    dsearch::se_funcs => "is not null",
    dsearch::se_keys => ""
  )
);
$rd->setAttributeValue(dsearch::se_t_detail, $criteria);
$rd->store();

$s = new SearchElements();
$s->useCollection($rd->initid);
$dl = $s->getResults();
foreach ($dl as $d) {
  print $d->getTitle();
}

# Présentation du rapport

Les colonnes à afficher sont indiquées par le Smart Field rep_idcols. Ce Smart Field doit contenir un identnifiant de Smart Field ou de propriété.

$columns = array(
  array(
    Attribute\Report::rep_lcols => "Utilisateurs",
    Attribute\Report::rep_idcols => "title",
    Attribute\Report::rep_foots => "CARD"
  ),
  array(
    Attribute\Report::rep_lcols => "Utilisateurs",
    Attribute\Report::rep_idcols => Attribute\Iuser::us_whatid
  ),
  array(
    Attribute\Report::rep_lcols => "Courriel",
    Attribute\Report::rep_idcols => Attribute\Iuser::us_mail
  ),
  array(
    Attribute\Report::rep_lcols => "Groupes",
    Attribute\Report::rep_idcols => Attribute\Iuser::us_idgroup
  ),
  array(
    Attribute\Report::rep_lcols => "Identifiant groupes",
    Attribute\Report::rep_displayoption => "docid",
    Attribute\Report::rep_idcols => Attribute\Iuser::us_idgroup
  )
);

$report->setAttributeValue(Attribute\Report::rep_tcols, $columns);
$report->setAttributeValue(Attribute\Report::rep_style, "standard1");
$report->store();

Le Smart Field rep_lcols (libellé) n'est pas utilisé lors de la génération. Le libellé affiché correspond au libellé du Smart Field ou de la propriété.
Pour le cas particulier des Smart fields de type docid et de type account si le Smart field req_displayoption, si le Smart Fields rep_displayoption vaut docid, alors ce sont les identifiants des Smart Fields qui sont affichés au lieu des titres des Smart Fields.
Pour la propriété title, des précautions doivent être prise en cas de surcharge du titre.

# Recherche spécialisée

Pour toute recherche non prévue en standard par l'interface, il est possible de programmer des recherches spécifiques. Elles pourront ensuite être utilisées comme une recherche "normale" depuis l'interface grâce à la Smart Structure recherche spécialisée. Lorsque vous éditez une recherche spécialisée, vous devez renseigner :

  • Le fichier PHP où se trouve la fonction de recherche,

    Ce fichier doit être dans le répertoire EXTERNALS du contexte.

  • Le nom de cette fonction.

    Cette fonction prend les 3 arguments suivants:

    • start: index de de départ pour la recherche.
    • slice : nombre max d'élément à retourner.
    • userid : utilisateur courant.

Des arguments supplémentaires peuvent êgalement être fournis:

Exemple: Fichier ÈXTERNALS/my.test.phpp$

namespace My;

use Anakeen\Search\SearchElementData;

/**
 * function use for specialised search
 * return all Smart Element tagged TOVIEWDOC by current usr=er
 *
 * @param int $start start cursor
 * @param int $slice offset ("ALL" means no limit)
 * @param int $userid user system identifier (NOT USED in this function)
 *
 */
function myToViewTags($start = "0", $slice = "ALL", $userid = 0)
{
  $tag = "TOVIEWDOC";
  $s = new SearchElementData();
  $s->join("id = docutag(id)");
  $s->setSlice($slice);
  $s->setStart($start);
  $s->addFilter("docutag.uid = %d", $userid);
  $s->addFilter("docutag.tag = '%s'", $tag);
  return $s->search()->getResults();
}

# Enregistrement d'une recherche spécialisée

L'enregistrement se fait en créant un Smart Element de la Smart Structure SSEARCH. Les Smart Fields se_phpfile et se_phpfunc permettent d'indiquer la fonction à utiliser.

use Anakeen\Core\SEManager;
use SmartStructure\Fields\Ssearch as ssearch;

$sd = SEManager::createDocument("SSEARCH");
$sd->setValue(ssearch::ba_title, "Search TOVIEWDOC Tag");
$sd->setValue(ssearch::se_phpfile, "myTest.php"); //EXTERNALS/myTest.php
$sd->setValue(ssearch::se_phpfunc, "My\\myToViewTags");
$sd->store();

# Arguments supplémentaires de la fonction

Des arguments supplémentaires peuvent être ajoutés dans le Smart Field ArgumentPHP' (se_phparg`). Ils sont ajoutés dans l'appel à partir de la quatrième position. Pour ajouter plusieurs arguments, il faut les séparer par une virgule (exemple: 2134,ceci est un test, dernier argument).
Dans ces arguments, il est possible de référencer:

  • N'importe quel Smart Field ou propriété du Smart Element recherche, au moyen de la notation %ATTRID% ou %PROPID%,

    Par exemple, %TITLE% pour avoir le titre de la recherche

  • L'objet recherche lui-même au moyen du mot clé %THIS%.

# Retour de la fonction

La fonction de recherche doit retourner un tableau de Smart Elements bruts (type array et non object). Ce type est celui retourné par la classe SearchElements.