[ Index ]
 

Code source de SPIP 1.9.2c

Accédez au Source d'autres logiciels libres

title

Body

[fermer]

/ecrire/public/ -> compiler.php (source)

   1  <?php
   2  
   3  /***************************************************************************\
   4   *  SPIP, Systeme de publication pour l'internet                           *
   5   *                                                                         *
   6   *  Copyright (c) 2001-2007                                                *
   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  
  18  if (!defined("_ECRIRE_INC_VERSION")) return;
  19  
  20  // reperer un code ne calculant rien, meme avec commentaire
  21  define('CODE_MONOTONE', ",^(\n//[^\n]*\n)?\(?'([^'])*'\)?$,");
  22  
  23  // Definition de la structure $p, et fonctions de recherche et de reservation
  24  // dans l'arborescence des boucles
  25  include_spip('public/references');
  26  
  27  // definition des boucles
  28  include_spip('public/boucles');
  29  
  30  // definition des criteres
  31  include_spip('public/criteres');
  32  
  33  // definition des balises
  34  include_spip('public/balises');
  35  
  36  // definition de l'API
  37  include_spip('public/interfaces');
  38  
  39  # definition des tables
  40  include_spip('base/serial');
  41  
  42  // http://doc.spip.org/@argumenter_inclure
  43  function argumenter_inclure($struct, $descr, &$boucles, $id_boucle, $echap=true){
  44      $l = array();
  45      $lang = '';
  46      foreach($struct->param as $val) {
  47          $var = array_shift($val);
  48          if ($var == 'lang')
  49              $lang = $val;
  50          else
  51              $l[$var] = ($echap?"\'$var\' => ' . argumenter_squelette(":"'$var' => ")  .
  52              ($val
  53                  ? calculer_liste($val[0], $descr, $boucles, $id_boucle)
  54                  : index_pile($id_boucle, $var, $boucles)
  55              ) . ($echap?") . '":" ");
  56      }
  57      // Cas particulier de la langue : si {lang=xx} est definie, on
  58      // la passe, sinon on passe la langue courante au moment du calcul
  59      $l['lang'] = ($echap?"\'lang\' => ' . argumenter_squelette(":"'lang' => ")  .
  60          ($lang
  61              ? calculer_liste($lang[0], $descr, $boucles, $id_boucle)
  62              : '$GLOBALS["spip_lang"]'
  63              ) . ($echap?") . '":" ");
  64      return $l;
  65  }
  66  
  67  //
  68  // Calculer un <INCLURE()>
  69  //
  70  // http://doc.spip.org/@calculer_inclure
  71  function calculer_inclure($struct, $descr, &$boucles, $id_boucle) {
  72  
  73      # Si pas raccourci <INCLURE{fond=xxx}> 
  74      # chercher le fichier, eventuellement en changeant.php3 => .php
  75      # et en gardant la compatibilite <INCLURE(page.php3)>
  76      if ($fichier = $struct->texte) {
  77          if (preg_match(',^(.*[.]php)3?$,', $fichier, $r)) {
  78              $fichier = $r[1];
  79          }
  80          if ($fichier == 'page.php') {
  81              $fichier = '';
  82          } else {
  83              if (!$path = find_in_path($fichier))
  84                  $path = find_in_path($fichier.'3');
  85              if (!$path) {
  86              spip_log("ERREUR: <INCLURE($fichier)> impossible");
  87              erreur_squelette(_T('zbug_info_erreur_squelette'),
  88                   "&lt;INCLURE($fichier)&gt; - "
  89                   ._T('fichier_introuvable', array('fichier' => $fichier)));
  90              return "'<!-- Erreur INCLURE(".texte_script($fichier).") -->'";
  91              }
  92          }
  93      }
  94  
  95      return "\n'<".
  96          "?php\n\t\$contexte_inclus = array(" .
  97          join(",\n\t", argumenter_inclure($struct, $descr, $boucles, $id_boucle)) .
  98          ");" .
  99          "\n\tinclude(" .
 100          ($fichier ? "\\'$path\\'" : ('_DIR_RESTREINT . "public.php"')).
 101          ");" .
 102          "\n?'." . "'>'";
 103   }
 104  
 105  //
 106  // calculer_boucle() produit le corps PHP d'une boucle Spip. 
 107  // ce corps remplit une variable $t0 retournee en valeur.
 108  // Ici on distingue boucles recursives et boucle a requete SQL
 109  // et on insere le code d'envoi au debusqueur du resultat de la fonction.
 110  
 111  // http://doc.spip.org/@calculer_boucle
 112  function calculer_boucle($id_boucle, &$boucles) {
 113   
 114    if ($boucles[$id_boucle]->type_requete == 'boucle')  {
 115      $corps = calculer_boucle_rec($id_boucle, $boucles);
 116      $req = "";
 117      } else {
 118        $corps = calculer_boucle_nonrec($id_boucle, $boucles);
 119        // attention, ne calculer la requete que maintenant
 120        // car la fonction precedente appelle index_pile qui influe dessus
 121        $req =    (($init = $boucles[$id_boucle]->doublons) ?
 122              ("\n\t$init = array();") : '') .
 123          calculer_requete_sql($boucles[$id_boucle]);
 124      }
 125    $notrace = isset($GLOBALS['var_mode_affiche']) ? ($GLOBALS['var_mode_affiche'] != 'resultat') : true;
 126    return $req . $corps 
 127      . ($notrace ? "" : "
 128          boucle_debug_resultat('$id_boucle', 'resultat', \$t0);")
 129      .  "\n    return \$t0;";
 130  }
 131  
 132  // compil d'une boucle recursive. 
 133  // il suffit (ET IL FAUT) sauvegarder les valeurs des arguments passes par
 134  // reference, car par definition un tel passage ne les sauvegarde pas
 135  
 136  // http://doc.spip.org/@calculer_boucle_rec
 137  function calculer_boucle_rec($id_boucle, &$boucles) {
 138      $nom = $boucles[$id_boucle]->param[0];
 139      return "\n\t\$save_numrows = (\$Numrows['$nom']);"
 140      . "\n\t\$t0 = " . $boucles[$id_boucle]->return . ";"
 141      . "\n\t\$Numrows['$nom'] = (\$save_numrows);";
 142  }
 143  
 144  // compil d'une boucle non recursive. 
 145  // c'est un "while (fetch_sql)" dans le cas général,
 146  // qu'on essaye d'optimiser un max.
 147  
 148  // http://doc.spip.org/@calculer_boucle_nonrec
 149  function calculer_boucle_nonrec($id_boucle, &$boucles) {
 150  
 151      $boucle = &$boucles[$id_boucle];
 152      $return = $boucle->return;
 153      $type_boucle = $boucle->type_requete;
 154      $primary = $boucle->primary;
 155      $constant = preg_match(CODE_MONOTONE,$return);
 156  
 157      // Cas {1/3} {1,4} {n-2,1}...
 158  
 159      $flag_cpt = $boucle->mode_partie ||$boucle->cptrows;
 160  
 161      //
 162      // Creer le debut du corps de la boucle :
 163      //
 164      $corps = !$flag_cpt ? '' : "\n        \$Numrows['$id_boucle']['compteur_boucle']++;";
 165  
 166      if ($boucle->mode_partie)
 167          $corps .= "
 168          if (\$Numrows['$id_boucle']['compteur_boucle']-1 >= \$debut_boucle) {
 169          if (\$Numrows['$id_boucle']['compteur_boucle']-1 > \$fin_boucle) break;\n";
 170  
 171      // Calculer les invalideurs si c'est une boucle non constante et si on
 172      // souhaite invalider ces elements
 173      if (!$constant AND $primary) {
 174          include_spip('inc/invalideur');
 175          if (function_exists($i = 'calcul_invalideurs'))
 176              $corps = $i($corps, $primary, $boucles, $id_boucle);
 177      }
 178  
 179      // faudrait expanser le foreach a la compil, car y en a souvent qu'un 
 180      // et puis faire un [] plutot qu'un "','."
 181      if ($boucle->doublons)
 182          $corps .= "\n\t\t\tforeach(" . $boucle->doublons . ' as $k) $doublons[$k] .= "," . ' .
 183          index_pile($id_boucle, $primary, $boucles)
 184          . "; // doublons\n";
 185  
 186  
 187      if (count($boucle->separateur))
 188        $code_sep = ("'" . str_replace("'","\'",join('',$boucle->separateur)) . "'");
 189  
 190      // La boucle doit-elle selectionner la langue ?
 191      // -. par defaut, les boucles suivantes le font
 192      // "peut-etre", c'est-a-dire si forcer_lang == false.
 193      // - . a moins d'une demande explicite
 194      if (!$constant && $boucle->lang_select != 'non' &&
 195          (($boucle->lang_select == 'oui')  ||
 196              (
 197              $type_boucle == 'articles'
 198              OR $type_boucle == 'rubriques'
 199              OR $type_boucle == 'hierarchie'
 200              OR $type_boucle == 'breves'
 201              )))
 202        {
 203            $corps .= 
 204            (($boucle->lang_select != 'oui') ? 
 205              "\t\tif (!\$GLOBALS['forcer_lang'])\n\t " : '')
 206            . "\t\t\$GLOBALS['spip_lang'] = (\$x = "
 207            . index_pile($id_boucle, 'lang', $boucles)
 208            . ') ? $x : $old_lang;';
 209          // Memoriser la langue avant la boucle pour la restituer apres
 210            $init = "\n    \$old_lang = \$GLOBALS['spip_lang'];";
 211            $fin = "\n    \$GLOBALS['spip_lang'] = \$old_lang;";
 212  
 213        }
 214      else {
 215          $init = '';
 216          $fin = '';
 217      }
 218  
 219      // gestion optimale des separateurs et des boucles constantes
 220      $corps .= 
 221          ((!$boucle->separateur) ? 
 222              (($constant && !$corps) ? $return :
 223                   ("\n\t\t" . '$t0 .= ' . $return . ";")) :
 224           ("\n\t\t\$t1 " .
 225              ((strpos($return, '$t1.') === 0) ? 
 226               (".=" . substr($return,4)) :
 227               ('= ' . $return)) .
 228            ";\n\t\t" .
 229            '$t0 .= (($t1 && $t0) ? ' . $code_sep . " : '') . \$t1;"));
 230       
 231      // Fin de parties
 232      if ($boucle->mode_partie) $corps .= "\n        }\n";
 233  
 234  
 235      // si le corps est une constante, ne pas appeler le serveur N fois!
 236      if (preg_match(CODE_MONOTONE,$corps, $r)) {
 237          if (!$r[2]) {
 238              if (!$boucle->numrows)
 239                  return 'return "";';
 240              else
 241                  $corps = "";
 242          } else {
 243              $boucle->numrows = true;
 244              $corps = "\n    ".'for($x=$Numrows["'.$id_boucle.'"]["total"];$x>0;$x--)
 245              $t0 .= ' . $corps .';';
 246          }
 247      } else {
 248  
 249          $corps = $init . '
 250  
 251      // RESULTATS
 252      while ($Pile[$SP] = @spip_abstract_fetch($result,"' .
 253            $boucle->sql_serveur .
 254            '")) {' . 
 255            "\n$corps\n    }\n" .
 256            $fin ;
 257      }
 258  
 259      return ($boucle->mode_partie ? 
 260             calculer_parties($boucles, $id_boucle) :
 261             (!$boucle->numrows ? '' :
 262              ( "\n    \$Numrows['" .
 263              $id_boucle .
 264              "']['total'] = @spip_abstract_count(\$result,'" .
 265              $boucle->sql_serveur .
 266                "');"))) .
 267          (!$flag_cpt  ? "" :
 268              "\n    \$Numrows['$id_boucle']['compteur_boucle'] = 0;")
 269          . '
 270      $t0 = "";
 271      $SP++;'
 272          .
 273          $corps .
 274          "\n    @spip_abstract_free(\$result,'" .
 275          $boucle->sql_serveur . "');";
 276  }
 277  
 278  
 279  // http://doc.spip.org/@calculer_requete_sql
 280  function calculer_requete_sql(&$boucle)
 281  {
 282      if (!$order = $boucle->order
 283      AND !$order = $boucle->default_order)
 284          $order = array();
 285  
 286      return   ($boucle->hierarchie ? "\n\t$boucle->hierarchie" : '')
 287          . $boucle->in 
 288          . $boucle->hash . 
 289          "\n\n    // REQUETE
 290      \$result = spip_optim_select(\n\t\tarray(\"" . 
 291          # En absence de champ c'est un decompte : 
 292            # prendre une constante pour avoir qqch
 293          (!$boucle->select ? 1 :
 294           join("\",\n\t\t\"", $boucle->select)) .
 295          '"), # SELECT
 296          ' . calculer_from($boucle) .
 297          ', # FROM
 298          ' . calculer_dump_array($boucle->where) .
 299          ', # WHERE
 300          ' . calculer_dump_join($boucle->join)
 301          . ', # WHERE pour jointure
 302          ' . (!$boucle->group ? "''" : 
 303               ('"' . join(", ", $boucle->group)) . '"') .
 304          ', # GROUP
 305          array(' .
 306              join(', ', $order) .
 307          "), # ORDER
 308          " . (strpos($boucle->limit, 'intval') === false ?
 309              "'".$boucle->limit."'" :
 310              $boucle->limit). ", # LIMIT
 311          '".$boucle->sous_requete. "', # sous
 312          " . calculer_dump_array($boucle->having) . ", # HAVING
 313          '".$boucle->id_table."', # table
 314          '".$boucle->id_boucle."', # boucle
 315          '".$boucle->sql_serveur."'); # serveur";
 316  }
 317  
 318  
 319  // http://doc.spip.org/@calculer_dump_array
 320  function calculer_dump_array($a)
 321  {
 322    if (!is_array($a)) return $a ;
 323    $res = "";
 324    if ($a AND $a[0] == "'?'") 
 325      return ("(" . calculer_dump_array($a[1]) .
 326          " ? " . calculer_dump_array($a[2]) .
 327          " : " . calculer_dump_array($a[3]) .
 328          ")");
 329    else {
 330      foreach($a as $k => $v) $res .= ", " . calculer_dump_array($v);
 331      return "\n\t\t\tarray(" . substr($res,2) . ')';
 332    }
 333  }
 334  
 335  // http://doc.spip.org/@calculer_dump_join
 336  function calculer_dump_join($a)
 337  {
 338    $res = "";
 339    foreach($a as $k => $v) $res .= ", $k => array('$v[0]', '$v[1]')";
 340    return 'array(' . substr($res,2) . ')';
 341  }
 342  
 343  // http://doc.spip.org/@calculer_from
 344  function calculer_from(&$boucle)
 345  {
 346    $res = "";
 347    foreach($boucle->from as $k => $v) $res .= ",'$k' => '$v'";
 348    return 'array(' . substr($res,1) . ')';
 349  }
 350  
 351  //
 352  // fonction traitant les criteres {1,n} (analyses dans inc-criteres)
 353  //
 354  ## a deplacer dans inc-criteres ??
 355  // http://doc.spip.org/@calculer_parties
 356  function calculer_parties($boucles, $id_boucle) {
 357  
 358      $boucle = &$boucles[$id_boucle];
 359      $partie = $boucle->partie;
 360      $mode_partie = $boucle->mode_partie;
 361      $total_parties = $boucle->total_parties;
 362  
 363      // Notes :
 364      // $debut_boucle et $fin_boucle sont les indices SQL du premier
 365      // et du dernier demandes dans la boucle : 0 pour le premier,
 366      // n-1 pour le dernier ; donc total_boucle = 1 + debut - fin
 367  
 368      // nombre total avant partition
 369      $retour = "\n\n    // Partition\n    " .
 370          '$nombre_boucle = @spip_abstract_count($result,"' .
 371          $boucle->sql_serveur .
 372          '");';
 373  
 374      preg_match(",([+-/p])([+-/])?,", $mode_partie, $regs);
 375      list(,$op1,$op2) = $regs;
 376  
 377      // {1/3}
 378      if ($op1 == '/') {
 379          $pmoins1 = is_numeric($partie) ? ($partie-1) : "($partie-1)";
 380          $totpos = is_numeric($total_parties) ? ($total_parties) :
 381            "($total_parties ? $total_parties : 1)";
 382          $retour .= "\n    "
 383            .'$debut_boucle = ceil(($nombre_boucle * '
 384            . $pmoins1 . ')/' . $totpos . ");";
 385          $fin = 'ceil (($nombre_boucle * '
 386              . $partie . ')/' . $totpos . ") - 1";
 387      }
 388  
 389      // {1,x}
 390      elseif ($op1 == '+') {
 391          $retour .= "\n    "
 392              . '$debut_boucle = ' . $partie . ';';
 393      }
 394      // {n-1,x}
 395      elseif ($op1 == '-') {
 396          $retour .= "\n    "
 397              . '$debut_boucle = $nombre_boucle - ' . $partie . ';';
 398      }
 399      // {pagination}
 400      elseif ($op1 == 'p') {
 401          $retour .= "\n    "
 402              . '$debut_boucle = ' . $partie . ';';
 403      }
 404  
 405      // {x,1}
 406      if ($op2 == '+') {
 407          $fin = '$debut_boucle'
 408            . (is_numeric($total_parties) ?
 409               (($total_parties==1) ? "" :(' + ' . ($total_parties-1))):
 410               ('+' . $total_parties . ' - 1'));
 411      }
 412      // {x,n-1}
 413      elseif ($op2 == '-') {
 414          $fin = '$debut_boucle + $nombre_boucle - '
 415            . (is_numeric($total_parties) ? ($total_parties+1) :
 416               ($total_parties . ' - 1'));
 417      }
 418  
 419      // Rabattre $fin_boucle sur le maximum
 420      $retour .= "\n    "
 421          .'$fin_boucle = min(' . $fin . ', $nombre_boucle - 1);';
 422  
 423      // calcul du total boucle final
 424      $retour .= "\n    "
 425          .'$Numrows[\''.$id_boucle.'\']["grand_total"] = $nombre_boucle;'
 426          . "\n    "
 427          .'$Numrows[\''.$id_boucle.'\']["total"] = max(0,$fin_boucle - $debut_boucle + 1);';
 428  
 429      return $retour;
 430  }
 431  
 432  // Production du code PHP a partir de la sequence livree par le phraseur
 433  // $boucles est passe par reference pour affectation par index_pile.
 434  // Retourne une expression PHP,
 435  // (qui sera argument d'un Return ou la partie droite d'une affectation).
 436  
 437  // http://doc.spip.org/@calculer_liste
 438  function calculer_liste($tableau, $descr, &$boucles, $id_boucle='') {
 439      if (!$tableau) return "''";
 440      if (!isset($descr['niv'])) $descr['niv'] = 0;
 441      $codes = compile_cas($tableau, $descr, $boucles, $id_boucle);
 442      $n = count($codes);
 443      if (!$n) return "''";
 444      $tab = str_repeat("\t", $descr['niv']);
 445      if (!isset($GLOBALS['var_mode_affiche'])
 446      OR $GLOBALS['var_mode_affiche'] != 'validation')
 447        return
 448          (($n==1) ? $codes[0] : 
 449               "(" . join (" .\n$tab", $codes) . ")");
 450      else return "@debug_sequence('$id_boucle', '" .
 451        ($descr['nom']) .
 452        "', " .
 453        $descr['niv'] .
 454        ",  array(" .
 455        join(" ,\n$tab", $codes) . "))";
 456  }
 457  
 458  // http://doc.spip.org/@compile_cas
 459  function compile_cas($tableau, $descr, &$boucles, $id_boucle) {
 460          $codes = array();
 461      // cas de la boucle recursive
 462      if (is_array($id_boucle)) 
 463        $id_boucle = $id_boucle[0];
 464      $type = !$id_boucle ? '' : $boucles[$id_boucle]->type_requete;
 465      $tab = str_repeat("\t", ++$descr['niv']);
 466      $mode = isset($GLOBALS['var_mode_affiche']) ? $GLOBALS['var_mode_affiche'] : '';
 467      // chaque commentaire introduit dans le code doit commencer
 468      // par un caractere distinguant le cas, pour exploitation par debug.
 469      foreach ($tableau as $p) {
 470  
 471          switch($p->type) {
 472          // texte seul
 473          case 'texte':
 474              $code = "'".str_replace(array("\\","'"),array("\\\\","\\'"), $p->texte)."'";
 475  
 476              $commentaire= strlen($p->texte) . " signes";
 477              $avant='';
 478              $apres='';
 479              $altern = "''";
 480              break;
 481  
 482          case 'polyglotte':
 483              $code = "";
 484              foreach($p->traductions as $k => $v) {
 485                $code .= ",'" .
 486                  str_replace(array("\\","'"),array("\\\\","\\'"), $k) .
 487                  "' => '" .
 488                  str_replace(array("\\","'"),array("\\\\","\\'"), $v) .
 489                  "'";
 490              }
 491              $code = "multi_trad(array(" .
 492                 substr($code,1) .
 493                "))";
 494              $commentaire= '&';
 495              $avant='';
 496              $apres='';
 497              $altern = "''";
 498              break;
 499  
 500          // inclure
 501          case 'include':
 502              $code = calculer_inclure($p, $descr, $boucles, $id_boucle);
 503              
 504              $commentaire = '<INCLURE ' . addslashes(str_replace("\n", ' ', $code)) . '>';
 505              $avant='';
 506              $apres='';
 507              $altern = "''";
 508              break;
 509  
 510          // boucle
 511          case 'boucle':
 512              $nom = $p->id_boucle;
 513              $newdescr = $descr;
 514              $newdescr['id_mere'] = $nom;
 515              $newdescr['niv']++;
 516              $code = 'BOUCLE' .
 517                str_replace("-","_", $nom) . $descr['nom'] .
 518                '($Cache, $Pile, $doublons, $Numrows, $SP)';
 519              $commentaire= "?$nom";
 520              $avant = calculer_liste($p->avant,
 521                  $newdescr, $boucles, $id_boucle);
 522              $apres = calculer_liste($p->apres,
 523                  $newdescr, $boucles, $id_boucle);
 524              $newdescr['niv']--;
 525              $altern = calculer_liste($p->altern,
 526                  $newdescr, $boucles, $id_boucle);
 527              break;
 528  
 529          case 'idiome':
 530              $code = "_T('" . $p->module . ":" .$p->nom_champ . "')";
 531              if ($p->param) {
 532                $p->id_boucle = $id_boucle;
 533                $p->boucles = &$boucles;
 534                $code = compose_filtres($p, $code);
 535              }
 536              $commentaire = ":";
 537              $avant='';
 538              $apres='';
 539              $altern = "''";
 540              break;
 541  
 542          case 'champ':
 543  
 544              // cette structure pourrait etre completee des le phrase' (a faire)
 545              $p->id_boucle = $id_boucle;
 546              $p->boucles = &$boucles;
 547              $p->descr = $descr;
 548              #$p->interdire_scripts = true;
 549              $p->type_requete = $type;
 550  
 551              $code = calculer_champ($p);
 552              $commentaire = '#' . $p->nom_champ . $p->etoile;
 553              $avant = calculer_liste($p->avant,
 554                  $descr, $boucles, $id_boucle);
 555              $apres = calculer_liste($p->apres,
 556                  $descr, $boucles, $id_boucle);
 557              $altern = "''";
 558              break;
 559  
 560          default: 
 561            erreur_squelette(_T('zbug_info_erreur_squelette'));
 562          } // switch
 563  
 564          if ($code != "''") {
 565              if ($avant == "''")
 566                  $avant = '';
 567              if ($apres == "''")
 568                  $apres = '';
 569              if ($avant||$apres||($altern!="''")) {
 570                  $t = '$t' . $descr['niv'];
 571                  $res = (!$avant ? "" : "$avant . ") . 
 572                      $t .
 573                      (!$apres ? "" : " . $apres");
 574                  $code = "((strval($t = $code)!='')"
 575                      ." ?\n\t$tab($res) :\n\t$tab($altern))";
 576              }
 577  
 578              // gestion d'une boucle-fragment (ahah)
 579              if (isset($p->modificateur['fragment'])) {
 580                  static $nombre_fragments = array();
 581                  $fragment = $p->modificateur['fragment'];
 582                  $fragment .= $nombre_fragments[$p->modificateur['fragment']]++;
 583                  $code = "\n((\$f = ($code))?
 584                  '<div id=\"$fragment\" class=\"fragment\">'.\$f.'<!-- /$fragment --></div><"."?php stop_inclure(\"$fragment\"); ?".">':'')\n";
 585              }
 586  
 587          }
 588          if ($code != "''")
 589              $codes[]= (($mode == 'validation') ?
 590                  "array(" . $p->ligne . ", '$commentaire', $code)"
 591                  : (($mode == 'code') ?
 592                  "\n// $commentaire\n$code" :
 593                  $code));
 594      } // foreach
 595      return $codes;
 596  }
 597  
 598  // affichage du code produit
 599  
 600  // http://doc.spip.org/@code_boucle
 601  function code_boucle(&$boucles, $id, $nom)
 602  {
 603      $boucle = &$boucles[$id];
 604  
 605      // Indiquer la boucle en commentaire
 606      $pretty = '';
 607  
 608      if ($boucle->type_requete != 'boucle')
 609        {
 610          // Resynthetiser les criteres
 611          foreach ($boucle->param as $param) {
 612            $s = "";
 613            $sep = "";
 614            foreach ($param as $t) {
 615          if (is_array($t)) { // toujours vrai normalement
 616            $s .= $sep;
 617            $c = $t[0];
 618            if ($c->apres)
 619              $s .= ($c->apres . $c->texte . $c->apres);
 620            else {
 621          // faudrait decompiler aussi les balises...
 622              foreach ($t as $c)
 623                $s .=  ($c->type == 'texte') ? $c->texte : '#...';
 624            }
 625            $sep = ", ";
 626          }
 627            }
 628            $pretty .= ' {' . $s . '}';
 629          }
 630        }
 631  
 632      $pretty = "BOUCLE$id(".strtoupper($boucle->type_requete) . ")" .
 633          strtr($pretty,"\r\n", "  ");
 634  
 635      return $pretty;
 636  }
 637  
 638  
 639  // Prend en argument le texte d'un squelette (et son fichier d'origine)
 640  // sa grammaire et un nom.
 641  // Retourne une fonction PHP/SQL portant ce nom et calculant une page.
 642  // Pour appeler la fonction produite, lui fournir 2 tableaux de 1 e'le'ment:
 643  // - 1er: element 'cache' => nom (du fichier ou` mettre la page)
 644  // - 2e: element 0 contenant un environnement ('id_article => $id_article, etc)
 645  // Elle retourne alors un tableau de 5 e'le'ments:
 646  // - 'texte' => page HTML, application du squelette a` l'environnement;
 647  // - 'squelette' => le nom du squelette
 648  // - 'process_ins' => 'html' ou 'php' selon la pre'sence de PHP dynamique
 649  // - 'invalideurs' =>  de'pendances de cette page, pour invalider son cache.
 650  // - 'entetes' => tableau des entetes http
 651  // En cas d'erreur, elle retourne un tableau des 2 premiers elements seulement
 652  
 653  // http://doc.spip.org/@public_compiler_dist
 654  function public_compiler_dist($squelette, $nom, $gram, $sourcefile) {
 655    global  $table_des_tables, $tables_des_serveurs_sql, $tables_principales,
 656      $tables_jointures;
 657  
 658      // Pre-traitement : reperer le charset du squelette, et le convertir
 659      // Bonus : supprime le BOM
 660      include_spip('inc/charsets');
 661      $squelette = transcoder_page($squelette);
 662  
 663      // Hacke un eventuel tag xml "<?xml" pour qu'il ne soit pas traite comme php
 664      $squelette = str_replace('<'.'?xml', "#HTTP_HEADER{X-Xml-Hack: ok}<\1?xml", $squelette);
 665  
 666      // Phraser le squelette, selon sa grammaire
 667      // pour le moment: "html" seul connu (HTML+balises BOUCLE)
 668      $boucles = array();
 669      spip_timer('calcul_skel');
 670  
 671      $f = charger_fonction('phraser_'.$gram, 'public');
 672  
 673      $racine = $f($squelette, '',$boucles, $nom);
 674  
 675      // tableau des informations sur le squelette
 676      $descr = array('nom' => $nom, 'sourcefile' => $sourcefile);
 677  
 678      // une boucle documents est conditionnee par tout le reste!
 679      foreach($boucles as $id => $boucle) {
 680          $type = $boucle->type_requete;
 681          if ($type != 'boucle') {
 682            $boucles[$id]->descr = &$descr;
 683            if ($x = $table_des_tables[$type]) {
 684              $boucles[$id]->id_table = $x;
 685              $boucles[$id]->primary = $tables_principales["spip_$x"]['key']["PRIMARY KEY"];
 686              if ((!$boucles[$id]->jointures)
 687              AND (is_array($x = $tables_jointures['spip_' . $x])))
 688                $boucles[$id]->jointures = $x;
 689            } else {
 690              // table non Spip.
 691              $boucles[$id]->id_table = $type;
 692              $serveur = $boucle->sql_serveur;
 693              $x = $tables_des_serveurs_sql[$serveur ? $serveur : 'localhost'][$type]['key'];        
 694              $boucles[$id]->primary = ($x["PRIMARY KEY"] ? $x["PRIMARY KEY"] : $x["KEY"]);
 695            }
 696          }
 697          if (($boucle->type_requete == 'documents') && $boucle->doublons)
 698              { $descr['documents'] = true;  }
 699      }
 700      // Commencer par reperer les boucles appelees explicitement 
 701      // car elles indexent les arguments de maniere derogatoire
 702      foreach($boucles as $id => $boucle) { 
 703          if ($boucle->type_requete == 'boucle') {
 704              $boucles[$id]->descr = &$descr;
 705              $rec = &$boucles[$boucle->param[0]];
 706              if (!$rec) {
 707                  return array(_T('zbug_info_erreur_squelette'),
 708                          ($boucle->param[0]
 709                          . ' '. _T('zbug_boucle_recursive_undef')));
 710              } else {
 711                  $rec->externe = $id;
 712                  $descr['id_mere'] = $id;
 713                  $boucles[$id]->return =
 714                          calculer_liste(array($rec),
 715                               $descr,
 716                               $boucles,
 717                               $boucle->param);
 718              }
 719          }
 720      }
 721      foreach($boucles as $id => $boucle) { 
 722          $type = $boucle->type_requete;
 723          if ($type != 'boucle') {
 724            if ($boucle->param) {
 725                  $res = calculer_criteres($id, $boucles);
 726                  if (is_array($res)) return $res; # erreur
 727              }
 728            $descr['id_mere'] = $id;
 729            $boucles[$id]->return =
 730                calculer_liste($boucle->milieu,
 731                       $descr,
 732                       $boucles,
 733                       $id);
 734          }
 735      }
 736  
 737      // idem pour la racine
 738      $descr['id_mere'] = '';
 739      $corps = calculer_liste($racine, $descr, $boucles);
 740  
 741      // Calcul du corps de toutes les fonctions PHP,
 742      // en particulier les requetes SQL et TOTAL_BOUCLE
 743      // de'terminables seulement maintenant
 744  
 745      foreach($boucles as $id => $boucle) {
 746          // appeler la fonction de definition de la boucle
 747          $f = 'boucle_'.strtoupper($boucle->type_requete);
 748          // si pas de definition perso, definition spip
 749          if (!function_exists($f)) $f = $f.'_dist';
 750          // laquelle a une definition par defaut
 751          if (!function_exists($f)) $f = 'boucle_DEFAUT';
 752          if (!function_exists($f)) $f = 'boucle_DEFAUT_dist';
 753          $boucles[$id]->return = 
 754              "function BOUCLE" . strtr($id,"-","_") . $nom .
 755              '(&$Cache, &$Pile, &$doublons, &$Numrows, $SP) {' .
 756              $f($id, $boucles) .
 757              "\n}\n\n";
 758          if ($GLOBALS['var_mode'] == 'debug')
 759            boucle_debug_compile ($id, $nom, $boucles[$id]->return);
 760  
 761      }
 762  
 763      $code = "";
 764      foreach($boucles as $id => $boucle) {
 765          $code .= "\n//\n// <BOUCLE " .
 766  #          code_boucle($boucles, $id, $nom). # pas au point
 767            $boucle->type_requete .
 768            ">\n//\n" .
 769            $boucle->return;
 770      }
 771  
 772      $secondes = spip_timer('calcul_skel');
 773      spip_log("COMPIL ($secondes) ["
 774          .preg_replace(',\.html$,', '', $sourcefile)
 775          ."] $nom.php");
 776  
 777      $code = "<"."?php
 778  /*
 779   * Squelette : $sourcefile
 780   * Date :      ".gmdate("D, d M Y H:i:s", @filemtime($sourcefile))." GMT
 781   * Compile :   ".gmdate("D, d M Y H:i:s", time())." GMT ($secondes)
 782   * " . (!$boucles ?  "Pas de boucle" :
 783      ("Boucles :   " . join (', ', array_keys($boucles)))) ."
 784   */ " .
 785        $code . '
 786  
 787  //
 788  // Fonction principale du squelette ' . $sourcefile ."
 789  //
 790  function " . $nom . '($Cache, $Pile, $doublons=array(), $Numrows=array(), $SP=0) {
 791      $page = ' .
 792      // ATTENTION, le calcul du l'expression $corps affectera $Cache
 793      // c'est pourquoi on l'affecte a cette variable auxiliaire
 794      // avant de referencer $Cache
 795      $corps . ";
 796  
 797      return analyse_resultat_skel('$nom', \$Cache, \$page);
 798  }
 799  
 800  ?".">";
 801  
 802      if ($GLOBALS['var_mode'] == 'debug')
 803          squelette_debug_compile($nom, $sourcefile, $code, $squelette);
 804      return $code;
 805  
 806  }
 807  
 808  ?>


Généré le : Wed Nov 21 10:20:27 2007 par Balluche grâce à PHPXref 0.7
  Clicky Web Analytics