function decompiler_boucle($struct, $fmt='', $prof=0) { $nom = $struct->id_boucle; $avant = public_decompiler($struct->avant, $fmt, $prof); $apres = public_decompiler($struct->apres, $fmt, $prof); $altern = public_decompiler($struct->altern, $fmt, $prof); $milieu = public_decompiler($struct->milieu, $fmt, $prof); $type = $struct->sql_serveur ? "$struct->sql_serveur:" : ''; $type .= ($struct->type_requete ? $struct->type_requete : $struct->table_optionnelle); if ($struct->jointures_explicites) $type .= " " . $struct->jointures_explicites; if ($struct->table_optionnelle) $type .= "?"; // Revoir le cas de la boucle recursive $crit = $struct->param; if ($crit AND !is_array($crit[0])) { $type = strtolower($type) . array_shift($crit); } $crit = decompiler_criteres($crit, $struct->criteres, $fmt, $prof) ; $f = 'format_boucle_' . ($fmt ? $fmt : _EXTENSION_SQUELETTES); return $f($avant, $nom, $type, $crit, $milieu, $apres, $altern, $prof); }
function decompiler_boucle($struct, $fmt = '', $prof = 0) { $nom = $struct->id_boucle; $avant = decompiler_($struct->avant, $fmt, $prof); $apres = decompiler_($struct->apres, $fmt, $prof); $altern = decompiler_($struct->altern, $fmt, $prof); $milieu = decompiler_($struct->milieu, $fmt, $prof); $type = $struct->sql_serveur ? "{$struct->sql_serveur}:" : ''; $type .= $struct->type_requete ? $struct->type_requete : $struct->table_optionnelle; if ($struct->jointures_explicites) { $type .= " " . $struct->jointures_explicites; } if ($struct->table_optionnelle) { $type .= "?"; } // Revoir le cas de la boucle recursive $crit = $struct->param; if ($crit and !is_array($crit[0])) { $type = strtolower($type) . array_shift($crit); } $crit = decompiler_criteres($struct, $fmt, $prof); $f = 'format_boucle_' . $fmt; return $f($avant, $nom, $type, $crit, $milieu, $apres, $altern, $prof); }
function compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $connect = ''){ global $tables_jointures; static $trouver_table; spip_timer('calcul_skel'); if (isset($GLOBALS['var_mode']) AND $GLOBALS['var_mode']=='debug'){ $GLOBALS['debug_objets']['squelette'][$nom] = $descr['squelette']; $GLOBALS['debug_objets']['sourcefile'][$nom] = $sourcefile; if (!isset($GLOBALS['debug_objets']['principal'])) $GLOBALS['debug_objets']['principal'] = $nom; } foreach ($boucles as $id => $boucle){ $GLOBALS['debug_objets']['boucle'][$nom . $id] = $boucle; } $descr['documents'] = compile_inclure_doublons($squelette); // Demander la description des tables une fois pour toutes // et reperer si les doublons sont demandes // pour un inclure ou une boucle document // c'est utile a la fonction champs_traitements if (!$trouver_table) $trouver_table = charger_fonction('trouver_table', 'base'); foreach ($boucles as $id => $boucle){ if (!($type = $boucle->type_requete)) continue; if (!$descr['documents'] AND ( (($type=='documents') AND $boucle->doublons) OR compile_inclure_doublons($boucle->avant) OR compile_inclure_doublons($boucle->apres) OR compile_inclure_doublons($boucle->milieu) OR compile_inclure_doublons($boucle->altern)) ) $descr['documents'] = true; if ($type!='boucle'){ if (!$boucles[$id]->sql_serveur AND $connect) $boucles[$id]->sql_serveur = $connect; $show = $trouver_table($type, $boucles[$id]->sql_serveur); // si la table n'existe pas avec le connecteur par defaut, // c'est peut etre une table qui necessite son connecteur dedie fourni // permet une ecriture allegee (GEO) -> (geo:GEO) if (!$show AND $show = $trouver_table($type, strtolower($type))) $boucles[$id]->sql_serveur = strtolower($type); if ($show){ $boucles[$id]->show = $show; // recopie les infos les plus importantes $boucles[$id]->primary = $show['key']["PRIMARY KEY"]; $boucles[$id]->id_table = $x = $show['id_table']; $boucles[$id]->from[$x] = $nom_table = $show['table']; $boucles[$id]->descr = &$descr; if ((!$boucles[$id]->jointures) AND (isset($tables_jointures[$nom_table])) AND is_array($x = $tables_jointures[$nom_table]) ) $boucles[$id]->jointures = $x; if ($boucles[$id]->jointures_explicites){ $jointures = preg_split("/\s+/", $boucles[$id]->jointures_explicites); while ($j = array_pop($jointures)) array_unshift($boucles[$id]->jointures, $j); } } else { // Pas une erreur si la table est optionnelle if ($boucles[$id]->table_optionnelle) $boucles[$id]->type_requete = ''; else { $boucles[$id]->type_requete = false; $boucle = $boucles[$id]; $x = (!$boucle->sql_serveur ? '' : ($boucle->sql_serveur . ":")) . $type; $msg = array('zbug_table_inconnue', array('table' => $x)); erreur_squelette($msg, $boucle); } } } } // Commencer par reperer les boucles appelees explicitement // car elles indexent les arguments de maniere derogatoire foreach ($boucles as $id => $boucle){ if ($boucle->type_requete=='boucle' AND $boucle->param){ $boucles[$id]->descr = &$descr; $rec = &$boucles[$boucle->param[0]]; if (!$rec){ $msg = array('zbug_boucle_recursive_undef', array('nom' => $boucle->param[0])); erreur_squelette($msg, $boucle); $boucles[$id]->type_requete = false; } else { $rec->externe = $id; $descr['id_mere'] = $id; $boucles[$id]->return = calculer_liste(array($rec), $descr, $boucles, $boucle->param); } } } foreach ($boucles as $id => $boucle){ $id = strval($id); // attention au type dans index_pile $type = $boucle->type_requete; if ($type AND $type!='boucle'){ $crit = !$boucle->param ? true : calculer_criteres($id, $boucles); $descr['id_mere'] = $id; $boucles[$id]->return = calculer_liste($boucle->milieu, $descr, $boucles, $id); // Si les criteres se sont mal compiles // ne pas tenter d'assembler le code final // (mais compiler le corps pour detection d'erreurs) if (is_array($crit)) $boucles[$id]->type_requete = false; } } // idem pour la racine $descr['id_mere'] = ''; $corps = calculer_liste($squelette, $descr, $boucles); $debug = (isset($GLOBALS['var_mode']) AND $GLOBALS['var_mode']=='debug'); if ($debug){ include_spip('public/decompiler'); include_spip('public/format_' . _EXTENSION_SQUELETTES); } // Calcul du corps de toutes les fonctions PHP, // en particulier les requetes SQL et TOTAL_BOUCLE // de'terminables seulement maintenant foreach ($boucles as $id => $boucle){ $boucle = $boucles[$id] = pipeline('pre_boucle', $boucle); if ($boucle->return===false) continue; // appeler la fonction de definition de la boucle if ($req = $boucle->type_requete){ $f = 'boucle_' . strtoupper($req); // si pas de definition perso, definition spip if (!function_exists($f)) $f = $f . '_dist'; // laquelle a une definition par defaut if (!function_exists($f)) $f = 'boucle_DEFAUT'; if (!function_exists($f)) $f = 'boucle_DEFAUT_dist'; $req = "\n\n\tstatic \$connect = " . _q($boucle->sql_serveur) . ";" . $f($id, $boucles); } else $req = ("\n\treturn '';"); $boucles[$id]->return = "function BOUCLE" . strtr($id, "-", "_") . $nom . '(&$Cache, &$Pile, &$doublons, &$Numrows, $SP) {' . $req . "\n}\n\n"; if ($debug) $GLOBALS['debug_objets']['code'][$nom . $id] = $boucles[$id]->return; } // Au final, si le corps ou un critere au moins s'est mal compile // retourner False, sinon inserer leur decompilation if (is_bool($corps)) return false; foreach ($boucles as $id => $boucle){ if ($boucle->return===false) return false; $boucle->return = "\n\n/* BOUCLE " . $boucle->type_requete . " " . (!$debug ? '' : str_replace('*/', '* /', decompiler_criteres($boucle->param, $boucle->criteres))) . " */\n\n " . $boucle->return; } $secondes = spip_timer('calcul_skel'); spip_log("COMPIL ($secondes) [$sourcefile] $nom.php"); // $connect n'est pas sûr : on nettoie $connect = preg_replace(',[^\w],', '', $connect); // Assimiler la fct principale a une boucle anonyme, c'est plus simple $code = new Boucle; $code->descr = $descr; $code->return = ' // // Fonction principale du squelette ' . $sourcefile . ($connect ? " pour $connect" : '') . (!CODE_COMMENTE ? '' : "\n// Temps de compilation total: $secondes") . "\n//" . (!$debug ? '' : ("\n/*\n" . str_replace('*/', '* /', public_decompiler($squelette)) . "\n*/")) . " function " . $nom . '($Cache, $Pile, $doublons=array(), $Numrows=array(), $SP=0) { ' // reporter de maniere securisee les doublons inclus . ' if (isset($Pile[0]["doublons"]) AND is_array($Pile[0]["doublons"])) $doublons = nettoyer_env_doublons($Pile[0]["doublons"]); $connect = ' . _q($connect) . '; $page = ' . // ATTENTION, le calcul de l'expression $corps affectera $Cache // c'est pourquoi on l'affecte a la variable auxiliaire $page. // avant de referencer $Cache $corps . "; return analyse_resultat_skel(" . var_export($nom, true) . ", \$Cache, \$page, " . var_export($sourcefile, true) . "); }"; $boucles[''] = $code; return $boucles; }
function debusquer_navigation_boucles($boucles, $nom_skel, $self) { $i = 0; $res = ''; $var_mode_objet = _request('var_mode_objet'); foreach ($boucles as $objet => $boucle) { if (substr($objet, 0, strlen($nom_skel)) == $nom_skel) { $i++; $nom = $boucle->id_boucle; $req = $boucle->type_requete; $crit = decompiler_criteres($boucle->param, $boucle->criteres); $self2 = $self . "&var_mode_objet=" . $objet; $res .= "\n<tr style='background-color: " . ($i%2 ? '#e0e0f0' : '#f8f8ff') . "'><td align='right'>$i</td><td>\n" . "<a class='debug_link_boucle' href='" . $self2 . "&var_mode_affiche=boucle#$nom_skel$nom'>" . _T('zbug_boucle') . "</a></td><td>\n<a class='debug_link_boucle' href='" . $self2 . "&var_mode_affiche=resultat#$nom_skel$nom'>" . _T('zbug_resultat') . "</a></td><td>\n<a class='debug_link_resultat' href='" . $self2 . "&var_mode_affiche=code#$nom_skel$nom'>" . _T('zbug_code') . "</a></td><td>\n<a class='debug_link_resultat' href='" . str_replace('var_mode=','var_profile=', $self2) . "'>" . _T('zbug_calcul') . "</a></td><td>\n" . (($var_mode_objet == $objet) ? "<b>$nom</b>" : $nom) . "</td><td>\n" . $req . "</td><td>\n" . $crit . "</td></tr>"; } } return $res; }