*
* Cherche les rubriques ayant des id_secteur ou profondeurs ne correspondant pas
* avec leur parent, et les met à jour. De même avec les articles et leur id_secteur
+ * On procede en iterant la profondeur de 1 en 1 pour ne pas risquer une boucle infinie sur reference circulaire
*
* @return void
**/
function propager_les_secteurs()
{
- // fixer les id_secteur des rubriques racines
+ // Profondeur 0
+ // Toutes les rubriques racines sont de profondeur 0
+ // et fixer les id_secteur des rubriques racines
sql_update('spip_rubriques', array('id_secteur'=>'id_rubrique','profondeur'=>0), "id_parent=0");
+ // Toute rubrique non racine est de profondeur >0
+ sql_updateq('spip_rubriques', array('profondeur'=>1), "id_parent<>0 AND profondeur=0");
+
+ // securite : pas plus d'iteration que de rubriques dans la base
+ $maxiter = sql_countsel("spip_rubriques");
// reparer les rubriques qui n'ont pas l'id_secteur de leur parent
+ // on fait profondeur par profondeur
+
+ $prof = 0;
do {
$continuer = false;
- $r = sql_select("A.id_rubrique AS id, R.id_secteur AS secteur, R.profondeur+1 as profondeur", "spip_rubriques AS A, spip_rubriques AS R", "A.id_parent = R.id_rubrique AND (A.id_secteur <> R.id_secteur OR A.profondeur <> R.profondeur+1)");
- while ($row = sql_fetch($r)) {
- sql_update("spip_rubriques", array("id_secteur" => $row['secteur'],'profondeur' => $row['profondeur']), "id_rubrique=".$row['id']);
+
+ // Par recursivite : si toutes les rubriques de profondeur $prof sont bonnes
+ // on fixe le profondeur $prof+1
+
+ // Toutes les rubriques dont le parent est de profondeur $prof ont une profondeur $prof+1
+ // on teste A.profondeur > $prof+1 car :
+ // - toutes les rubriques de profondeur 0 à $prof sont bonnes
+ // - si A.profondeur = $prof+1 c'est bon
+ // - cela nous protege de la boucle infinie en cas de reference circulaire dans les rubriques
+ $maxiter2 = $maxiter;
+ while ($maxiter2--
+ AND $rows = sql_allfetsel(
+ "A.id_rubrique AS id, R.id_secteur AS id_secteur, R.profondeur+1 as profondeur",
+ "spip_rubriques AS A JOIN spip_rubriques AS R ON A.id_parent = R.id_rubrique",
+ "R.profondeur=".intval($prof)." AND (A.id_secteur <> R.id_secteur OR A.profondeur > R.profondeur+1)",
+ "","R.id_secteur","0,100")){
+
+ $id_secteur = null;
+ $ids = array();
+ while ($row = array_shift($rows)) {
+ if ($row['id_secteur']!==$id_secteur){
+ if (count($ids))
+ sql_updateq("spip_rubriques", array("id_secteur" => $id_secteur,'profondeur' => $prof+1), sql_in('id_rubrique',$ids));
+ $id_secteur = $row['id_secteur'];
+ $ids = array();
+ }
+ $ids[] = $row['id'];
+ }
+ if (count($ids))
+ sql_updateq("spip_rubriques", array("id_secteur" => $id_secteur,'profondeur' => $prof+1), sql_in('id_rubrique',$ids));
+ }
+
+
+ // Toutes les rubriques de profondeur $prof+1 qui n'ont pas un parent de profondeur $prof sont decalees
+ $maxiter2 = $maxiter;
+ while ($maxiter2--
+ AND $rows = sql_allfetsel(
+ "id_rubrique as id",
+ "spip_rubriques",
+ "profondeur=".intval($prof+1)." AND id_parent NOT IN (".sql_get_select("zzz.id_rubrique","spip_rubriques AS zzz","zzz.profondeur=".intval($prof)).")",'','','0,100')){
+ $rows = array_map('reset',$rows);
+ sql_updateq("spip_rubriques", array('profondeur' => $prof+2), sql_in("id_rubrique",$rows));
+ }
+
+ // ici on a fini de valider $prof+1, toutes les rubriques de prondeur 0 a $prof+1 sont OK
+ // si pas de rubrique a profondeur $prof+1 pas la peine de continuer
+ // si il reste des rubriques non vues, c'est une branche morte ou reference circulaire (base foireuse)
+ // on arrete les frais
+ if (sql_countsel("spip_rubriques","profondeur=".intval($prof+1))){
+ $prof++;
$continuer = true;
}
- } while ($continuer);
-
+ }
+ while ($continuer AND $maxiter--);
+
+ // loger si la table des rubriques semble foireuse
+ // et mettre un id_secteur=0 sur ces rubriques pour eviter toute selection par les boucles
+ if (sql_countsel("spip_rubriques","profondeur>".intval($prof+1))){
+ spip_log("Les rubriques de profondeur>".($prof+1)." semblent suspectes (branches morte ou reference circulaire dans les parents)",_LOG_CRITIQUE);
+ sql_update("spip_rubriques",array('id_secteur'=>0),"profondeur>".intval($prof+1));
+ }
+
// reparer les articles
$r = sql_select("A.id_article AS id, R.id_secteur AS secteur", "spip_articles AS A, spip_rubriques AS R", "A.id_rubrique = R.id_rubrique AND A.id_secteur <> R.id_secteur");
* @see inc_calcul_hierarchie_in_dist()
* @param string|int|array $id
* Identifiant de la, ou des rubriques dont on veut obtenir les hierarchies
+ * @param bool $tout
+ * inclure la rubrique de depart dans la hierarchie ou non
* @return string
* Liste des identifiants séparés par des virgules,
* incluant les rubriques transmises et toutes leurs parentées
*/
-function calcul_hierarchie_in($id) {
+function calcul_hierarchie_in($id, $tout=true) {
$calcul_hierarchie_in = charger_fonction('calcul_hierarchie_in','inc');
- return $calcul_hierarchie_in($id);
+ return $calcul_hierarchie_in($id, $tout);
}
$branche = $r = $id;
// On ajoute une generation (les filles de la generation precedente)
- // jusqu'a epuisement
- while ($filles = sql_allfetsel(
+ // jusqu'a epuisement, en se protegeant des references circulaires
+ $maxiter = 10000;
+ while ($maxiter-- AND $filles = sql_allfetsel(
'id_rubrique',
'spip_rubriques',
- sql_in('id_parent', $r)." AND ". sql_in('id_rubrique', $r, 'NOT')
+ sql_in('id_parent', $r) ." AND ". sql_in('id_rubrique', $r, 'NOT')
)) {
- $r = join(',', array_map('array_shift', $filles));
+ $r = join(',', array_map('reset', $filles));
$branche .= ',' . $r;
}
*
* @param string|int|array $id
* Identifiant de la, ou des rubriques dont on veut obtenir les hierarchies
+ * @param bool $tout
+ * inclure la rubrique de depart dans la hierarchie ou non
* @return string
* Liste des identifiants séparés par des virgules,
* incluant les rubriques transmises et toutes leurs parentées
*/
-function inc_calcul_hierarchie_in_dist($id) {
+function inc_calcul_hierarchie_in_dist($id, $tout=true) {
static $b = array();
// normaliser $id qui a pu arriver comme un array, comme un entier, ou comme une chaine NN,NN,NN
if (isset($b[$id]))
return $b[$id];
- // Notre branche commence par la rubrique de depart
- $hier = $id;
+ // Notre branche commence par la rubrique de depart si $tout=true
+ $hier = $tout?$id:"";
// On ajoute une generation (les filles de la generation precedente)
- // jusqu'a epuisement
- while ($parents = sql_allfetsel('id_parent', 'spip_rubriques',sql_in('id_rubrique', $id))) {
+ // jusqu'a epuisement, en se protegeant des references circulaires
+ $maxiter = 10000;
+ while ($maxiter-- AND $parents = sql_allfetsel(
+ 'id_parent',
+ 'spip_rubriques',
+ sql_in('id_rubrique', $id) ." AND ". sql_in('id_parent',$hier,'NOT')
+ )) {
$id = join(',', array_map('reset', $parents));
- $hier .= ',' . $id;
+ $hier = $id.(strlen($hier)?','.$hier:'');
}
# securite pour ne pas plomber la conso memoire sur les sites prolifiques