source: spip-zone/_plugins_/iterateurs/public/compiler.php @ 54050

Last change on this file since 54050 was 54050, checked in by esj@…, 9 years ago

Report du correctif 18683 de SPIP:
Bug dans le compilateur. L'item de langue suivant:

<:liste_des_n_articles{n=#TOTAL_BOUCLE}:>

déclenchait à tort l'erreur que TOTAL_BOUCLE serait hors boucle.

File size: 38.4 KB
Line 
1<?php
2
3/***************************************************************************\
4 *  SPIP, Systeme de publication pour l'internet                           *
5 *                                                                         *
6 *  Copyright (c) 2001-2011                                                *
7 *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
8 *                                                                         *
9 *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
10 *  Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne.   *
11\***************************************************************************/
12
13
14//
15// Fichier principal du compilateur de squelettes
16//
17
18if (!defined('_ECRIRE_INC_VERSION')) return;
19
20// reperer un code ne calculant rien, meme avec commentaire
21define('CODE_MONOTONE', ",^(\n//[^\n]*\n)?\(?'([^'])*'\)?$,");
22// s'il faut commenter le code produit
23define('CODE_COMMENTE', true);
24
25// definition des structures de donnees
26include_spip('public/interfaces');
27
28// Definition de la structure $p, et fonctions de recherche et de reservation
29// dans l'arborescence des boucles
30include_spip('public/references');
31
32// definition des boucles
33include_spip('public/boucles');
34
35// definition des criteres
36include_spip('public/criteres');
37
38// definition des balises
39include_spip('public/balises');
40
41// Gestion des jointures
42include_spip('public/jointures');
43
44// Les 2 ecritures INCLURE{A1,A2,A3...} et INCLURE(A1){A2}{A3}... sont admises
45// Preferer la premiere.
46// Les Ai sont de la forme Vi=Ei ou bien Vi qui veut alors dire Vi=Vi
47// Le resultat est un tableau indexe par les Vi
48// Toutefois, si le premier argument n'est pas de la forme Vi=Ei
49// il est conventionnellement la valeur de l'index 1.
50// pour la balise #INCLURE
51// mais pas pour <INCLURE> dont le fond est defini explicitement.
52
53
54// http://doc.spip.org/@argumenter_inclure
55function argumenter_inclure($params, $rejet_filtres, $p, &$boucles, $id_boucle, $echap=true, $lang = '', $fond1=false){
56        $l = array();
57        $erreur_p_i_i = '';
58        if (!is_array($params)) return $l;
59        foreach($params as $k => $couple) {
60        // la liste d'arguments d'inclusion peut se terminer par un filtre
61                $filtre = array_shift($couple);
62                if ($filtre) break;
63                foreach($couple as $n => $val) {
64                        $var = $val[0];
65                        if ($var->type != 'texte') {
66                          if ($n OR $k OR $fond1) {
67                                $erreur_p_i_i = array('zbug_parametres_inclus_incorrects',
68                                         array('param' => $var->nom_champ));
69                                erreur_squelette($erreur_p_i_i, $p);
70                          } else $l[1] = calculer_liste($val, $p->descr, $boucles, $id_boucle);
71                          break;
72                        } else {
73                                preg_match(",^([^=]*)(=?)(.*)$,", $var->texte,$m);
74                                $var = $m[1];
75                                $auto = false;;
76                                if ($m[2]) {
77                                  $v = $m[3];
78                                  if (preg_match(',^[\'"](.*)[\'"]$,', $v, $m)) $v = $m[1];
79                                  $val[0] = new Texte;
80                                  $val[0]->texte = $v;
81                                } elseif ($k OR $n OR $fond1) {
82                                  $auto = true;
83                                } else $var = 1;
84
85                                if ($var == 'lang') {
86                                  $lang = !$auto 
87                                    ? calculer_liste($val, $p->descr, $boucles, $id_boucle)
88                                    : '$GLOBALS["spip_lang"]';
89                                } else {
90                                  $val = $auto
91                                    ? index_pile($id_boucle, $var, $boucles)
92                                    : calculer_liste($val, $p->descr, $boucles, $id_boucle);
93                                  if ($var !== 1)
94                                    $val = ($echap?"\'$var\' => ' . argumenter_squelette(":"'$var' => ")
95                                    . $val . ($echap? ") . '":" ");
96                                  else $val = $echap ? "'.$val.'" : $val;
97                                  $l[$var] = $val;
98                                }
99                        }
100                }
101        }
102        if ($erreur_p_i_i) return false;
103        // Cas particulier de la langue : si {lang=xx} est definie, on
104        // la passe, sinon on passe la langue courante au moment du calcul
105        // sauf si on n'en veut pas
106        if ($lang === false) return $l;
107        if (!$lang) $lang = '$GLOBALS["spip_lang"]';
108        $l['lang'] = ($echap?"\'lang\' => ' . argumenter_squelette(":"'lang' => ")  . $lang . ($echap?") . '":" ");
109
110        return $l;
111}
112
113//
114// Calculer un <INCLURE()>
115// La constante ci-dessous donne le code general quand il s'agit d'un script.
116
117define('CODE_INCLURE_SCRIPT', 'if (($path = %s) AND is_readable($path))
118        include $path;
119else erreur_squelette(array("fichier_introuvable", array("fichier" => "%s")), array(%s));'
120);
121
122// // et celle-ci pour un squelette (aussi pour #INCLURE, #MODELE #LES_AUTEURS)
123
124define('CODE_RECUPERER_FOND', 'recuperer_fond(%s, %s, array(%s), %s)');
125
126// http://doc.spip.org/@calculer_inclure
127function calculer_inclure($p, &$boucles, $id_boucle) {
128
129        $_contexte = argumenter_inclure($p->param, false, $p, $boucles, $id_boucle, true, '', true);
130        if (is_string($p->texte)) {
131                $fichier = $p->texte;
132                $code = "\"$fichier\"";
133
134        } else {
135                $code = calculer_liste($p->texte, $p->descr, $boucles, $id_boucle);
136                if ($code AND preg_match("/^'([^']*)'/s", $code, $r))
137                        $fichier = $r[1];
138                else $fichier = '';
139        }
140        if (!$code OR $code === '""') {
141                $erreur_p_i_i = array('zbug_parametres_inclus_incorrects',
142                                         array('param' => $code));
143                erreur_squelette($erreur_p_i_i, $p);
144                return false;
145        }
146        $compil = texte_script(memoriser_contexte_compil($p));
147
148        if (is_array($_contexte)) {
149                // Critere d'inclusion {env} (et {self} pour compatibilite ascendante)
150                if ($env = (isset($_contexte['env'])|| isset($_contexte['self']))) {
151                        unset($_contexte['env']);
152                }
153
154                // noter les doublons dans l'appel a public.php
155                if (isset($_contexte['doublons'])) {
156                        $_contexte['doublons'] = "\\'doublons\\' => '.var_export(\$doublons,true).'";
157                }
158
159                if ($ajax = isset($_contexte['ajax']))
160                        unset($_contexte['ajax']);
161
162                $_contexte = join(",\n\t", $_contexte);
163        }
164        else
165                return false; // j'aurais voulu toucher le fond ...
166               
167        $contexte = 'array(' . $_contexte  .')';
168
169        if ($env) {
170                $contexte = "array_merge('.var_export(\$Pile[0],1).',$contexte)";
171        }
172
173        // s'il y a une extension .php, ce n'est pas un squelette
174        if (preg_match('/^.+[.]php$/s', $fichier)) {
175                // si inexistant, on essaiera a l'execution
176                if ($path = find_in_path($fichier))
177                        $path = "\"$path\"";
178                else $path = "find_in_path(\"$fichier\")";
179
180                $code = sprintf(CODE_INCLURE_SCRIPT, $path, $fichier, $compil);
181        } else  {
182                $_options[] = "\"compil\"=>array($compil)";
183                if ($ajax)
184                        $_options[] = "\"ajax\"=>true";
185                $code = " ' . argumenter_squelette($code) . '"; 
186                $code = "echo " . sprintf(CODE_RECUPERER_FOND, $code, $contexte, implode(',',$_options), "_request(\"connect\")") . ';';
187        }
188
189        return  "\n'<'.'".      "?php ". $code . "\n?'." . "'>'";
190}
191
192
193/**
194 * Calculer la clause where pour filtrer les status,
195 *
196 * @param string $mstatut
197 *  le champ de la table sur lequel porte la condition
198 * @param string $liste
199 *  statut ou liste des statuts separes par une virgule
200 * @return array
201 */
202function calculer_where_statut($mstatut,$liste){
203        $not = false;
204        if (strncmp($liste,'!',1)==0){
205                $not = true;
206          $liste = substr($liste,1);
207        }
208        // '' => ne rien afficher, '!'=> ne rien filtrer
209        if (!strlen($liste))
210                return ($not?"'1=1'":"'0=1'");
211
212        $liste = explode(',',$liste);
213        foreach($liste as $k=>$v) {
214                $liste[$k] = "\\'".preg_replace(",\W,","",$v)."\\'";
215        }
216  if (count($liste)==1){
217                return array($not?"'<>'":"'='", "'$mstatut'", "'".reset($liste)."'");
218  }
219  else {
220          return array($not?"'NOT IN'":"'IN'", "'$mstatut'", "'(".implode(',',$liste).")'");
221  }
222}
223
224/**
225 * calculer_boucle() produit le corps PHP d'une boucle Spip.
226 * ce corps remplit une variable $t0 retournee en valeur.
227 * Ici on distingue boucles recursives et boucle a requete SQL
228 * et on insere le code d'envoi au debusqueur du resultat de la fonction.
229 *
230 * http://doc.spip.org/@calculer_boucle
231 *
232 * @param  $id_boucle
233 * @param  $boucles
234 * @return string
235 */
236function calculer_boucle($id_boucle, &$boucles) {
237
238        // gerer les statuts si declares pour cette table
239        /*
240        $table_statut[nom_table][] = array(
241                'champ'=>'statut',  // champ de la table sur lequel porte le filtrage par le statut
242                'publie'=>'publie', // valeur ou liste de valeurs, qui definissent l'objet comme publie.
243                'previsu'=>'publie,prop', // valeur ou liste de valeurs qui sont visibles en previsu
244                'post_date'=>'date', // un champ de date pour la prise en compte des post_dates, ou rien sinon
245          'exception'=>'statut', // liste des modificateurs qui annulent le filtrage par statut
246                                 // si plusieurs valeurs : array('statut','tout','lien')
247        );
248
249        Pour 'publier' ou 'previsu', si la chaine commence par un "!" on exclu au lieu de filtrer sur les valeurs donnees
250        si la chaine est vide, on ne garde rien si elle est seulement "!" on n'exclu rien
251
252        Si le statut repose sur une jointure, 'champ' est alors un tableau du format suivant :
253        'champ'=>array(
254            array(table1, cle1),
255            ...
256            array(tablen, clen),
257            champstatut
258         )
259
260        champstatut est alors le champ statut sur la tablen
261        dans les jointures, clen peut etre un tableau pour une jointure complexe : array('id_objet','id_article','objet','article')     
262        */
263
264        $boucle = &$boucles[$id_boucle];
265        $id_table = $boucle->id_table;
266        $table_sql = $boucle->from[$id_table];
267        if (isset($GLOBALS['table_statut'][$table_sql])){
268                foreach($GLOBALS['table_statut'][$table_sql] as $s){
269                        // Restreindre aux elements publies si pas de {statut} ou autre dans les criteres
270                        $filtrer = true;
271                        if (isset($s['exception'])) {
272                                foreach(is_array($s['exception'])?$s['exception']:array($s['exception']) as $m) {
273                                        if (isset($boucle->modificateur[$m]) OR isset($boucle->modificateur['criteres'][$m])) {
274                                                $filtrer = false;
275                                                break;
276                                        }
277                                }
278                        }
279
280                        if ($filtrer) {
281                                if (is_array($s['champ'])){
282                                        $statut = preg_replace(',\W,','',array_pop($s['champ'])); // securite
283                                        $jointures = array();
284                                        foreach($s['champ'] as $j) {
285                                                $jointures[] = array('',array($id=reset($j)),end($j));
286                                        }
287                                        $jointures[0][0] = $id_table;
288                                        if (!array_search($id, $boucle->from)){
289                                                fabrique_jointures($boucle, $jointures, true, $boucle->show, $id_table);
290                                        }
291                                        // trouver l'alias de la table d'arrivee qui porte le statut
292                                        $id = array_search($id, $boucle->from);
293                                }
294                                else {
295                                        $id = $id_table;
296                                        $statut = preg_replace(',\W,','',$s['champ']); // securite
297                                }
298                                $mstatut = $id .'.'.$statut;
299
300                                if (!$GLOBALS['var_preview']) {
301                                        if (isset($s['post_date']) AND $s['post_date']
302                                                AND $GLOBALS['meta']["post_dates"] == 'non'){
303                                                $date = $id.'.'.preg_replace(',\W,','',$s['post_date']); // securite
304                                                array_unshift($boucle->where,"quete_condition_postdates('$date')");
305                                        }
306                                        array_unshift($boucle->where,calculer_where_statut($mstatut,$s['publie']));
307                                }
308                                else {
309                                        array_unshift($boucle->where,calculer_where_statut($mstatut,$s['previsu']));
310                                }
311                        }
312                }
313        }
314
315
316
317        $boucles[$id_boucle] = pipeline('post_boucle', $boucles[$id_boucle]);
318
319        // en mode debug memoriser les premiers passages dans la boucle,
320        // mais pas tous, sinon ca pete.
321        if  (_request('var_mode_affiche') != 'resultat') 
322                $trace = '';
323        else {
324                $trace = $boucles[$id_boucle]->descr['nom'] . $id_boucle;
325                $trace = "if (count(@\$GLOBALS['debug_objets']['resultat']['$trace'])<3)
326            \$GLOBALS['debug_objets']['resultat']['$trace'][] = \$t0;";
327        }
328        return ($boucles[$id_boucle]->type_requete == 'boucle')
329        ? calculer_boucle_rec($id_boucle, $boucles, $trace) 
330        : calculer_boucle_nonrec($id_boucle, $boucles, $trace);
331}
332
333// compil d'une boucle recursive.
334// il suffit (ET IL FAUT) sauvegarder les valeurs des arguments passes par
335// reference, car par definition un tel passage ne les sauvegarde pas
336
337// http://doc.spip.org/@calculer_boucle_rec
338function calculer_boucle_rec($id_boucle, &$boucles, $trace) {
339        $nom = $boucles[$id_boucle]->param[0];
340        return "\n\t\$save_numrows = (\$Numrows['$nom']);"
341        . "\n\t\$t0 = " . $boucles[$id_boucle]->return . ";"
342        . "\n\t\$Numrows['$nom'] = (\$save_numrows);"
343        . $trace
344        . "\n\treturn \$t0;";
345}
346
347// Compilation d'une boucle non recursive.
348// Ci-dessous la constante donnant le cadre systematique du code:
349// %s1: initialisation des arguments de calculer_select
350// %s2: appel de calculer_select en donnant un contexte pour les cas d'erreur
351// %s3: initialisation du sous-tableau Numrows[id_boucle]
352// %s4: sauvegarde de la langue et calcul des invariants de boucle sur elle
353// %s5: boucle while sql_fetch ou str_repeat si corps monotone
354// %s6: restauration de la langue
355// %s7: liberation de la ressource, en tenant compte du serveur SQL
356// %s8: code de trace eventuel avant le retour
357
358define('CODE_CORPS_BOUCLE', '%s
359        $t0 = "";
360        // REQUETE
361        $iter = IterFactory::create(
362                "%s",
363                %s,
364                array(%s)
365        );
366        if (!$iter->err()) {
367        %s%s$SP++;
368        // RESULTATS
369        %s
370        %s$iter->free();
371        }%s
372        return $t0;'
373);
374
375// http://doc.spip.org/@calculer_boucle_nonrec
376function calculer_boucle_nonrec($id_boucle, &$boucles, $trace) {
377
378        $boucle = &$boucles[$id_boucle];
379        $return = $boucle->return;
380        $type_boucle = $boucle->type_requete;
381        $primary = $boucle->primary;
382        $constant = preg_match(CODE_MONOTONE, str_replace("\\'",'', $return));
383        $flag_cpt = $boucle->mode_partie ||$boucle->cptrows;
384        $corps = '';
385
386        // faudrait expanser le foreach a la compil, car y en a souvent qu'un
387        // et puis faire un [] plutot qu'un "','."
388        if ($boucle->doublons)
389                $corps .= "\n\t\t\tforeach(" . $boucle->doublons . ' as $k) $doublons[$k] .= "," . ' .
390                index_pile($id_boucle, $primary, $boucles)
391                . "; // doublons\n";
392
393        // La boucle doit-elle selectionner la langue ?
394        // - par defaut, les boucles suivantes le font
395        //    (sauf si forcer_lang==true ou si le titre contient <multi>).
396        // - a moins d'une demande explicite via {!lang_select}
397        if (!$constant && $boucle->lang_select != 'non' &&
398            (($boucle->lang_select == 'oui')  ||
399                    in_array($type_boucle, array(
400                        'articles', 'rubriques', 'hierarchie', 'breves'
401                        )))
402        ) {
403                // Memoriser la langue avant la boucle et la restituer apres
404                // afin que le corps de boucle affecte la globale directement
405                $init_lang = "lang_select(\$GLOBALS['spip_lang']);\n\t";
406                $fin_lang = "lang_select();\n\t";
407
408                $corps .= 
409                        "\n\t\tlang_select_public("
410                        . index_pile($id_boucle, 'lang', $boucles)
411                        . ", '".$boucle->lang_select."'"
412                        . (in_array($type_boucle, array(
413                                'articles', 'rubriques', 'hierarchie', 'breves'
414                                )) ? ', '.index_pile($id_boucle, 'titre', $boucles) : '')
415                        . ');';
416        }
417        else {
418                $init_lang = '';
419                $fin_lang = '';
420                // sortir les appels au traducteur (invariants de boucle)
421                if (strpos($return, '?php') === false
422                AND preg_match_all("/\W(_T[(]'[^']*'[)])/", $return, $r)) {
423                        $i = 1;
424                        foreach($r[1] as $t) {
425                                $init_lang .= "\n\t\$l$i = $t;";
426                                $return = str_replace($t, "\$l$i", $return);
427                                $i++;
428                        }
429                }
430        }
431
432        // gestion optimale des separateurs et des boucles constantes
433        if (count($boucle->separateur))
434          $code_sep = ("'" . str_replace("'","\'",join('',$boucle->separateur)) . "'");
435
436        $corps .= 
437                ((!$boucle->separateur) ? 
438                        (($constant && !$corps && !$flag_cpt) ? $return :
439                         (($return==="''") ? '' :
440                          ("\n\t\t" . '$t0 .= ' . $return . ";"))) :
441                 ("\n\t\t\$t1 " .
442                        ((strpos($return, '$t1.') === 0) ? 
443                         (".=" . substr($return,4)) :
444                         ('= ' . $return)) .
445                  ";\n\t\t" .
446                  '$t0 .= (($t1 && $t0) ? ' . $code_sep . " : '') . \$t1;"));
447     
448        // Calculer les invalideurs si c'est une boucle non constante et si on
449        // souhaite invalider ces elements
450        if (!$constant AND $primary) {
451                include_spip('inc/invalideur');
452                if (function_exists($i = 'calcul_invalideurs'))
453                        $corps = $i($corps, $primary, $boucles, $id_boucle);
454        }
455
456        // gerer le compteur de boucle
457        // avec ou sans son utilisation par les criteres {1/3} {1,4} {n-2,1}...
458
459        if ($boucle->partie OR $boucle->cptrows)
460                $corps = "\n\t\t\$Numrows['$id_boucle']['compteur_boucle']++;"
461                . $boucle->partie 
462                . $corps;
463
464        // si le corps est une constante, ne pas appeler le serveur N fois!
465
466        if (preg_match(CODE_MONOTONE,str_replace("\\'",'',$corps), $r)) {
467                if (!isset($r[2]) OR (!$r[2])) {
468                        if (!$boucle->numrows)
469                                return "\n\t\$t0 = '';";
470                        else
471                                $corps = "";
472                } else {
473                        $boucle->numrows = true;
474                        $corps = "\n\t\$t0 = str_repeat($corps, \$Numrows['$id_boucle']['total']);";
475                }
476        } else $corps = "while (\$Pile[\$SP]=\$iter->fetch()) {\n$corps\n       }"; 
477
478        $count = '';
479        if (!$boucle->select) {
480                if (!$boucle->numrows OR $boucle->limit OR $boucle_mode_partie OR $boucle->group)
481                        $count = '1';
482                else $count = 'count(*)';
483                $boucles[$id_boucle]->select[]= $count; 
484        }
485
486        if ($flag_cpt)
487                $nums = "\n\t// COMPTEUR\n\t"
488                . "\$Numrows['$id_boucle']['compteur_boucle'] = 0;\n\t";
489        else $nums = '';
490
491        if ($boucle->numrows OR $boucle->mode_partie) {
492                $nums .= "\$Numrows['$id_boucle']['total'] = @intval(\$iter->count());"
493                . $boucle->mode_partie
494                . "\n\t";
495        }
496
497        // Ne calculer la requete que maintenant
498        // car ce qui precede appelle index_pile qui influe dessus
499
500        $init = (($init = $boucles[$id_boucle]->doublons)
501                         ? ("\n\t$init = array();") : '')
502        . calculer_requete_sql($boucles[$id_boucle]);
503
504        $contexte = memoriser_contexte_compil($boucle);
505
506        $a = sprintf(CODE_CORPS_BOUCLE,
507                $init,
508                $boucle->iterateur,
509                "\$command",
510                $contexte,
511                $nums,
512                $init_lang,
513                $corps,
514                $fin_lang,
515                $trace
516        );
517
518#       var_dump($a);exit;
519        return $a;
520}
521
522
523// http://doc.spip.org/@calculer_requete_sql
524function calculer_requete_sql($boucle)
525{
526        return ($boucle->hierarchie ? "\n\t$boucle->hierarchie" : '')
527          . $boucle->in 
528          . $boucle->hash 
529          . calculer_dec('table',  "'" . $boucle->id_table ."'")
530          . calculer_dec('id', "'" . $boucle->id_boucle ."'")
531                # En absence de champ c'est un decompte :
532          . calculer_dec('from',  calculer_from($boucle))
533          . calculer_dec('type', calculer_from_type($boucle))
534          . calculer_dec('groupby', 'array(' . (($g=join("\",\n\t\t\"",$boucle->group))?'"'.$g.'"':'') . ")")
535          . calculer_dec('select', 'array("' . join("\",\n\t\t\"", $boucle->select).  "\")")
536          . calculer_dec('orderby', 'array(' . calculer_order($boucle) .        ")")
537          . calculer_dec('where', calculer_dump_array($boucle->where))
538          . calculer_dec('join', calculer_dump_join($boucle->join))
539          . calculer_dec('limit', (strpos($boucle->limit, 'intval') === false ?
540                                    "'".$boucle->limit."'" :
541                                    $boucle->limit))
542          . calculer_dec('having', calculer_dump_array($boucle->having));
543}
544
545function memoriser_contexte_compil($p) {
546        return join(',', array(
547                _q($p->descr['sourcefile']),
548                _q($p->descr['nom']),
549                @_q($p->id_boucle),
550                intval($p->ligne),
551                '$GLOBALS[\'spip_lang\']'));
552}
553
554function reconstruire_contexte_compil($context_compil)
555{
556        if (!is_array($context_compil)) return $context_compil;
557        include_spip('public/interfaces');
558        $p = new Contexte;
559        $p->descr = array('sourcefile' => $context_compil[0],
560                                  'nom' => $context_compil[1]);
561        $p->id_boucle = $context_compil[2];
562        $p->ligne = $context_compil[3];
563        $p->lang = $context_compil[4];
564        return $p;
565}
566
567// http://doc.spip.org/@calculer_dec
568function calculer_dec($nom, $val)
569{
570        $static = 'if (!isset($command[\''.$nom.'\'])) ';
571        if (
572                strpos($val, '$') !== false 
573                OR strpos($val, 'sql_') !== false
574                OR (
575                        $test = str_replace(array("array(",'\"',"\'"),array("","",""),$val) // supprimer les array( et les echappements de guillemets
576                        AND strpos($test,"(")!==FALSE // si pas de parenthese ouvrante, pas de fonction, on peut sortir
577                        AND $test = preg_replace(",'[^']*',UimsS","",$test) // supprimer les chaines qui peuvent contenir des fonctions SQL qui ne genent pas
578                        AND preg_match(",\w+\s*\(,UimsS",$test,$regs) // tester la presence de fonctions restantes
579                )
580        )
581                $static = "";
582
583        return "\n\t" . $static . '$command[\''.$nom.'\'] = ' . $val . ';';
584}
585
586// http://doc.spip.org/@calculer_dump_array
587function calculer_dump_array($a)
588{
589  if (!is_array($a)) return $a ;
590  $res = "";
591  if ($a AND $a[0] == "'?'") 
592    return ("(" . calculer_dump_array($a[1]) .
593            " ? " . calculer_dump_array($a[2]) .
594            " : " . calculer_dump_array($a[3]) .
595            ")");
596  else {
597    foreach($a as $v) $res .= ", " . calculer_dump_array($v);
598    return "\n\t\t\tarray(" . substr($res,2) . ')';
599  }
600}
601
602// http://doc.spip.org/@calculer_dump_join
603function calculer_dump_join($a)
604{
605  $res = "";
606  foreach($a as $k => $v) 
607                $res .= ", '$k' => array(".implode(',',$v).")";
608  return 'array(' . substr($res,2) . ')';
609}
610
611// http://doc.spip.org/@calculer_from
612function calculer_from(&$boucle)
613{
614  $res = "";
615  foreach($boucle->from as $k => $v) $res .= ",'$k' => '$v'";
616  return 'array(' . substr($res,1) . ')';
617}
618
619// http://doc.spip.org/@calculer_from_type
620function calculer_from_type(&$boucle)
621{
622  $res = "";
623  foreach($boucle->from_type as $k => $v) $res .= ",'$k' => '$v'";
624  return 'array(' . substr($res,1) . ')';
625}
626
627// http://doc.spip.org/@calculer_order
628function calculer_order(&$boucle)
629{
630        if (!$order = $boucle->order
631        AND !$order = $boucle->default_order)
632                $order = array();
633
634        /*if (isset($boucle->modificateur['collate'])){
635                $col = "." . $boucle->modificateur['collate'];
636                foreach($order as $k=>$o)
637                        if (strpos($order[$k],'COLLATE')===false)
638                                $order[$k].= $col;
639        }*/
640        return join(', ', $order);
641}
642
643// Production du code PHP a partir de la sequence livree par le phraseur
644// $boucles est passe par reference pour affectation par index_pile.
645// Retourne une expression PHP,
646// (qui sera argument d'un Return ou la partie droite d'une affectation).
647
648// http://doc.spip.org/@calculer_liste
649function calculer_liste($tableau, $descr, &$boucles, $id_boucle='') {
650        if (!$tableau) return "''";
651        if (!isset($descr['niv'])) $descr['niv'] = 0;
652        $codes = compile_cas($tableau, $descr, $boucles, $id_boucle);
653        if ($codes === false) return false;
654        $n = count($codes);
655        if (!$n) return "''";
656        $tab = str_repeat("\t", $descr['niv']);
657        if (_request('var_mode_affiche') != 'validation') {
658                if ($n==1) 
659                        return $codes[0];
660                else {
661                        $res = '';
662                        foreach($codes as $code) {
663                                if (!preg_match("/^'[^']*'$/", $code)
664                                OR substr($res,-1,1)!=="'")
665                                  $res .=  " .\n$tab$code";
666                                else {
667                                  $res = substr($res,0,-1) . substr($code,1);
668                                }
669                        }
670                        return '(' . substr($res,2+$descr['niv']) . ')';
671                }
672        } else {
673          $nom = $descr['nom'] . $id_boucle .  ($descr['niv']?$descr['niv']:'');
674          return "join('', array_map('array_shift', \$GLOBALS['debug_objets']['sequence']['$nom'] = array(" .  join(" ,\n$tab", $codes) . ")))";
675        }
676}
677
678define('_REGEXP_COND_VIDE_NONVIDE',"/^[(](.*)[?]\s*''\s*:\s*('[^']+')\s*[)]$/");
679define('_REGEXP_COND_NONVIDE_VIDE',"/^[(](.*)[?]\s*('[^']+')\s*:\s*''\s*[)]$/");
680define('_REGEXP_CONCAT_NON_VIDE', "/^(.*)[.]\s*'[^']+'\s*$/");
681
682// http://doc.spip.org/@compile_cas
683function compile_cas($tableau, $descr, &$boucles, $id_boucle) {
684
685        $codes = array();
686        // cas de la boucle recursive
687        if (is_array($id_boucle)) 
688          $id_boucle = $id_boucle[0];
689        $type = !$id_boucle ? '' : $boucles[$id_boucle]->type_requete;
690        $tab = str_repeat("\t", ++$descr['niv']);
691        $mode = _request('var_mode_affiche');
692        $err_e_c = '';
693        // chaque commentaire introduit dans le code doit commencer
694        // par un caractere distinguant le cas, pour exploitation par debug.
695        foreach ($tableau as $p) {
696
697                switch($p->type) {
698                // texte seul
699                case 'texte':
700                        $code = "'".str_replace(array("\\","'"),array("\\\\","\\'"), $p->texte)."'";
701
702                        $commentaire= strlen($p->texte) . " signes";
703                        $avant='';
704                        $apres='';
705                        $altern = "''";
706                        break;
707
708                case 'polyglotte':
709                        $code = "";
710                        foreach($p->traductions as $k => $v) {
711                          $code .= ",'" .
712                            str_replace(array("\\","'"),array("\\\\","\\'"), $k) .
713                            "' => '" .
714                            str_replace(array("\\","'"),array("\\\\","\\'"), $v) .
715                            "'";
716                        }
717                        $code = "choisir_traduction(array(" .
718                          substr($code,1) .
719                          "))";
720                        $commentaire= '&';
721                        $avant='';
722                        $apres='';
723                        $altern = "''";
724                        break;
725
726                // inclure
727                case 'include':
728                        $p->descr = $descr;
729                        $code = calculer_inclure($p, $boucles, $id_boucle);
730                        if ($code === false) {
731                                $err_e_c = true;
732                                $code = "''";
733                        } else {
734                                $commentaire = '<INCLURE ' . addslashes(str_replace("\n", ' ', $code)) . '>';
735                                $avant='';
736                                $apres='';
737                                $altern = "''";
738                        }
739                        break;
740
741                // boucle
742                case 'boucle':
743                        $nom = $p->id_boucle;
744                        $newdescr = $descr;
745                        $newdescr['id_mere'] = $nom;
746                        $newdescr['niv']++;
747                        $avant = calculer_liste($p->avant,
748                                $newdescr, $boucles, $id_boucle);
749                        $apres = calculer_liste($p->apres,
750                                $newdescr, $boucles, $id_boucle);
751                        $newdescr['niv']--;
752                        $altern = calculer_liste($p->altern,
753                                $newdescr, $boucles, $id_boucle);
754                        if (($avant === false) OR ($apres === false) OR ($altern === false)) {
755                                $err_e_c = true;
756                                $code = "''";
757                        } else {
758                                $code = 'BOUCLE' .
759                                  str_replace("-","_", $nom) . $descr['nom'] .
760                                  '($Cache, $Pile, $doublons, $Numrows, $SP)';
761                                $commentaire= "?$nom";
762                                if (!$boucles[$nom]->milieu
763                                AND $boucles[$nom]->type_requete <> 'boucle') {
764                                        if ($altern != "''") $code .= "\n. $altern";
765                                        if ($avant<>"''" OR $apres<>"''")
766                                          spip_log("boucle $nom toujours vide, code superflu dans $id");
767                                        $avant = $apres = $altern = "''";
768                                } else if ($altern != "''") $altern = "($altern)";
769                        }
770                        break;
771
772                case 'idiome':
773                        $l = array();
774                        foreach ($p->arg as $k => $v) {
775                          if ($k) $l[]= _q($k).' => '.calculer_liste($v,$descr,$boucles,$id_boucle);
776                        }
777                        $l = !$l ? '' : (", array(".implode(",\n",$l).")");
778                        $code = "_T('" . $p->module . ":" .$p->nom_champ . "'$l)";
779                        if ($p->param) {
780                                $p->id_boucle = $id_boucle;
781                                $p->boucles = &$boucles;
782                                $code = compose_filtres($p, $code);
783                        }
784                        $commentaire = ":";
785                        $avant='';
786                        $apres='';
787                        $altern = "''";
788                        break;
789
790                case 'champ':
791
792                        // cette structure pourrait etre completee des le phrase' (a faire)
793                        $p->id_boucle = $id_boucle;
794                        $p->boucles = &$boucles;
795                        $p->descr = $descr;
796                        #$p->interdire_scripts = true;
797                        $p->type_requete = $type;
798
799                        $code = calculer_champ($p);
800                        $commentaire = '#' . $p->nom_champ . $p->etoile;
801                        $avant = calculer_liste($p->avant,
802                                $descr, $boucles, $id_boucle);
803                        $apres = calculer_liste($p->apres,
804                                $descr, $boucles, $id_boucle);
805                        $altern = "''";
806                        // Si la valeur est destinee a une comparaison a ''
807                        // forcer la conversion en une chaine par strval
808                        // si ca peut etre autre chose qu'une chaine
809                        if (($avant != "''" OR $apres != "''")
810                        AND $code[0]!= "'"
811#                       AND (strpos($code,'interdire_scripts') !== 0)
812                        AND !preg_match(_REGEXP_COND_VIDE_NONVIDE, $code)
813                        AND !preg_match(_REGEXP_COND_NONVIDE_VIDE, $code)
814                        AND !preg_match(_REGEXP_CONCAT_NON_VIDE, $code)) 
815                                $code = "strval($code)";
816                        break;
817
818                default: 
819                  // Erreur de construction de l'arbre de syntaxe abstraite
820                        $code = "''";
821                        $p->descr = $descr;
822                        $err_e_c = array('zbug_erreur_compilation');
823                        erreur_squelette($err_e_c, $p);
824                } // switch
825
826                if ($code != "''") {
827                        $code = compile_retour($code, $avant, $apres, $altern, $tab, $descr['niv']);
828                        $codes[]= (($mode == 'validation') ?
829                                "array($code, '$commentaire', " . $p->ligne . ")"
830                                : (($mode == 'code') ?
831                                "\n// $commentaire\n$code" :
832                                $code));
833                }
834        } // foreach
835
836        return $err_e_c ? false : $codes;
837}
838
839// production d'une expression conditionnelle ((v=EXP) ? (p . v .s) : a)
840// mais si EXP est de la forme (t ? 'C' : '') on produit (t ? (p . C . s) : a)
841// de meme si EXP est de la forme (t ? '' : 'C')
842
843// http://doc.spip.org/@compile_retour
844function compile_retour($code, $avant, $apres, $altern, $tab, $n)
845{
846        if ($avant == "''") $avant = '';
847        if ($apres == "''") $apres = '';
848        if (!$avant AND !$apres AND ($altern==="''")) return $code;
849
850        if (preg_match(_REGEXP_CONCAT_NON_VIDE, $code)) {
851                $t = $code;
852                $cond = '';
853        } elseif (preg_match(_REGEXP_COND_VIDE_NONVIDE,$code, $r)) {
854                $t = $r[2];
855                $cond =  '!' . $r[1];
856        } else if  (preg_match(_REGEXP_COND_NONVIDE_VIDE,$code, $r)) {
857                $t = $r[2];
858                $cond = $r[1];
859        } else {
860                $t = '$t' . $n;
861                $cond = "($t = $code)!==''";
862        }
863
864        $res = (!$avant ? "" : "$avant . ") . 
865                $t .
866                (!$apres ? "" : " . $apres");
867
868        if ($res !== $t) $res = "($res)";
869        return !$cond ? $res : "($cond ?\n\t$tab$res :\n\t$tab$altern)";
870}
871
872
873function compile_inclure_doublons($lexemes)
874{
875        foreach($lexemes as $v)
876          if($v->type === 'include' AND $v->param) 
877            foreach($v->param as $r) 
878              if (trim($r[0]) === 'doublons') 
879                return true;
880        return false;
881}
882
883// Prend en argument le texte d'un squelette, le nom de son fichier d'origine,
884// sa grammaire et un nom. Retourne False en cas d'erreur,
885// sinon retourne un tableau de fonctions PHP compilees a evaluer,
886// notamment une fonction portant ce nom et calculant une page.
887// Pour appeler la fonction produite, lui fournir 2 tableaux de 1 e'le'ment:
888// - 1er: element 'cache' => nom (du fichier ou` mettre la page)
889// - 2e: element 0 contenant un environnement ('id_article => $id_article, etc)
890// Elle retournera alors un tableau de 5 e'le'ments:
891// - 'texte' => page HTML, application du squelette a` l'environnement;
892// - 'squelette' => le nom du squelette
893// - 'process_ins' => 'html' ou 'php' selon la pre'sence de PHP dynamique
894// - 'invalideurs' =>  de'pendances de cette page, pour invalider son cache.
895// - 'entetes' => tableau des entetes http
896// En cas d'erreur, elle retournera un tableau des 2 premiers elements seulement
897
898// http://doc.spip.org/@public_compiler_dist
899function public_compiler_dist($squelette, $nom, $gram, $sourcefile, $connect=''){
900        // Pre-traitement : reperer le charset du squelette, et le convertir
901        // Bonus : supprime le BOM
902        include_spip('inc/charsets');
903        $squelette = transcoder_page($squelette);
904
905        $descr = array('nom' => $nom,
906                        'gram' => $gram,
907                        'sourcefile' => $sourcefile,
908                        'squelette' => $squelette);
909
910        // Phraser le squelette, selon sa grammaire
911
912        $boucles = array();
913        $f = charger_fonction('phraser_' . $gram, 'public');
914
915        $squelette = $f($squelette, '', $boucles, $descr);
916
917        return compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $connect);
918}
919
920// Point d'entree pour arbre de syntaxe abstraite fourni en premier argument
921// Autres specifications comme ci-dessus
922
923function compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $connect=''){
924        global $tables_jointures;
925        static $trouver_table;
926        spip_timer('calcul_skel');
927
928        if (isset($GLOBALS['var_mode']) AND $GLOBALS['var_mode'] == 'debug') {
929                $GLOBALS['debug_objets']['squelette'][$nom] = $descr['squelette'];
930                $GLOBALS['debug_objets']['sourcefile'][$nom] = $sourcefile;
931
932                if (!isset($GLOBALS['debug_objets']['principal']))
933                        $GLOBALS['debug_objets']['principal'] = $nom;
934        }
935        foreach ($boucles as $id => $boucle) {
936                $GLOBALS['debug_objets']['boucle'][$nom.$id] = $boucle;
937        }
938        $descr['documents'] = compile_inclure_doublons($squelette);
939
940        // Demander la description des tables une fois pour toutes
941        // et reperer si les doublons sont demandes
942        // pour un inclure ou une boucle document
943        // c'est utile a la fonction champs_traitements
944        if (!$trouver_table)
945                $trouver_table = charger_fonction('trouver_table', 'base');
946
947        foreach($boucles as $id => $boucle) {
948                if (!($type = $boucle->type_requete)) continue;
949                if (!$descr['documents'] AND (
950                        (($type == 'documents') AND $boucle->doublons) OR
951                                compile_inclure_doublons($boucle->avant) OR
952                                compile_inclure_doublons($boucle->apres) OR
953                                compile_inclure_doublons($boucle->milieu) OR
954                                compile_inclure_doublons($boucle->altern)))
955                        $descr['documents'] = true; 
956                if ($type != 'boucle') {
957                        if (!$boucles[$id]->sql_serveur AND $connect)
958                                $boucles[$id]->sql_serveur = $connect;
959                        $show = $trouver_table($type, $boucles[$id]->sql_serveur);
960                        // si la table n'existe pas avec le connecteur par defaut,
961                        // c'est peut etre une table qui necessite son connecteur dedie fourni
962                        // permet une ecriture allegee (GEO) -> (geo:GEO)
963                        if (!$show
964                        AND $show=$trouver_table($type, strtolower($type))) {
965                                $boucles[$id]->sql_serveur = strtolower($type);
966                        }
967
968                        // chercher dans les iterateurs du repertoire iterateur/
969                        if ($g = charger_fonction(
970                        preg_replace('/\W/', '_', $boucle->type_requete), 'iterateur', true)) {
971                                $boucles[$id] = $g($boucle);
972
973                        // sinon, en cas de requeteur d'un type predefini,
974                        // utiliser les informations donnees par le requeteur
975                        // cas "php:xx" et "data:xx".
976                        } else if ($requeteur = charger_fonction($boucle->sql_serveur, 'requeteur', true)) {
977                                $requeteur($boucles, $boucle, $id);
978                       
979                        // utiliser la description des champs transmis
980                        } else if ($show) {
981                                $boucles[$id]->show = $show;
982                                // recopie les infos les plus importantes
983                                $boucles[$id]->primary = $show['key']["PRIMARY KEY"];
984                                $boucles[$id]->id_table = $x = $show['id_table'];
985                                $boucles[$id]->from[$x] = $nom_table = $show['table'];
986                                $boucles[$id]->iterateur = 'SQL';
987
988                                $boucles[$id]->descr = &$descr;
989                                if ((!$boucles[$id]->jointures)
990                                AND (isset($tables_jointures[$nom_table])) 
991                                AND is_array($x = $tables_jointures[$nom_table]))
992                                        $boucles[$id]->jointures = $x;
993                                if ($boucles[$id]->jointures_explicites){
994                                        $jointures = preg_split("/\s+/",$boucles[$id]->jointures_explicites);
995                                        while ($j=array_pop($jointures))
996                                                array_unshift($boucles[$id]->jointures,$j);
997                                }
998                        } else {
999                                // Pas une erreur si la table est optionnelle
1000                                if ($boucles[$id]->table_optionnelle)
1001                                        $boucles[$id]->type_requete = '';
1002                                else  {
1003                                        $boucles[$id]->type_requete = false;
1004                                        $boucle = $boucles[$id];
1005                                        $x = (!$boucle->sql_serveur ? '' :
1006                                              ($boucle->sql_serveur . ":")) .
1007                                          $type;
1008                                        $msg = array('zbug_table_inconnue',
1009                                                        array('table' => $x));
1010                                        erreur_squelette($msg, $boucle);
1011                                }
1012                        }
1013                }
1014        }
1015
1016        // Commencer par reperer les boucles appelees explicitement
1017        // car elles indexent les arguments de maniere derogatoire
1018        foreach($boucles as $id => $boucle) { 
1019                if ($boucle->type_requete == 'boucle' AND $boucle->param) {
1020                        $boucles[$id]->descr = &$descr;
1021                        $rec = &$boucles[$boucle->param[0]];
1022                        if (!$rec) {
1023                                $msg = array('zbug_boucle_recursive_undef',
1024                                        array('nom' => $boucle->param[0]));
1025                                erreur_squelette($msg, $boucle);
1026                                $boucles[$id]->type_requete = false;
1027                        } else {
1028                                $rec->externe = $id;
1029                                $descr['id_mere'] = $id;
1030                                $boucles[$id]->return =
1031                                                calculer_liste(array($rec),
1032                                                         $descr,
1033                                                         $boucles,
1034                                                         $boucle->param);
1035                        }
1036                }
1037        }
1038        foreach($boucles as $id => $boucle) { 
1039                $id = strval($id); // attention au type dans index_pile
1040                $type = $boucle->type_requete;
1041                if ($type AND $type != 'boucle') {
1042                        if ($boucle->param) {
1043                                $res = calculer_criteres($id, $boucles);
1044                        }
1045                        $descr['id_mere'] = $id;
1046                        $boucles[$id]->return =
1047                          calculer_liste($boucle->milieu,
1048                                         $descr,
1049                                         $boucles,
1050                                         $id);
1051                        // Si les criteres se sont mal compiles
1052                        // ne pas tenter d'assembler le code final
1053                        // (mais compiler le corps pour detection d'erreurs)
1054                        if (is_array($res))
1055                                $boucles[$id]->type_requete = false;
1056                }
1057        }
1058
1059        // idem pour la racine
1060        $descr['id_mere'] = '';
1061        $corps = calculer_liste($squelette, $descr, $boucles);
1062        $debug = (isset($GLOBALS['var_mode']) AND $GLOBALS['var_mode']=='debug');
1063
1064        if ($debug) {
1065                include_spip('public/decompiler');
1066                include_spip('public/format_' . _EXTENSION_SQUELETTES);
1067        }
1068        // Calcul du corps de toutes les fonctions PHP,
1069        // en particulier les requetes SQL et TOTAL_BOUCLE
1070        // de'terminables seulement maintenant
1071
1072        foreach($boucles as $id => $boucle) {
1073                $boucle = $boucles[$id] = pipeline('pre_boucle', $boucle);
1074                if ($boucle->return === false) continue;
1075                // appeler la fonction de definition de la boucle
1076
1077                if ($req = $boucle->type_requete) {
1078                        $f = 'boucle_'.strtoupper($req);
1079                // si pas de definition perso, definition spip
1080                        if (!function_exists($f)) $f = $f.'_dist';
1081                        // laquelle a une definition par defaut
1082                        if (!function_exists($f)) $f = 'boucle_DEFAUT';
1083                        if (!function_exists($f)) $f = 'boucle_DEFAUT_dist';
1084                        $req = "\n\n\tstatic \$command = array();\n\t" .
1085                                        "static \$connect;\n\t" .
1086                                        "\$command['connect'] = \$connect = " .
1087                                _q($boucle->sql_serveur) .
1088                                ";" .
1089                                $f($id, $boucles);
1090                } else $req = ("\n\treturn '';");
1091
1092                $boucles[$id]->return = 
1093                        "function BOUCLE" . strtr($id,"-","_") . $nom .
1094                        '(&$Cache, &$Pile, &$doublons, &$Numrows, $SP) {' .
1095                        $req .
1096                        "\n}\n\n";
1097
1098                if ($debug)
1099                        $GLOBALS['debug_objets']['code'][$nom.$id] = $boucles[$id]->return;
1100        }
1101
1102        // Au final, si le corps ou un critere au moins s'est mal compile
1103        // retourner False, sinon inserer leur decompilation
1104        if (is_bool($corps)) return false;
1105        foreach($boucles as $id => $boucle) {
1106                if ($boucle->return === false) return false;
1107                $boucle->return = "\n\n/* BOUCLE " .
1108                        $boucle->type_requete .
1109                        " " .
1110                        (!$debug ? '' : 
1111                        str_replace('*/', '* /', 
1112                                decompiler_criteres($boucle->param, 
1113                                                $boucle->criteres))) .
1114                        " */\n\n " .
1115                        $boucle->return;
1116        }
1117
1118        $secondes = spip_timer('calcul_skel');
1119        spip_log("COMPIL ($secondes) [$sourcefile] $nom.php");
1120
1121        // Assimiler la fct principale a une boucle anonyme, c'est plus simple
1122        $code = new Boucle;
1123        $code->descr = $descr;
1124        $code->return = '
1125//
1126// Fonction principale du squelette ' . 
1127        $sourcefile . 
1128        ($connect ? " pour $connect" : '') . 
1129        (!CODE_COMMENTE ? '' : "\n// Temps de compilation total: $secondes") .
1130        "\n//" .
1131        (!$debug ? '' : ("\n/*\n" . 
1132                        str_replace('*/', '* /', public_decompiler($squelette)) 
1133                                      . "\n*/")) . "
1134
1135function " . $nom . '($Cache, $Pile, $doublons=array(), $Numrows=array(), $SP=0) {
1136
1137'
1138        // reporter de maniere securisee les doublons inclus
1139.'
1140        if (isset($Pile[0]["doublons"]) AND is_array($Pile[0]["doublons"]))
1141                $doublons = nettoyer_env_doublons($Pile[0]["doublons"]);
1142
1143        $connect = ' .
1144        _q($connect) . ';
1145        $page = ' .
1146        // ATTENTION, le calcul de l'expression $corps affectera $Cache
1147        // c'est pourquoi on l'affecte a la variable auxiliaire $page.
1148        // avant de referencer $Cache
1149        $corps . ";
1150
1151        return analyse_resultat_skel(".var_export($nom,true)
1152                .", \$Cache, \$page, ".var_export($sourcefile,true).");
1153}";
1154
1155        $boucles[''] = $code;
1156        return $boucles;
1157}
1158
1159
1160
1161/**
1162 * Requeteur pour les boucles (php:nom_iterateur)
1163 *
1164 * Analyse si le nom d'iterateur correspond bien a une classe PHP existante
1165 * et dans ce cas charge la boucle avec cet iterateur.
1166 * Affichera une erreur dans le cas contraire.
1167 *
1168 * @param $boucles Liste des boucles
1169 * @param $boucle  La boucle parcourue
1170 * @param $id      L'identifiant de la boucle parcourue
1171 *
1172**/
1173function requeteur_php_dist(&$boucles, &$boucle, &$id) {
1174        if (class_exists($boucle->type_requete)) {
1175                $g = charger_fonction('php', 'iterateur');
1176                $boucles[$id] = $g($boucle, $boucle->type_requete);
1177        } else {
1178                $x = $boucle->type_requete;
1179                $boucle->type_requete = false;
1180                $msg = array('zbug_iterateur_inconnu',
1181                                array('iterateur' => $x));
1182                erreur_squelette($msg, $boucle);
1183        }
1184}
1185
1186
1187/**
1188 * Requeteur pour les boucles (data:type de donnee)
1189 * note: (DATA) tout court ne passe pas par ici.
1190 *
1191 * Analyse si le type de donnee peut etre traite
1192 * et dans ce cas charge la boucle avec cet iterateur.
1193 * Affichera une erreur dans le cas contraire.
1194 *
1195 * @param $boucles Liste des boucles
1196 * @param $boucle  La boucle parcourue
1197 * @param $id      L'identifiant de la boucle parcourue
1198 *
1199**/
1200function requeteur_data_dist(&$boucles, &$boucle, &$id) {
1201        include_spip('iterateur/data');
1202        if ($h = charger_fonction($boucle->type_requete . '_to_array' , 'inc', true)) {
1203                $g = charger_fonction('data', 'iterateur');
1204                $boucles[$id] = $g($boucle);
1205                // from[0] stocke le type de data (rss, yql, ...)
1206                $boucles[$id]->from[] = $boucle->type_requete;
1207               
1208        } else {
1209                $x = $boucle->type_requete;
1210                $boucle->type_requete = false;
1211                $msg = array('zbug_requeteur_inconnu',
1212                                array(
1213                                'requeteur' => 'data',
1214                                'type' => $x
1215                ));
1216                erreur_squelette($msg, $boucle);
1217        }
1218}
1219
1220?>
Note: See TracBrowser for help on using the repository browser.