|
|
|
<?php
|
|
|
|
|
|
|
|
/***************************************************************************\
|
|
|
|
* SPIP, Systeme de publication pour l'internet *
|
|
|
|
* *
|
|
|
|
* Copyright (c) 2001-2016 *
|
|
|
|
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
|
|
|
|
* *
|
|
|
|
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
|
|
|
|
* Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
|
|
|
|
\***************************************************************************/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Définition des {criteres} d'une boucle
|
|
|
|
*
|
|
|
|
* @package SPIP\Compilateur\Criteres
|
|
|
|
**/
|
|
|
|
|
|
|
|
if (!defined('_ECRIRE_INC_VERSION')) return;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Une Regexp repérant une chaine produite par le compilateur,
|
|
|
|
* souvent utilisée pour faire de la concaténation lors de la compilation
|
|
|
|
* plutôt qu'à l'exécution, i.e. pour remplacer 'x'.'y' par 'xy'
|
|
|
|
**/
|
|
|
|
define('_CODE_QUOTE', ",^(\n//[^\n]*\n)? *'(.*)' *$,");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Compile le critère {racine}
|
|
|
|
*
|
|
|
|
* Ce critère sélectionne les éléments à la racine d'une hiérarchie,
|
|
|
|
* c'est à dire ayant id_parent=0
|
|
|
|
*
|
|
|
|
* @link http://www.spip.net/@racine
|
|
|
|
*
|
|
|
|
* @param string $idb
|
|
|
|
* Identifiant de la boucle
|
|
|
|
* @param array $boucles
|
|
|
|
* AST du squelette
|
|
|
|
* @param array $crit
|
|
|
|
* Paramètres du critère dans cette boucle
|
|
|
|
* @return
|
|
|
|
* AST complété de la gestion du critère
|
|
|
|
**/
|
|
|
|
function critere_racine_dist($idb, &$boucles, $crit){
|
|
|
|
global $exceptions_des_tables;
|
|
|
|
$not = $crit->not;
|
|
|
|
$boucle = &$boucles[$idb];
|
|
|
|
$id_parent = isset($exceptions_des_tables[$boucle->id_table]['id_parent']) ?
|
|
|
|
$exceptions_des_tables[$boucle->id_table]['id_parent'] :
|
|
|
|
'id_parent';
|
|
|
|
|
|
|
|
$c = array("'='", "'$boucle->id_table."."$id_parent'", 0);
|
|
|
|
$boucle->where[] = ($crit->not ? array("'NOT'", $c) : $c);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Compile le critère {exclus}
|
|
|
|
*
|
|
|
|
* Exclut du résultat l’élément dans lequel on se trouve déjà
|
|
|
|
*
|
|
|
|
* @link http://www.spip.net/@exclus
|
|
|
|
*
|
|
|
|
* @param string $idb
|
|
|
|
* Identifiant de la boucle
|
|
|
|
* @param array $boucles
|
|
|
|
* AST du squelette
|
|
|
|
* @param array $crit
|
|
|
|
* Paramètres du critère dans cette boucle
|
|
|
|
* @return
|
|
|
|
* AST complété de la gestion du critère
|
|
|
|
**/
|
|
|
|
function critere_exclus_dist($idb, &$boucles, $crit){
|
|
|
|
$not = $crit->not;
|
|
|
|
$boucle = &$boucles[$idb];
|
|
|
|
$id = $boucle->primary;
|
|
|
|
|
|
|
|
if ($not OR !$id)
|
|
|
|
return (array('zbug_critere_inconnu', array('critere' => $not.$crit->op)));
|
|
|
|
$arg = kwote(calculer_argument_precedent($idb, $id, $boucles));
|
|
|
|
$boucle->where[] = array("'!='", "'$boucle->id_table."."$id'", $arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Compile le critère {doublons} ou {unique}
|
|
|
|
*
|
|
|
|
* Ce critères enlève de la boucle les éléments déjà sauvegardés
|
|
|
|
* dans un précédent critère {doublon} sur une boucle de même table.
|
|
|
|
*
|
|
|
|
* Il est possible de spécifier un nom au doublon tel que {doublons sommaire}
|
|
|
|
*
|
|
|
|
* @link http://www.spip.net/@doublons
|
|
|
|
*
|
|
|
|
* @param string $idb
|
|
|
|
* Identifiant de la boucle
|
|
|
|
* @param array $boucles
|
|
|
|
* AST du squelette
|
|
|
|
* @param array $crit
|
|
|
|
* Paramètres du critère dans cette boucle
|
|
|
|
* @return
|
|
|
|
* AST complété de la gestion du critère
|
|
|
|
**/
|
|
|
|
function critere_doublons_dist($idb, &$boucles, $crit){
|
|
|
|
$boucle = &$boucles[$idb];
|
|
|
|
$primary = $boucle->primary;
|
|
|
|
|
|
|
|
// la table nécessite une clé primaire, non composée
|
|
|
|
if (!$primary OR strpos($primary, ',')){
|
|
|
|
return (array('zbug_doublon_sur_table_sans_cle_primaire'));
|
|
|
|
}
|
|
|
|
|
|
|
|
$not = ($crit->not ? '' : 'NOT');
|
|
|
|
|
|
|
|
// le doublon s'applique sur un type de boucle (article)
|
|
|
|
$nom = "'" . $boucle->type_requete. "'";
|
|
|
|
|
|
|
|
// compléter le nom avec un nom précisé {doublons nom}
|
|
|
|
// on obtient $nom = "'article' . 'nom'"
|
|
|
|
if (isset($crit->param[0])) {
|
|
|
|
$nom .= "." . calculer_liste($crit->param[0], array(), $boucles, $boucles[$idb]->id_parent);
|
|
|
|
}
|
|
|
|
|
|
|
|
// code qui déclarera l'index du stockage de nos doublons (pour éviter une notice PHP)
|
|
|
|
$init_comment = "\n\n\t// Initialise le(s) critère(s) doublons\n";
|
|
|
|
$init_code = "\tif (!isset(\$doublons[\$d = $nom])) { \$doublons[\$d] = ''; }\n";
|
|
|
|
|
|
|
|
// on crée un sql_in avec la clé primaire de la table
|
|
|
|
// et la collection des doublons déjà emmagasinés dans le tableau
|
|
|
|
// $doublons et son index, ici $nom
|
|
|
|
|
|
|
|
// debut du code "sql_in('articles.id_article', "
|
|
|
|
$debut_in = "sql_in('".$boucle->id_table.'.'.$primary."', ";
|
|
|
|
// lecture des données du doublon "$doublons[$doublon_index[] = "
|
|
|
|
// Attention : boucle->doublons désigne une variable qu'on affecte
|
|
|
|
$debut_doub = '$doublons[' . (!$not ? '' : ($boucle->doublons."[]= "));
|
|
|
|
|
|
|
|
// le debut complet du code des doublons
|
|
|
|
$debut_doub = $debut_in . $debut_doub;
|
|
|
|
|
|
|
|
// nom du doublon "('article' . 'nom')]"
|
|
|
|
$fin_doub = "($nom)]";
|
|
|
|
|
|
|
|
// si on trouve un autre critère doublon,
|
|
|
|
// on fusionne pour avoir un seul IN, et on s'en va !
|
|
|
|
foreach ($boucle->where as $k => $w) {
|
|
|
|
if (strpos($w[0], $debut_doub)===0) {
|
|
|
|
// fusionner le sql_in (du where)
|
|
|
|
$boucle->where[$k][0] = $debut_doub . $fin_doub.' . '.substr($w[0], strlen($debut_in));
|
|
|
|
// fusionner l'initialisation (du hash) pour faire plus joli
|
|
|
|
$x = strpos($boucle->hash, $init_comment);
|
|
|
|
$len = strlen($init_comment);
|
|
|
|
$boucle->hash =
|
|
|
|
substr($boucle->hash, 0, $x + $len) . $init_code . substr($boucle->hash, $x + $len);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// mettre l'ensemble dans un tableau pour que ce ne soit pas vu comme une constante
|
|
|
|
$boucle->where[] = array($debut_doub . $fin_doub.", '".$not."')");
|
|
|
|
|
|
|
|
// déclarer le doublon s'il n'existe pas encore
|
|
|
|
$boucle->hash .= $init_comment . $init_code;
|
|
|
|
|
|
|
|
|
|
|
|
# la ligne suivante avait l'intention d'eviter une collecte deja faite
|
|
|
|
# mais elle fait planter une boucle a 2 critere doublons:
|
|
|
|
# {!doublons A}{doublons B}
|
|
|
|
# (de http://article.gmane.org/gmane.comp.web.spip.devel/31034)
|
|
|
|
# if ($crit->not) $boucle->doublons = "";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Compile le critère {lang_select}
|
|
|
|
*
|
|
|
|
* Permet de restreindre ou non une boucle en affichant uniquement
|
|
|
|
* les éléments dans la langue en cours. Certaines boucles
|
|
|
|
* tel que articles et rubriques restreignent par défaut sur la langue
|
|
|
|
* en cours.
|
|
|
|
*
|
|
|
|
* Sans définir de valeur au critère, celui-ci utilise 'oui' comme
|
|
|
|
* valeur par défaut.
|
|
|
|
*
|
|
|
|
* @param string $idb
|
|
|
|
* Identifiant de la boucle
|
|
|
|
* @param array $boucles
|
|
|
|
* AST du squelette
|
|
|
|
* @param array $crit
|
|
|
|
* Paramètres du critère dans cette boucle
|
|
|
|
* @return
|
|
|
|
* AST complété de la gestion du critère
|
|
|
|
**/
|
|
|
|
function critere_lang_select_dist($idb, &$boucles, $crit){
|
|
|
|
if (!isset($crit->param[1][0]) OR !($param = $crit->param[1][0]->texte)) $param = 'oui';
|
|
|
|
if ($crit->not) $param = ($param=='oui') ? 'non' : 'oui';
|
|
|
|
$boucle = &$boucles[$idb];
|
|
|
|
$boucle->lang_select = $param;
|
|
|
|
}
|
|
|
|
|
|
|
|
// {debut_xxx}
|
|
|
|
// http://www.spip.net/@debut_
|
|
|
|
// http://doc.spip.org/@critere_debut_dist
|
|
|
|
function critere_debut_dist($idb, &$boucles, $crit){
|
|
|
|
list($un, $deux) = $crit->param;
|
|
|
|
$un = $un[0]->texte;
|
|
|
|
$deux = $deux[0]->texte;
|
|
|
|
if ($deux){
|
|
|
|
$boucles[$idb]->limit = 'intval($Pile[0]["debut'.
|
|
|
|
$un.
|
|
|
|
'"]) . ",'.
|
|
|
|
$deux.
|
|
|
|
'"';
|
|
|
|
} else calculer_critere_DEFAUT_dist($idb, $boucles, $crit);
|
|
|
|
}
|
|
|
|
|
|
|
|
// {pagination}
|
|
|
|
// {pagination 20}
|
|
|
|
// {pagination #ENV{pages,5}} etc
|
|
|
|
// {pagination 20 #ENV{truc,chose}} pour utiliser la variable debut_#ENV{truc,chose}
|
|
|
|
// http://www.spip.net/@pagination
|
|
|
|
// http://doc.spip.org/@critere_pagination_dist
|
|
|
|
function critere_pagination_dist($idb, &$boucles, $crit){
|
|
|
|
|
|
|
|
$boucle = &$boucles[$idb];
|
|
|
|
// definition de la taille de la page
|
|
|
|
$pas = !isset($crit->param[0][0]) ? "''"
|
|
|
|
: calculer_liste(array($crit->param[0][0]), array(), $boucles, $boucle->id_parent);
|
|
|
|
|
|
|
|
if (!preg_match(_CODE_QUOTE, $pas, $r)){
|
|
|
|
$pas = "((\$a = intval($pas)) ? \$a : 10)";
|
|
|
|
} else {
|
|
|
|
$r = intval($r[2]);
|
|
|
|
$pas = strval($r ? $r : 10);
|
|
|
|
}
|
|
|
|
$type = !isset($crit->param[0][1]) ? "'$idb'"
|
|
|
|
: calculer_liste(array($crit->param[0][1]), array(), $boucles, $boucle->id_parent);
|
|
|
|
$debut = ($type[0]!=="'") ? "'debut'.$type"
|
|
|
|
: ("'debut".substr($type, 1));
|
|
|
|
|
|
|
|
$boucle->modificateur['debut_nom'] = $type;
|
|
|
|
$partie =
|
|
|
|
// tester si le numero de page demande est de la forme '@yyy'
|
|
|
|
'isset($Pile[0]['.$debut.']) ? $Pile[0]['.$debut.'] : _request('.$debut.");\n"
|
|
|
|
."\tif(substr(\$debut_boucle,0,1)=='@'){\n"
|
|
|
|
."\t\t".'$debut_boucle = $Pile[0]['.$debut.'] = quete_debut_pagination(\''.$boucle->primary.'\',$Pile[0][\'@'.$boucle->primary.'\'] = substr($debut_boucle,1),'.$pas.',$iter);'."\n"
|
|
|
|
."\t\t".'$iter->seek(0);'."\n"
|
|
|
|
."\t}\n"
|
|
|
|
."\t".'$debut_boucle = intval($debut_boucle)';
|
|
|
|
|
|
|
|
$boucle->hash .= '
|
|
|
|
$command[\'pagination\'] = array((isset($Pile[0]['.$debut.']) ? $Pile[0]['.$debut.'] : null), ' . $pas . ');';
|
|
|
|
|
|
|
|
$boucle->total_parties = $pas;
|
|
|
|
calculer_parties($boucles, $idb, $partie, 'p+');
|
|
|
|
// ajouter la cle primaire dans le select pour pouvoir gerer la pagination referencee par @id
|
|
|
|
// sauf si pas de primaire, ou si primaire composee
|
|
|
|
// dans ce cas, on ne sait pas gerer une pagination indirecte
|
|
|
|
$t = $boucle->id_table.'.'.$boucle->primary;
|
|
|
|
if ($boucle->primary
|
|
|
|
AND !preg_match('/[,\s]/', $boucle->primary)
|
|
|
|
AND !in_array($t, $boucle->select)
|
|
|
|
)
|
|
|
|
$boucle->select[] = $t;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// {recherche} ou {recherche susan}
|
|
|
|
// http://www.spip.net/@recherche
|
|
|
|
// http://doc.spip.org/@critere_recherche_dist
|
|
|
|
function critere_recherche_dist($idb, &$boucles, $crit){
|
|
|
|
|
|
|
|
$boucle = &$boucles[$idb];
|
|
|
|
|
|
|
|
if (!$boucle->primary OR strpos($boucle->primary, ',')){
|
|
|
|
erreur_squelette(_T('zbug_critere_sur_table_sans_cle_primaire',array('critere'=>'recherche')), $boucle);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isset($crit->param[0]))
|
|
|
|
$quoi = calculer_liste($crit->param[0], array(), $boucles, $boucles[$idb]->id_parent);
|
|
|
|
else
|
|
|
|
$quoi = '(isset($Pile[0]["recherche"])?$Pile[0]["recherche"]:(isset($GLOBALS["recherche"])?$GLOBALS["recherche"]:""))';
|
|
|
|
|
|
|
|
$_modificateur = var_export($boucle->modificateur, true);
|
|
|
|
$boucle->hash .= '
|
|
|
|
// RECHERCHE'
|
|
|
|
.($crit->cond ? '
|
|
|
|
if (!strlen('.$quoi.')){
|
|
|
|
list($rech_select, $rech_where) = array("0 as points","");
|
|
|
|
} else' : '').'
|
|
|
|
{
|
|
|
|
$prepare_recherche = charger_fonction(\'prepare_recherche\', \'inc\');
|
|
|
|
list($rech_select, $rech_where) = $prepare_recherche('.$quoi.', "'.$boucle->id_table.'", "'.$crit->cond.'","'.$boucle->sql_serveur.'",'.$_modificateur.',"'.$boucle->primary.'");
|
|
|
|
}
|
|
|
|
';
|
|
|
|
|
|
|
|
|
|
|
|
$t = $boucle->id_table.'.'.$boucle->primary;
|
|
|
|
if (!in_array($t, $boucles[$idb]->select))
|
|
|
|
$boucle->select[] = $t; # pour postgres, neuneu ici
|
|
|
|
// jointure uniquement sur le serveur principal
|
|
|
|
// (on ne peut joindre une table d'un serveur distant avec la table des resultats du serveur principal)
|
|
|
|
if (!$boucle->sql_serveur){
|
|
|
|
$boucle->join['resultats'] = array("'".$boucle->id_table."'", "'id'", "'".$boucle->primary."'");
|
|
|
|
$boucle->from['resultats'] = 'spip_resultats';
|
|
|
|
}
|
|
|
|
$boucle->select[] = '$rech_select';
|
|
|
|
//$boucle->where[]= "\$rech_where?'resultats.id=".$boucle->id_table.".".$boucle->primary."':''";
|
|
|
|
|
|
|
|
// et la recherche trouve
|
|
|
|
$boucle->where[] = '$rech_where?$rech_where:\'\'';
|
|
|
|
}
|
|
|
|
|
|
|
|
// {traduction}
|
|
|
|
// http://www.spip.net/@traduction
|
|
|
|
// (id_trad>0 AND id_trad=id_trad(precedent))
|
|
|
|
// OR id_article=id_article(precedent)
|
|
|
|
// http://doc.spip.org/@critere_traduction_dist
|
|
|
|
function critere_traduction_dist($idb, &$boucles, $crit){
|
|
|
|
$boucle = &$boucles[$idb];
|
|
|
|
$prim = $boucle->primary;
|
|
|
|
$table = $boucle->id_table;
|
|
|
|
$arg = kwote(calculer_argument_precedent($idb, 'id_trad', $boucles));
|
|
|
|
$dprim = kwote(calculer_argument_precedent($idb, $prim, $boucles));
|
|
|
|
$boucle->where[] =
|
|
|
|
array("'OR'",
|
|
|
|
array("'AND'",
|
|
|
|
array("'='", "'$table.id_trad'", 0),
|
|
|
|
array("'='", "'$table.$prim'", $dprim)
|
|
|
|
),
|
|
|
|
array("'AND'",
|
|
|
|
array("'>'", "'$table.id_trad'", 0),
|
|
|
|
array("'='", "'$table.id_trad'", $arg)
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// {origine_traduction}
|
|
|
|
// (id_trad>0 AND id_article=id_trad) OR (id_trad=0)
|
|
|
|
// http://www.spip.net/@origine_traduction
|
|
|
|
// http://doc.spip.org/@critere_origine_traduction_dist
|
|
|
|
function critere_origine_traduction_dist($idb, &$boucles, $crit){
|
|
|
|
$boucle = &$boucles[$idb];
|
|
|
|
$prim = $boucle->primary;
|
|
|
|
$table = $boucle->id_table;
|
|
|
|
|
|
|
|
$c =
|
|
|
|
array("'OR'",
|
|
|
|
array("'='", "'$table."."id_trad'", "'$table.$prim'"),
|
|
|
|
array("'='", "'$table.id_trad'", "'0'")
|
|
|
|
);
|
|
|
|
$boucle->where[] = ($crit->not ? array("'NOT'", $c) : $c);
|
|
|
|
}
|
|
|
|
|
|
|
|
// {meme_parent}
|
|
|
|
// http://www.spip.net/@meme_parent
|
|
|
|
// http://doc.spip.org/@critere_meme_parent_dist
|
|
|
|
function critere_meme_parent_dist($idb, &$boucles, $crit){
|
|
|
|
global $exceptions_des_tables;
|
|
|
|
$boucle = &$boucles[$idb];
|
|
|
|
$arg = kwote(calculer_argument_precedent($idb, 'id_parent', $boucles));
|
|
|
|
$id_parent = isset($exceptions_des_tables[$boucle->id_table]['id_parent']) ?
|
|
|
|
$exceptions_des_tables[$boucle->id_table]['id_parent'] :
|
|
|
|
'id_parent';
|
|
|
|
$mparent = $boucle->id_table.'.'.$id_parent;
|
|
|
|
|
|
|
|
if ($boucle->type_requete=='rubriques' OR isset($exceptions_des_tables[$boucle->id_table]['id_parent'])){
|
|
|
|
$boucle->where[] = array("'='", "'$mparent'", $arg);
|
|
|
|
|
|
|
|
}
|
|
|
|
// le cas FORUMS est gere dans le plugin forum, dans la fonction critere_FORUMS_meme_parent_dist()
|
|
|
|
else {
|
|
|
|
return (array('zbug_critere_inconnu', array('critere' => $crit->op.' '.$boucle->type_requete)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sélectionne dans une boucle les éléments appartenant à une branche d'une rubrique
|
|
|
|
*
|
|
|
|
* Calcule une branche d'une rubrique et conditionne la boucle avec.
|
|
|
|
* Cherche l'identifiant de la rubrique dans les boucles parentes ou par jointure
|
|
|
|
* et calcule la liste des identifiants de rubrique de toute la branche
|
|
|
|
*
|
|
|
|
* @link http://www.spip.net/@branche
|
|
|
|
*
|
|
|
|
* @param string $idb
|
|
|
|
* Identifiant de la boucle
|
|
|
|
* @param array $boucles
|
|
|
|
* AST du squelette
|
|
|
|
* @param array $crit
|
|
|
|
* Paramètres du critère dans cette boucle
|
|
|
|
* @return
|
|
|
|
* AST complété de la condition where au niveau de la boucle,
|
|
|
|
* restreignant celle ci aux rubriques de la branche
|
|
|
|
**/
|
|
|
|
function critere_branche_dist($idb, &$boucles, $crit){
|
|
|
|
|
|
|
|
$not = $crit->not;
|
|
|
|
$boucle = &$boucles[$idb];
|
|
|
|
$arg = calculer_argument_precedent($idb, 'id_rubrique', $boucles);
|
|
|
|
|
|
|
|
//Trouver une jointure
|
|
|
|
$champ = "id_rubrique";
|
|
|
|
$desc = $boucle->show;
|
|
|
|
//Seulement si necessaire
|
|
|
|
if (!array_key_exists($champ, $desc['field'])){
|
|
|
|
$cle = trouver_jointure_champ($champ, $boucle);
|
|
|
|
$trouver_table = charger_fonction("trouver_table", "base");
|
|
|
|
$desc = $trouver_table($boucle->from[$cle]);
|
|
|
|
if (count(trouver_champs_decomposes($champ, $desc))>1){
|
|
|
|
$decompose = decompose_champ_id_objet($champ);
|
|
|
|
$champ = array_shift($decompose);
|
|
|
|
$boucle->where[] = array("'='", _q($cle.".".reset($decompose)), '"'.sql_quote(end($decompose)).'"');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else $cle = $boucle->id_table;
|
|
|
|
|
|
|
|
$c = "sql_in('$cle".".$champ', calcul_branche_in($arg)"
|
|
|
|
.($not ? ", 'NOT'" : '').")";
|
|
|
|
$boucle->where[] = !$crit->cond ? $c :
|
|
|
|
("($arg ? $c : ".($not ? "'0=1'" : "'1=1'").')');
|
|
|
|
}
|
|
|
|
|
|
|
|
// {logo} liste les objets qui ont un logo
|
|
|
|
// http://doc.spip.org/@critere_logo_dist
|
|
|
|
function critere_logo_dist($idb, &$boucles, $crit){
|
|
|
|
|
|
|
|
$not = $crit->not;
|
|
|
|
$boucle = &$boucles[$idb];
|
|
|
|
|
|
|
|
$c = "sql_in('".
|
|
|
|
$boucle->id_table.'.'.$boucle->primary
|
|
|
|
."', lister_objets_avec_logos('".$boucle->primary."'), '')";
|
|
|
|
|
|
|
|
if ($crit->cond) $c = "($arg ? $c : 1)";
|
|
|
|
|
|
|
|
if ($not)
|
|
|
|
$boucle->where[] = array("'NOT'", $c);
|
|
|
|
else
|
|
|
|
$boucle->where[] = $c;
|
|
|
|
}
|
|
|
|
|
|
|
|
// c'est la commande SQL "GROUP BY"
|
|
|
|
// par exemple <boucle(articles){fusion lang}>
|
|
|
|
// http://doc.spip.org/@critere_fusion_dist
|
|
|
|
function critere_fusion_dist($idb, &$boucles, $crit){
|
|
|
|
if ($t = isset($crit->param[0])){
|
|
|
|
$t = $crit->param[0];
|
|
|
|
if ($t[0]->type=='texte'){
|
|
|
|
$t = $t[0]->texte;
|
|
|
|
if (preg_match("/^(.*)\.(.*)$/", $t, $r)){
|
|
|
|
$t = table_objet_sql($r[1]);
|
|
|
|
$t = array_search($t, $boucles[$idb]->from);
|
|
|
|
if ($t) $t .= '.'.$r[2];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$t = '".'
|
|
|
|
.calculer_critere_arg_dynamique($idb, $boucles, $t)
|
|
|
|
.'."';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ($t){
|
|
|
|
$boucles[$idb]->group[] = $t;
|
|
|
|
if (!in_array($t, $boucles[$idb]->select))
|
|
|
|
$boucles[$idb]->select[] = $t;
|
|
|
|
} else
|
|
|
|
return (array('zbug_critere_inconnu', array('critere' => $crit->op.' ?')));
|
|
|
|
}
|
|
|
|
|
|
|
|
// c'est la commande SQL "COLLATE"
|
|
|
|
// qui peut etre appliquee sur les order by, group by, where like ...
|
|
|
|
// http://doc.spip.org/@critere_collecte_dist
|
|
|
|
function critere_collecte_dist($idb, &$boucles, $crit){
|
|
|
|
if (isset($crit->param[0])){
|
|
|
|
$_coll = calculer_liste($crit->param[0], array(), $boucles, $boucles[$idb]->id_parent);
|
|
|
|
$boucle = $boucles[$idb];
|
|
|
|
$boucle->modificateur['collate'] = "($_coll ?' COLLATE '.$_coll:'')";
|
|
|
|
$n = count($boucle->order);
|
|
|
|
if ($n && (strpos($boucle->order[$n-1], 'COLLATE')===false))
|
|
|
|
$boucle->order[$n-1] .= " . ".$boucle->modificateur['collate'];
|
|
|
|
} else
|
|
|
|
return (array('zbug_critere_inconnu', array('critere' => $crit->op." ".count($boucles[$idb]->order))));
|
|
|
|
}
|
|
|
|
|
|
|
|
// http://doc.spip.org/@calculer_critere_arg_dynamique
|
|
|
|
function calculer_critere_arg_dynamique($idb, &$boucles, $crit, $suffix = ''){
|
|
|
|
$boucle = $boucles[$idb];
|
|
|
|
$alt = "('".$boucle->id_table.'.\' . $x'.$suffix.')';
|
|
|
|
$var = '$champs_'.$idb;
|
|
|
|
$desc = (strpos($boucle->in, "static $var =")!==false);
|
|
|
|
if (!$desc){
|
|
|
|
$desc = $boucle->show['field'];
|
|
|
|
$desc = implode(',', array_map('_q', array_keys($desc)));
|
|
|
|
$boucles[$idb]->in .= "\n\tstatic $var = array(".$desc.");";
|
|
|
|
}
|
|
|
|
if ($desc) $alt = "(in_array(\$x, $var) ? $alt :(\$x$suffix))";
|
|
|
|
$arg = calculer_liste($crit, array(), $boucles, $boucle->id_parent);
|
|
|
|
return "((\$x = preg_replace(\"/\\W/\",'', $arg)) ? $alt : '')";
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tri : {par xxxx}
|
|
|
|
// http://www.spip.net/@par
|
|
|
|
// http://doc.spip.org/@critere_par_dist
|
|
|
|
function critere_par_dist($idb, &$boucles, $crit){
|
|
|
|
return critere_parinverse($idb, $boucles, $crit);
|
|
|
|
}
|
|
|
|
|
|
|
|
// http://doc.spip.org/@critere_parinverse
|
|
|
|
function critere_parinverse($idb, &$boucles, $crit, $sens = ''){
|
|
|
|
global $exceptions_des_jointures;
|
|
|
|
$boucle = &$boucles[$idb];
|
|
|
|
if ($crit->not) $sens = $sens ? "" : " . ' DESC'";
|
|
|
|
$collecte = (isset($boucle->modificateur['collecte'])) ? " . ".$boucle->modificateur['collecte'] : "";
|
|
|
|
|
|
|
|
foreach ($crit->param as $tri){
|
|
|
|
|
|
|
|
$order = $fct = ""; // en cas de fonction SQL
|
|
|
|
// tris specifies dynamiquement
|
|
|
|
if ($tri[0]->type!='texte'){
|
|
|
|
// calculer le order dynamique qui verifie les champs
|
|
|
|
$order = calculer_critere_arg_dynamique($idb, $boucles, $tri, $sens);
|
|
|
|
// et si ce n'est fait, ajouter un champ 'hasard'
|
|
|
|
// pour supporter 'hasard' comme tri dynamique
|
|
|
|
$par = "rand()";
|
|
|
|
$parha = $par." AS hasard";
|
|
|
|
if (!in_array($parha, $boucle->select))
|
|
|
|
$boucle->select[] = $parha;
|
|
|
|
} else {
|
|
|
|
$par = array_shift($tri);
|
|
|
|
$par = $par->texte;
|
|
|
|
// par multi champ
|
|
|
|
if (preg_match(",^multi[\s]*(.*)$,", $par, $m)){
|
|
|
|
$champ = trim($m[1]);
|
|
|
|
// par multi L1.champ
|
|
|
|
if (strpos($champ, '.')) {
|
|
|
|
$cle = '';
|
|
|
|
// par multi champ (champ sur une autre table)
|
|
|
|
} elseif (!array_key_exists($champ, $boucle->show['field'])){
|
|
|
|
$cle = trouver_jointure_champ($champ, $boucle);
|
|
|
|
// par multi champ (champ dans la table en cours)
|
|
|
|
} else {
|
|
|
|
$cle = $boucle->id_table;
|
|
|
|
}
|
|
|
|
if ($cle) { $cle .= '.'; }
|
|
|
|
$texte = $cle.$champ;
|
|
|
|
$boucle->select[] = "\".sql_multi('".$texte."', \$GLOBALS['spip_lang']).\"";
|
|
|
|
$order = "'multi'";
|
|
|
|
// par num champ(, suite)
|
|
|
|
} else if (preg_match(",^num (.*)$,m", $par, $m)) {
|
|
|
|
$champ = trim($m[1]);
|
|
|
|
// par num L1.champ
|
|
|
|
if (strpos($champ, '.')) {
|
|
|
|
$cle = '';
|
|
|
|
// par num champ (champ sur une autre table)
|
|
|
|
} elseif (!array_key_exists($champ, $boucle->show['field'])){
|
|
|
|
$cle = trouver_jointure_champ($champ, $boucle);
|
|
|
|
// par num champ (champ dans la table en cours)
|
|
|
|
} else {
|
|
|
|
$cle = $boucle->id_table;
|
|
|
|
}
|
|
|
|
if ($cle) { $cle .= '.'; }
|
|
|
|
$texte = '0+'. $cle . $champ;
|
|
|
|
$suite = calculer_liste($tri, array(), $boucles, $boucle->id_parent);
|
|
|
|
if ($suite!=="''")
|
|
|
|
$texte = "\" . ((\$x = $suite) ? ('$texte' . \$x) : '0')"." . \"";
|
|
|
|
$as = 'num'.($boucle->order ? count($boucle->order) : "");
|
|
|
|
$boucle->select[] = $texte." AS $as";
|
|
|
|
$order = "'$as'";
|
|
|
|
} else {
|
|
|
|
if (!preg_match(",^".CHAMP_SQL_PLUS_FONC.'$,is', $par, $match)){
|
|
|
|
return (array('zbug_critere_inconnu', array('critere' => $crit->op." $par")));
|
|
|
|
} else {
|
|
|
|
if (count($match)>2){
|
|
|
|
$par = substr($match[2], 1, -1);
|
|
|
|
$fct = $match[1];
|
|
|
|
}
|
|
|
|
// par hasard
|
|
|
|
if ($par=='hasard'){
|
|
|
|
$par = "rand()";
|
|
|
|
$boucle->select[] = $par." AS alea";
|
|
|
|
$order = "'alea'";
|
|
|
|
}
|
|
|
|
// par titre_mot ou type_mot voire d'autres
|
|
|
|
else if (isset($exceptions_des_jointures[$par])){
|
|
|
|
list($table, $champ) = $exceptions_des_jointures[$par];
|
|
|
|
$order = critere_par_joint($table, $champ, $boucle, $idb);
|
|
|
|
if (!$order)
|
|
|
|
return (array('zbug_critere_inconnu', array('critere' => $crit->op." $par")));
|
|
|
|
}
|
|
|
|
else if ($par=='date'
|
|
|
|
AND $desc = $boucle->show
|
|
|
|
AND $desc['date']
|
|
|
|
){
|
|
|
|
$m = $desc['date'];
|
|
|
|
$order = "'".$boucle->id_table.".".$m."'";
|
|
|
|
}
|
|
|
|
// par champ. Verifier qu'ils sont presents.
|
|
|
|
elseif (preg_match("/^([^,]*)\.(.*)$/", $par, $r)) {
|
|
|
|
// cas du tri sur champ de jointure explicite
|
|
|
|
$t = array_search($r[1], $boucle->from);
|
|
|
|
if (!$t){
|
|
|
|
$t = trouver_jointure_champ($r[2], $boucle, array($r[1]));
|
|
|
|
}
|
|
|
|
if (!$t){
|
|
|
|
return (array('zbug_critere_inconnu', array('critere' => $crit->op." $par")));
|
|
|
|
} else $order = "'".$t.'.'.$r[2]."'";
|
|
|
|
} else {
|
|
|
|
$desc = $boucle->show;
|
|
|
|
if ($desc['field'][$par])
|
|
|
|
$par = $boucle->id_table.".".$par;
|
|
|
|
// sinon tant pis, ca doit etre un champ synthetise (cf points)
|
|
|
|
$order = "'$par'";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (preg_match('/^\'([^"]*)\'$/', $order, $m)){
|
|
|
|
$t = $m[1];
|
|
|
|
if (strpos($t, '.') AND !in_array($t, $boucle->select)){
|
|
|
|
$boucle->select[] = $t;
|
|
|
|
}
|
|
|
|
} else $sens = '';
|
|
|
|
|
|
|
|
if ($fct){
|
|
|
|
if (preg_match("/^\s*'(.*)'\s*$/", $order, $r))
|
|
|
|
$order = "'$fct(".$r[1].")'";
|
|
|
|
else $order = "'$fct(' . $order . ')'";
|
|
|
|
}
|
|
|
|
$t = $order.$collecte.$sens;
|
|
|
|
if (preg_match("/^(.*)'\s*\.\s*'([^']*')$/", $t, $r))
|
|
|
|
$t = $r[1].$r[2];
|
|
|
|
$boucle->order[] = $t;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// http://doc.spip.org/@critere_par_joint
|
|
|
|
function critere_par_joint($table, $champ, &$boucle, $idb){
|
|
|
|
$t = array_search($table, $boucle->from);
|
|
|
|
if (!$t) $t = trouver_jointure_champ($champ, $boucle);
|
|
|
|
return !$t ? '' : ("'".$t.'.'.$champ."'");
|
|
|
|
}
|
|
|
|
|
|
|
|
// {inverse}
|
|
|
|
// http://www.spip.net/@inverse
|
|
|
|
|
|
|
|
// http://doc.spip.org/@critere_inverse_dist
|
|
|
|
function critere_inverse_dist($idb, &$boucles, $crit){
|
|
|
|
|
|
|
|
$boucle = &$boucles[$idb];
|
|
|
|
// Classement par ordre inverse
|
|
|
|
if ($crit->not)
|
|
|
|
critere_parinverse($idb, $boucles, $crit);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$order = "' DESC'";
|
|
|
|
// Classement par ordre inverse fonction eventuelle de #ENV{...}
|
|
|
|
if (isset($crit->param[0])){
|
|
|
|
$critere = calculer_liste($crit->param[0], array(), $boucles, $boucles[$idb]->id_parent);
|
|
|
|
$order = "(($critere)?' DESC':'')";
|
|
|
|
}
|
|
|
|
|
|
|
|
$n = count($boucle->order);
|
|
|
|
if (!$n){
|
|