e3cf0c5a1b1c4d40194e94fb88583ee0606e330a
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
6 * Copyright (c) 2001-2017 *
7 * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
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 \***************************************************************************/
14 * Fichier gérant l'actualisation et le suivi des rubriques, et de leurs branches
16 * @package SPIP\Core\Rubriques
19 if (!defined('_ECRIRE_INC_VERSION')) {
25 * Recalcule les statuts d'une rubrique
27 * Fonction à appeler lorsque le statut d'un objet change dans une rubrique
28 * ou que la rubrique est deplacée.
30 * Si le statut passe a "publie", la rubrique et ses parents y passent aussi
31 * et les langues utilisees sont recalculées.
32 * Conséquences symétriques s'il est depublié.
34 * S'il est deplacé alors qu'il était publiée, double conséquence.
36 * Tout cela devrait passer en SQL, sous forme de Cascade SQL.
38 * @uses depublier_branche_rubrique_if()
39 * @uses calculer_prochain_postdate()
40 * @uses publier_branche_rubrique()
42 * @param int $id_rubrique
43 * Identifiant de la rubrique
44 * @param array $modifs
45 * Tableau de description des modifications.
46 * Peut avoir 2 index, 'statut' étant obligatoire :
47 * - statut : indique le nouveau statut de la rubrique
48 * - id_rubrique : indiquer la rubrique dans laquelle on déplace la rubrique (son nouveau parent donc)
49 * @param string $statut_ancien
50 * Ancien statut de la rubrique
51 * @param bool $postdate
52 * true pour recalculer aussi la date du prochain article post-daté
54 * true si le statut change effectivement
56 function calculer_rubriques_if($id_rubrique, $modifs, $statut_ancien = '', $postdate = false) {
58 if ($statut_ancien == 'publie') {
59 if (isset($modifs['statut'])
60 or isset($modifs['id_rubrique'])
61 or ($postdate and strtotime($postdate) > time())
63 $neuf |
= depublier_branche_rubrique_if($id_rubrique);
65 // ne publier que si c'est pas un postdate, ou si la date n'est pas dans le futur
67 calculer_prochain_postdate(true);
68 $neuf |
= (strtotime($postdate) <= time()); // par securite
69 } elseif (isset($modifs['id_rubrique'])) {
70 $neuf |
= publier_branche_rubrique($modifs['id_rubrique']);
72 } elseif (isset($modifs['statut']) and $modifs['statut'] == 'publie') {
74 calculer_prochain_postdate(true);
75 $neuf |
= (strtotime($postdate) <= time()); // par securite
77 $neuf |
= publier_branche_rubrique($id_rubrique);
81 if ($neuf) // Sauver la date de la derniere mise a jour (pour menu_rubriques)
83 ecrire_meta("date_calcul_rubriques", date("U"));
86 $langues = calculer_langues_utilisees();
87 ecrire_meta('langues_utilisees', $langues);
92 * Publie une rubrique et sa hiérarchie de rubriques
94 * Fonction à appeler lorsqu'on dépublie ou supprime quelque chose
97 * @todo Le nom de la fonction est trompeur, vu que la fonction remonte dans la hierarchie !
99 * @param int $id_rubrique
100 * Identifiant de la rubrique
102 * true si le statut change effectivement
104 function publier_branche_rubrique($id_rubrique) {
105 $id_pred = $id_rubrique;
107 sql_updateq('spip_rubriques', array('statut' => 'publie', 'date' => date('Y-m-d H:i:s')),
108 "id_rubrique=" . intval($id_rubrique));
109 $id_parent = sql_getfetsel('id_parent', 'spip_rubriques AS R', "R.id_rubrique=" . intval($id_rubrique));
113 $id_rubrique = $id_parent;
116 # spip_log(" publier_branche_rubrique($id_rubrique $id_pred");
117 return $id_pred != $id_rubrique;
121 * Dépublie si nécessaire des éléments d'une hiérarchie de rubriques
123 * Fonction à appeler lorsqu'on dépublie ou supprime quelque chose
126 * @uses depublier_rubrique_if()
127 * @todo Le nom de la fonction est trompeur, vu que la fonction remonte dans la hierarchie !
129 * @param int $id_rubrique
130 * Identifiant de la rubrique
132 * true si le statut change effectivement
134 function depublier_branche_rubrique_if($id_rubrique) {
135 $date = date('Y-m-d H:i:s'); // figer la date
137 # spip_log("depublier_branche_rubrique($id_rubrique ?");
138 $id_pred = $id_rubrique;
141 if (!depublier_rubrique_if($id_pred, $date)) {
142 return $id_pred != $id_rubrique;
144 // passer au parent si on a depublie
145 $r = sql_fetsel("id_parent", "spip_rubriques", "id_rubrique=" . intval($id_pred));
146 $id_pred = $r['id_parent'];
149 return $id_pred != $id_rubrique;
153 * Dépublier une rubrique si aucun contenu publié connu n'est trouvé dedans
155 * @pipeline_appel objet_compte_enfants
157 * @param int $id_rubrique
158 * Identifiant de la rubrique à tester
159 * @param string|null $date
160 * Date pour le calcul des éléments post-datés.
161 * null = date actuelle.
163 * true si la rubrique a été dépubliée
165 function depublier_rubrique_if($id_rubrique, $date = null) {
166 if (is_null($date)) {
167 $date = date('Y-m-d H:i:s');
169 $postdates = ($GLOBALS['meta']["post_dates"] == "non") ?
170 " AND date <= " . sql_quote($date) : '';
172 if (!$id_rubrique = intval($id_rubrique)) {
176 // verifier qu'elle existe et est bien publiee
177 $r = sql_fetsel('id_rubrique,statut', 'spip_rubriques', "id_rubrique=" . intval($id_rubrique));
178 if (!$r or $r['statut'] !== 'publie') {
182 // On met le nombre de chaque type d'enfants dans un tableau
183 // Le type de l'objet est au pluriel
185 'articles' => sql_countsel("spip_articles",
186 "id_rubrique=" . intval($id_rubrique) . " AND statut='publie'$postdates"),
187 'rubriques' => sql_countsel("spip_rubriques", "id_parent=" . intval($id_rubrique) . " AND statut='publie'"),
188 'documents' => sql_countsel("spip_documents_liens", "id_objet=" . intval($id_rubrique) . " AND objet='rubrique'")
191 // On passe le tableau des comptes dans un pipeline pour que les plugins puissent ajouter (ou retirer) des enfants
192 $compte = pipeline('objet_compte_enfants',
195 'objet' => 'rubrique',
196 'id_objet' => $id_rubrique,
197 'statut' => 'publie',
204 // S'il y a au moins un enfant de n'importe quoi, on ne dépublie pas
205 foreach ($compte as $objet => $n) {
211 sql_updateq("spip_rubriques", array("statut" => 'prepa'), "id_rubrique=" . intval($id_rubrique));
213 # spip_log("depublier_rubrique $id_pred");
219 * Recalcule des héritages de rubriques
221 * Recalcule le statut des rubriques, les langues héritées et la date
222 * du prochain article post-daté
224 * Cette fonction est appelée après importation: elle calcule les meta-donnes
225 * resultantes et remet de la coherence au cas où la base importée en manquait
227 * Cette fonction doit etre invoquée sans processus concurrent potentiel.
229 * @uses calculer_rubriques_publiees()
230 * @uses calculer_langues_utilisees()
231 * @uses calculer_prochain_postdate()
235 function calculer_rubriques() {
237 calculer_rubriques_publiees();
239 // Apres chaque (de)publication
240 // recalculer les langues utilisees sur le site
241 $langues = calculer_langues_utilisees();
242 ecrire_meta('langues_utilisees', $langues);
244 // Sauver la date de la derniere mise a jour (pour menu_rubriques)
245 ecrire_meta("date_calcul_rubriques", date("U"));
247 // on calcule la date du prochain article post-date
248 calculer_prochain_postdate();
253 * Recalcule l'ensemble des données associées à l'arborescence des rubriques
255 * Attention, faute de SQL transactionnel on travaille sur
256 * des champs temporaires afin de ne pas casser la base
257 * pendant la demi seconde de recalculs
259 * @pipeline_appel calculer_rubriques
263 function calculer_rubriques_publiees() {
265 // Mettre les compteurs a zero
266 sql_updateq('spip_rubriques', array('date_tmp' => '0000-00-00 00:00:00', 'statut_tmp' => 'prepa'));
269 // Publier et dater les rubriques qui ont un article publie
272 // Afficher les articles post-dates ?
273 $postdates = ($GLOBALS['meta']["post_dates"] == "non") ?
274 "AND A.date <= " . sql_quote(date('Y-m-d H:i:s')) : '';
277 "R.id_rubrique AS id, max(A.date) AS date_h",
278 "spip_rubriques AS R JOIN spip_articles AS A ON R.id_rubrique = A.id_rubrique",
279 "A.date>R.date_tmp AND A.statut='publie' $postdates ", "R.id_rubrique");
280 while ($row = sql_fetch($r)) {
281 sql_updateq("spip_rubriques", array("statut_tmp" => 'publie', "date_tmp" => $row['date_h']),
282 "id_rubrique=" . intval($row['id']));
285 // point d'entree pour permettre a des plugins de gerer le statut
286 // autrement (par ex: toute rubrique est publiee des sa creation)
287 // Ce pipeline fait ce qu'il veut, mais s'il touche aux statuts/dates
288 // c'est statut_tmp/date_tmp qu'il doit modifier
289 // [C'est un trigger... a renommer en trig_calculer_rubriques ?]
290 pipeline('calculer_rubriques', null);
293 // Les rubriques qui ont une rubrique fille plus recente
294 // on tourne tant que les donnees remontent vers la racine.
298 "R.id_rubrique AS id, max(SR.date_tmp) AS date_h",
299 "spip_rubriques AS R JOIN spip_rubriques AS SR ON R.id_rubrique = SR.id_parent",
300 "(SR.date_tmp>R.date_tmp OR R.statut_tmp<>'publie') AND SR.statut_tmp='publie' ", "R.id_rubrique");
301 while ($row = sql_fetch($r)) {
302 sql_updateq('spip_rubriques', array('statut_tmp' => 'publie', 'date_tmp' => $row['date_h']),
303 "id_rubrique=" . intval($row['id']));
306 } while ($continuer);
308 // Enregistrement des modifs
309 sql_update('spip_rubriques', array('date' => 'date_tmp', 'statut' => 'statut_tmp'));
313 * Recalcule les secteurs et les profondeurs des rubriques (et articles)
315 * Cherche les rubriques ayant des id_secteur ou profondeurs ne correspondant pas
316 * avec leur parent, et les met à jour. De même avec les articles et leur id_secteur
317 * On procede en iterant la profondeur de 1 en 1 pour ne pas risquer une boucle infinie sur reference circulaire
319 * @pipeline_appel trig_propager_les_secteurs
323 function propager_les_secteurs() {
325 // Toutes les rubriques racines sont de profondeur 0
326 // et fixer les id_secteur des rubriques racines
327 sql_update('spip_rubriques', array('id_secteur' => 'id_rubrique', 'profondeur' => 0), "id_parent=0");
328 // Toute rubrique non racine est de profondeur >0
329 sql_updateq('spip_rubriques', array('profondeur' => 1), "id_parent<>0 AND profondeur=0");
331 // securite : pas plus d'iteration que de rubriques dans la base
332 $maxiter = sql_countsel("spip_rubriques");
334 // reparer les rubriques qui n'ont pas l'id_secteur de leur parent
335 // on fait profondeur par profondeur
341 // Par recursivite : si toutes les rubriques de profondeur $prof sont bonnes
342 // on fixe le profondeur $prof+1
344 // Toutes les rubriques dont le parent est de profondeur $prof ont une profondeur $prof+1
345 // on teste A.profondeur > $prof+1 car :
346 // - toutes les rubriques de profondeur 0 à $prof sont bonnes
347 // - si A.profondeur = $prof+1 c'est bon
348 // - cela nous protege de la boucle infinie en cas de reference circulaire dans les rubriques
349 $maxiter2 = $maxiter;
351 and $rows = sql_allfetsel(
352 "A.id_rubrique AS id, R.id_secteur AS id_secteur, R.profondeur+1 as profondeur",
353 "spip_rubriques AS A JOIN spip_rubriques AS R ON A.id_parent = R.id_rubrique",
354 "R.profondeur=" . intval($prof) . " AND (A.id_secteur <> R.id_secteur OR A.profondeur > R.profondeur+1)",
355 "", "R.id_secteur", "0,100")) {
359 while ($row = array_shift($rows)) {
360 if ($row['id_secteur'] !== $id_secteur) {
362 sql_updateq("spip_rubriques", array("id_secteur" => $id_secteur, 'profondeur' => $prof +
1),
363 sql_in('id_rubrique', $ids));
365 $id_secteur = $row['id_secteur'];
371 sql_updateq("spip_rubriques", array("id_secteur" => $id_secteur, 'profondeur' => $prof +
1),
372 sql_in('id_rubrique', $ids));
377 // Toutes les rubriques de profondeur $prof+1 qui n'ont pas un parent de profondeur $prof sont decalees
378 $maxiter2 = $maxiter;
380 and $rows = sql_allfetsel(
383 "profondeur=" . intval($prof +
1) . " AND id_parent NOT IN (" . sql_get_select("zzz.id_rubrique",
384 "spip_rubriques AS zzz", "zzz.profondeur=" . intval($prof)) . ")", '', '', '0,100')) {
385 $rows = array_map('reset', $rows);
386 sql_updateq("spip_rubriques", array('profondeur' => $prof +
2), sql_in("id_rubrique", $rows));
389 // ici on a fini de valider $prof+1, toutes les rubriques de prondeur 0 a $prof+1 sont OK
390 // si pas de rubrique a profondeur $prof+1 pas la peine de continuer
391 // si il reste des rubriques non vues, c'est une branche morte ou reference circulaire (base foireuse)
392 // on arrete les frais
393 if (sql_countsel("spip_rubriques", "profondeur=" . intval($prof +
1))) {
397 } while ($continuer and $maxiter--);
399 // loger si la table des rubriques semble foireuse
400 // et mettre un id_secteur=0 sur ces rubriques pour eviter toute selection par les boucles
401 if (sql_countsel("spip_rubriques", "profondeur>" . intval($prof +
1))) {
402 spip_log("Les rubriques de profondeur>" . ($prof +
1) . " semblent suspectes (branches morte ou reference circulaire dans les parents)",
404 sql_update("spip_rubriques", array('id_secteur' => 0), "profondeur>" . intval($prof +
1));
407 // reparer les articles
408 $r = sql_select("A.id_article AS id, R.id_secteur AS secteur", "spip_articles AS A, spip_rubriques AS R",
409 "A.id_rubrique = R.id_rubrique AND A.id_secteur <> R.id_secteur");
411 while ($row = sql_fetch($r)) {
412 sql_update("spip_articles", array("id_secteur" => $row['secteur']), "id_article=" . intval($row['id']));
415 // avertir les plugins qui peuvent faire leur mises a jour egalement
416 pipeline('trig_propager_les_secteurs', '');
421 * Recalcule les langues héritées des sous-rubriques
423 * Cherche les langues incorrectes de sous rubriques, qui doivent hériter
424 * de la rubrique parente lorsque langue_choisie est différent de oui,
428 * true si un changement a eu lieu
430 function calculer_langues_rubriques_etape() {
431 $s = sql_select("A.id_rubrique AS id_rubrique, R.lang AS lang", "spip_rubriques AS A, spip_rubriques AS R",
432 "A.id_parent = R.id_rubrique AND A.langue_choisie != 'oui' AND R.lang<>'' AND R.lang<>A.lang");
435 while ($row = sql_fetch($s)) {
436 $id_rubrique = $row['id_rubrique'];
437 $t = sql_updateq('spip_rubriques', array('lang' => $row['lang'], 'langue_choisie' => 'non'),
438 "id_rubrique=" . intval($id_rubrique));
445 * Recalcule les langues des rubriques et articles
447 * Redéfinit la langue du site sur les rubriques sans langue spécifiée
448 * (langue_choisie différent de 'oui')
450 * Redéfinit les langues des articles sans langue spécifiée
451 * (langue_choisie différent de 'oui') en les rebasant sur la langue
452 * de la rubrique parente lorsque ce n'est pas le cas.
454 * @uses calculer_langues_rubriques_etape()
455 * @pipeline_appel trig_calculer_langues_rubriques
459 function calculer_langues_rubriques() {
461 // rubriques (recursivite)
462 sql_updateq("spip_rubriques", array("lang" => $GLOBALS['meta']['langue_site'], "langue_choisie" => 'non'),
463 "id_parent=0 AND langue_choisie != 'oui'");
464 while (calculer_langues_rubriques_etape()) {
469 $s = sql_select("A.id_article AS id_article, R.lang AS lang", "spip_articles AS A, spip_rubriques AS R",
470 "A.id_rubrique = R.id_rubrique AND A.langue_choisie != 'oui' AND (length(A.lang)=0 OR length(R.lang)>0) AND R.lang<>A.lang");
471 while ($row = sql_fetch($s)) {
472 $id_article = $row['id_article'];
473 sql_updateq('spip_articles', array("lang" => $row['lang'], 'langue_choisie' => 'non'),
474 "id_article=" . intval($id_article));
477 if ($GLOBALS['meta']['multi_rubriques'] == 'oui') {
479 $langues = calculer_langues_utilisees();
480 ecrire_meta('langues_utilisees', $langues);
483 // avertir les plugins qui peuvent faire leur mises a jour egalement
484 pipeline('trig_calculer_langues_rubriques', '');
489 * Calcule la liste des langues réellement utilisées dans le site public
491 * La recherche de langue est effectuée en recréant une boucle pour chaque
492 * objet éditorial gérant des langues de sorte que les éléments non publiés
493 * ne sont pas pris en compte.
495 * @param string $serveur
496 * Nom du connecteur à la base de données
498 * Liste des langues utilisées séparées par des virgules
500 function calculer_langues_utilisees($serveur = '') {
501 include_spip('public/interfaces');
502 include_spip('public/compiler');
503 include_spip('public/composer');
504 include_spip('public/phraser_html');
507 $langues[$GLOBALS['meta']['langue_site']] = 1;
509 include_spip('base/objets');
510 $tables = lister_tables_objets_sql();
511 $trouver_table = charger_fonction('trouver_table', 'base');
513 foreach (array_keys($tables) as $t) {
514 $desc = $trouver_table($t, $serveur);
515 // c'est une table avec des langues
517 and isset($desc['field']['lang'])
518 and isset($desc['field']['langue_choisie'])
521 $boucle = new Boucle();
522 $boucle->show
= $desc;
523 $boucle->nom
= 'calculer_langues_utilisees';
524 $boucle->id_boucle
= $desc['table_objet'];
525 $boucle->id_table
= $desc['table_objet'];
526 $boucle->sql_serveur
= $serveur;
527 $boucle->select
[] = "DISTINCT lang";
528 $boucle->from
[$desc['table_objet']] = $t;
529 $boucle->separateur
[] = ',';
530 $boucle->return = '$Pile[$SP][\'lang\']';
531 $boucle->iterateur
= 'sql';
533 $boucle->descr
['nom'] = 'objet_test_si_publie'; // eviter notice php
534 $boucle->descr
['sourcefile'] = 'internal';
536 $boucle = pipeline('pre_boucle', $boucle);
538 if (isset($desc['statut'])
542 'calculer_langues_utilisees' => $boucle,
544 // generer un nom de fonction "anonyme" unique
546 $functionname = 'f_calculer_langues_utilisees_' . $boucle->id_table
. '_' . time() . '_' . rand();
547 } while (function_exists($functionname));
548 $code = calculer_boucle('calculer_langues_utilisees', $boucles);
549 $code = '$SP=0; $command=array();$command["connect"] = $connect = "' . $serveur . '"; $Pile=array(0=>array());' . "\n" . $code;
550 $code = 'function ' . $functionname . '(){' . $code . '};$res = ' . $functionname . '();';
553 $res = explode(',', $res);
554 foreach ($res as $lang) {
558 $res = sql_select(implode(',', $boucle->select
), $boucle->from
);
559 while ($row = sql_fetch($res)) {
560 $langues[$row['lang']] = 1;
566 $langues = array_filter(array_keys($langues));
568 $langues = join(',', $langues);
569 spip_log("langues utilisees: $langues");
575 * Calcule une branche de rubriques
577 * Dépréciée, pour compatibilité
580 * @see calcul_branche_in()
582 * @param string|int|array $generation
585 function calcul_branche($generation) { return calcul_branche_in($generation); }
588 * Calcul d'une branche de rubrique
590 * Liste des id_rubrique contenues dans une rubrique donnée
592 * @see inc_calcul_branche_in_dist()
594 * @param string|int|array $id
595 * Identifiant de la, ou des rubriques noeuds
597 * Liste des identifiants séparés par des virgules,
598 * incluant les rubriques noeuds et toutes leurs descendances
600 function calcul_branche_in($id) {
601 $calcul_branche_in = charger_fonction('calcul_branche_in', 'inc');
603 return $calcul_branche_in($id);
607 * Calcul d'une hiérarchie
609 * Liste des id_rubrique contenant une rubrique donnée
611 * @see inc_calcul_hierarchie_in_dist()
612 * @param string|int|array $id
613 * Identifiant de la, ou des rubriques dont on veut obtenir les hierarchies
615 * inclure la rubrique de depart dans la hierarchie ou non
617 * Liste des identifiants séparés par des virgules,
618 * incluant les rubriques transmises et toutes leurs parentées
620 function calcul_hierarchie_in($id, $tout = true) {
621 $calcul_hierarchie_in = charger_fonction('calcul_hierarchie_in', 'inc');
623 return $calcul_hierarchie_in($id, $tout);
628 * Calcul d'une branche de rubriques
630 * Liste des id_rubrique contenues dans une rubrique donnée
631 * pour le critere {branche}
633 * Fonction surchargeable pour optimisation
635 * @see inc_calcul_hierarchie_in_dist() pour la hierarchie
637 * @param string|int|array $id
638 * Identifiant de la, ou des rubriques noeuds
640 * Liste des identifiants séparés par des virgules,
641 * incluant les rubriques noeuds et toutes leurs descendances
643 function inc_calcul_branche_in_dist($id) {
646 // normaliser $id qui a pu arriver comme un array, comme un entier, ou comme une chaine NN,NN,NN
647 if (!is_array($id)) {
648 $id = explode(',', $id);
650 $id = join(',', array_map('intval', $id));
651 if (isset($b[$id])) {
655 // Notre branche commence par la rubrique de depart
658 // On ajoute une generation (les filles de la generation precedente)
659 // jusqu'a epuisement, en se protegeant des references circulaires
661 while ($maxiter-- and $filles = sql_allfetsel(
664 sql_in('id_parent', $r) . " AND " . sql_in('id_rubrique', $r, 'NOT')
666 $r = join(',', array_map('reset', $filles));
667 $branche .= ',' . $r;
670 # securite pour ne pas plomber la conso memoire sur les sites prolifiques
671 if (strlen($branche) < 10000) {
680 * Calcul d'une hiérarchie
682 * Liste des id_rubrique contenant une rubrique donnée,
683 * contrairement à la fonction calcul_branche_in() qui calcule les
684 * rubriques contenues
686 * @see inc_calcul_branche_in_dist() pour la descendence
688 * @param string|int|array $id
689 * Identifiant de la, ou des rubriques dont on veut obtenir les hierarchies
691 * inclure la rubrique de depart dans la hierarchie ou non
693 * Liste des identifiants séparés par des virgules,
694 * incluant les rubriques transmises et toutes leurs parentées
696 function inc_calcul_hierarchie_in_dist($id, $tout = true) {
699 // normaliser $id qui a pu arriver comme un array, comme un entier, ou comme une chaine NN,NN,NN
700 if (!is_array($id)) {
701 $id = explode(',', $id);
703 $id = join(',', array_map('intval', $id));
705 if (isset($b[$id])) {
706 // Notre branche commence par la rubrique de depart si $tout=true
707 return $tout ?
(strlen($b[$id]) ?
$b[$id] . ",$id" : $id) : $b[$id];
712 // On ajoute une generation (les filles de la generation precedente)
713 // jusqu'a epuisement, en se protegeant des references circulaires
714 $ids_nouveaux_parents = $id;
716 while ($maxiter-- and $parents = sql_allfetsel(
719 sql_in('id_rubrique', $ids_nouveaux_parents) . " AND " . sql_in('id_parent', $hier, 'NOT')
721 $ids_nouveaux_parents = join(',', array_map('reset', $parents));
722 $hier = $ids_nouveaux_parents . (strlen($hier) ?
',' . $hier : '');
725 # securite pour ne pas plomber la conso memoire sur les sites prolifiques
726 if (strlen($hier) < 10000) {
730 // Notre branche commence par la rubrique de depart si $tout=true
731 $hier = $tout ?
(strlen($hier) ?
"$hier,$id" : $id) : $hier;
738 * Calcule la date du prochain article post-daté
740 * Appelée lorsqu'un (ou plusieurs) article post-daté arrive à terme
743 * @uses publier_branche_rubrique()
744 * @pipeline_appel trig_calculer_prochain_postdate
747 * true pour affecter le statut des rubriques concernées.
750 function calculer_prochain_postdate($check = false) {
751 include_spip('base/abstract_sql');
753 $postdates = ($GLOBALS['meta']["post_dates"] == "non") ?
754 "AND A.date <= " . sql_quote(date('Y-m-d H:i:s')) : '';
756 $r = sql_select("DISTINCT A.id_rubrique AS id",
757 "spip_articles AS A LEFT JOIN spip_rubriques AS R ON A.id_rubrique=R.id_rubrique",
758 "R.statut != 'publie' AND A.statut='publie'$postdates");
759 while ($row = sql_fetch($r)) {
760 publier_branche_rubrique($row['id']);
763 pipeline('trig_calculer_prochain_postdate', '');
766 $t = sql_fetsel("date", "spip_articles", "statut='publie' AND date > " . sql_quote(date('Y-m-d H:i:s')), "", "date",
771 if (!isset($GLOBALS['meta']['date_prochain_postdate'])
772 or $t <> $GLOBALS['meta']['date_prochain_postdate']
774 ecrire_meta('date_prochain_postdate', strtotime($t));
775 ecrire_meta('derniere_modif', time());
778 effacer_meta('date_prochain_postdate');
779 ecrire_meta('derniere_modif', time());
782 spip_log("prochain postdate: $t");
786 * Crée une arborescence de rubrique
788 * creer_rubrique_nommee('truc/machin/chose') va créer
789 * une rubrique truc, une sous-rubrique machin, et une sous-sous-rubrique
790 * chose, sans créer de rubrique si elle existe déjà
791 * à partir de $id_parent (par défaut, à partir de la racine)
793 * NB: cette fonction est très pratique, mais pas utilisée dans le core
794 * pour rester légère elle n'appelle pas calculer_rubriques()
796 * @param string $titre
797 * Titre des rubriques, séparés par des /
798 * @param int $id_parent
799 * Identifiant de la rubrique parente
800 * @param string $serveur
801 * Nom du connecteur à la base de données
803 * Identifiant de la rubrique la plus profonde.
805 function creer_rubrique_nommee($titre, $id_parent = 0, $serveur = '') {
807 // eclater l'arborescence demandee
808 // echapper les </multi> et autres balises fermantes html
809 $titre = preg_replace(",</([a-z][^>]*)>,ims", "<@\\1>", $titre);
810 $arbo = explode('/', preg_replace(',^/,', '', $titre));
811 include_spip('base/abstract_sql');
812 foreach ($arbo as $titre) {
813 // retablir les </multi> et autres balises fermantes html
814 $titre = preg_replace(",<@([a-z][^>]*)>,ims", "</\\1>", $titre);
815 $r = sql_getfetsel("id_rubrique", "spip_rubriques",
816 "titre = " . sql_quote($titre) . " AND id_parent=" . intval($id_parent),
817 $groupby = array(), $orderby = array(), $limit = '', $having = array(), $serveur);
821 $id_rubrique = sql_insertq('spip_rubriques', array(
823 'id_parent' => $id_parent,
825 ), $desc = array(), $serveur);
826 if ($id_parent > 0) {
827 $data = sql_fetsel("id_secteur,lang", "spip_rubriques", "id_rubrique=$id_parent",
828 $groupby = array(), $orderby = array(), $limit = '', $having = array(), $serveur);
829 $id_secteur = $data['id_secteur'];
830 $lang = $data['lang'];
832 $id_secteur = $id_rubrique;
833 $lang = $GLOBALS['meta']['langue_site'];
836 sql_updateq('spip_rubriques', array('id_secteur' => $id_secteur, "lang" => $lang),
837 "id_rubrique=" . intval($id_rubrique), $desc = '', $serveur);
840 $id_parent = $id_rubrique;
844 return intval($id_parent);