You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

324 lines
10 KiB

  1. <?php
  2. /***************************************************************************\
  3. * SPIP, Systeme de publication pour l'internet *
  4. * *
  5. * Copyright (c) 2001-2020 *
  6. * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
  7. * *
  8. * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
  9. * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
  10. \***************************************************************************/
  11. if (!defined("_ECRIRE_INC_VERSION")) {
  12. return;
  13. }
  14. //
  15. // <BOUCLE(FORUMS)>
  16. //
  17. // https://code.spip.net/@boucle_FORUMS_dist
  18. function boucle_FORUMS_dist($id_boucle, &$boucles) {
  19. $boucle = &$boucles[$id_boucle];
  20. $id_table = $boucle->id_table;
  21. // Par defaut, selectionner uniquement les forums sans mere
  22. // Les criteres {tout} et {plat} inversent ce choix
  23. // de meme qu'un critere sur {id_forum} ou {id_parent}
  24. if (!isset($boucle->modificateur['tout'])
  25. and !isset($boucle->modificateur['plat'])
  26. and !isset($boucle->modificateur['criteres']['id_forum'])
  27. and !isset($boucle->modificateur['criteres']['id_parent'])
  28. ) {
  29. array_unshift($boucle->where, array("'='", "'$id_table." . "id_parent'", 0));
  30. }
  31. return calculer_boucle($id_boucle, $boucles);
  32. }
  33. // {meme_parent}
  34. // https://www.spip.net/@meme_parent
  35. // https://code.spip.net/@critere_meme_parent_dist
  36. function critere_FORUMS_meme_parent_dist($idb, &$boucles, $crit) {
  37. global $exceptions_des_tables;
  38. $boucle = &$boucles[$idb];
  39. $arg = kwote(calculer_argument_precedent($idb, 'id_parent', $boucles));
  40. $id_parent = isset($exceptions_des_tables[$boucle->id_table]['id_parent']) ?
  41. $exceptions_des_tables[$boucle->id_table]['id_parent'] :
  42. 'id_parent';
  43. $mparent = $boucle->id_table . '.' . $id_parent;
  44. $boucle->where[] = array("'='", "'$mparent'", $arg);
  45. $boucle->where[] = array("'>'", "'$mparent'", 0);
  46. $boucle->modificateur['plat'] = true;
  47. }
  48. /**
  49. * Compile le critère `{compter_reponses}`
  50. *
  51. * Ce critère compte le nombre de messages en réponse à un message donné.
  52. * Il stocke l’information dans le champ `nombre_reponses`.
  53. * On peut le récupérer en squelette avec `#FORUM_NOMBRE_REPONSES`
  54. *
  55. * Le calcul se fait par une jointure LEFT :
  56. * les éléments avec aucune réponse sont retournés.
  57. *
  58. * On peut passer un opérateur optionnel tel que :
  59. * `{compter_reponses nombre_reponses = 0}`
  60. * Ce qui fera un test sur le résultat du calcul (HAVING).
  61. *
  62. * @example
  63. * ```
  64. * <BOUCLE_(FORUMS){!par date_thread}{compter_reponses}> #FORUM_NOMBRE_REPONSES ...
  65. * <BOUCLE_(FORUMS){compter_reponses}{!par nombre_reponse}> les plus commentés ...
  66. * <BOUCLE_(FORUMS){!par date_thread}{compter_reponses nombre_reponse = 0}> sans réponse ...
  67. * <BOUCLE_(FORUMS){!par date_thread}{compter_reponses nombre_reponse > 10}> + de 10 réponses ...
  68. * ```
  69. *
  70. * @param string $idb Identifiant de la boucle
  71. * @param array $boucles AST du squelette
  72. * @param Critere $crit Paramètres du critère dans cette boucle
  73. * @return void
  74. */
  75. function critere_FORUMS_compter_reponses($idb, &$boucles, $crit) {
  76. $boucle = &$boucles[$idb];
  77. $id_parent = isset($GLOBALS['exceptions_des_tables'][$boucle->id_table]['id_parent']) ?
  78. $GLOBALS['exceptions_des_tables'][$boucle->id_table]['id_parent'] :
  79. 'id_parent';
  80. $id_table = $boucle->id_table;
  81. $boucle->from['fils'] = 'spip_forum';
  82. $boucle->from_type['fils'] = 'left';
  83. $boucle->join["fils"] = array("'$id_table'", "'$id_parent'", "'id_forum'", "'fils.statut='.sql_quote('publie')");
  84. $boucle->select[]= 'COUNT(fils.id_forum) AS nombre_reponses';
  85. // Gestion du having
  86. if (count($crit->param)) {
  87. $champ = $crit->param[0][0]->texte;
  88. if (preg_match(',^(\w+)\s*([<>=])\s*([0-9]+)$,', $champ, $r)) {
  89. $champ = $r[1];
  90. $op = $r[2];
  91. $op_val = $r[3];
  92. $boucle->having[]= array("'".$op."'", "'" . $champ . "'", $op_val);
  93. }
  94. }
  95. }
  96. /**
  97. * Retourne le nombre de vote sur un objet de SPIP.
  98. *
  99. * Nécessite le critere `{compter_reponses}` sur la boucle FORUMS
  100. *
  101. * `<BOUCLE_(FORUMS){compter_reponses}>#FORUM_NOMBRE_REPONSES ...`
  102. *
  103. * @param Champ $p
  104. * @return Champ
  105. */
  106. function balise_FORUM_NOMBRE_REPONSES_dist($p) {
  107. return rindex_pile($p, 'nombre_reponses', 'compter_reponses');
  108. }
  109. /**
  110. * Faute de copie du champ id_secteur dans la table des forums,
  111. * faut le retrouver par jointure
  112. * Pour chaque Row il faudrait tester si le forum est
  113. * d'article, de breve, de rubrique, ou de syndication.
  114. * Pour le moment on ne traite que les articles,
  115. * les 3 autres cas ne marcheront donc pas: ca ferait 4 jointures
  116. * qu'il faut traiter optimalement ou alors pas du tout.
  117. *
  118. * @param string $idb
  119. * @param object $boucles
  120. * @param $val
  121. * @param $crit
  122. * @return mixed|string
  123. */
  124. function public_critere_secteur_forums_dist($idb, &$boucles, $val, $crit) {
  125. return calculer_critere_externe_init($boucles[$idb], array('spip_articles'), 'id_secteur', $boucles[$idb]->show,
  126. $crit->cond, true);
  127. }
  128. //
  129. // Parametres de reponse a un forum
  130. //
  131. // Cette balise peut etre executee en dehors de toute boucle,
  132. // par exemple en tete de inc-forums.html ; impossible donc de
  133. // savoir a quel objet elle va s'appliquer, ca dependra du contexte
  134. //
  135. // https://code.spip.net/@balise_PARAMETRES_FORUM_dist
  136. function balise_PARAMETRES_FORUM_dist($p) {
  137. // s'il y a un id_article dans le contexte, regarder le statut
  138. // accepter_forum de cet article
  139. $_id_article = champ_sql('id_article', $p);
  140. $p->code = '
  141. // refus des forums ?
  142. (quete_accepter_forum(' . $_id_article . ')=="non" OR
  143. ($GLOBALS["meta"]["forums_publics"] == "non"
  144. AND quete_accepter_forum(' . $_id_article . ') == ""))
  145. ? "" : // sinon:
  146. ';
  147. // pas de calculs superflus si le site est monolingue
  148. $lang = strpos($GLOBALS['meta']['langues_utilisees'], ',');
  149. // si on est dans une boucle de forums, c'est une reponse
  150. if ($p->type_requete == 'forums') {
  151. $_id_reponse = champ_sql('id_forum', $p);
  152. } else {
  153. $_id_reponse = "null";
  154. }
  155. // objet et id_objet principaux sont a determiner
  156. // dans le contexte ; on demande en tout etat de cause
  157. // a la boucle mere de reserver son id_primary
  158. if ($p->id_boucle
  159. and isset($p->boucles[$p->id_boucle])
  160. and $primary = $p->boucles[$p->id_boucle]->primary
  161. ) {
  162. $_type = _q($p->boucles[$p->id_boucle]->type_requete);
  163. $_primary = champ_sql($primary, $p);
  164. } else {
  165. $_type = "null";
  166. $_primary = "null";
  167. }
  168. // le code de base des parametres
  169. $c = 'calcul_parametres_forum($Pile[0],'
  170. . $_id_reponse . ',' . $_type . ',' . $_primary . ')';
  171. // ajouter la lang, eventuellement donnee par le contexte
  172. if ($lang) {
  173. $_lang = champ_sql('lang', $p);
  174. $c = "lang_parametres_forum($c,$_lang)";
  175. }
  176. // Syntaxe [(#PARAMETRES_FORUM{#SELF})] pour fixer le retour du forum
  177. # note : ce bloc qui sert a recuperer des arguments calcules pourrait
  178. # porter un nom et faire partie de l'API.
  179. $retour = interprete_argument_balise(1, $p);
  180. if ($retour === null) {
  181. $retour = "''";
  182. }
  183. // Attention un eventuel &retour=xxx dans l'URL est prioritaire
  184. $c .= '.
  185. (($lien = (_request("retour") ? _request("retour") : str_replace("&amp;", "&", ' . $retour . '))) ? "&retour=".rawurlencode($lien) : "")';
  186. $c = '(' . $c . ')';
  187. // Ajouter le code d'invalideur specifique a cette balise
  188. include_spip('inc/invalideur');
  189. if ($i = charger_fonction('code_invalideur_forums', '', true)) {
  190. $p->code .= $i($p, $c);
  191. } else {
  192. $p->code .= $c;
  193. }
  194. $p->interdire_scripts = false;
  195. return $p;
  196. }
  197. // Cette fonction est appellee avec le contexte + trois parametres optionnels :
  198. // 1. $reponse = l'id_forum auquel on repond
  199. // 2. $type = le type de boucle dans lequel on se trouve, le cas echeant
  200. // 3. $primary = l'id_objet de la boucle dans laquelle on se trouve
  201. // elle doit renvoyer '', 'id_article=5' ou 'id_article=5&id_forum=12'
  202. // selon les cas
  203. function calcul_parametres_forum(&$env, $reponse, $type, $primary) {
  204. // si c'est une reponse, on peut esperer que (objet,id_objet) sont dans
  205. // la boucle mere, mais il est possible que non (forums imbriques etc)
  206. // dans ce cas on va chercher dans la base.
  207. if ($id_parent = intval($reponse)) {
  208. if ($type
  209. and $type != 'forums'
  210. and $primary
  211. ) {
  212. $forum = array('objet' => $type, 'id_objet' => $primary);
  213. } else {
  214. $forum = sql_fetsel('objet, id_objet', 'spip_forum', 'id_forum=' . $id_parent);
  215. }
  216. if ($forum) {
  217. return id_table_objet($forum['objet']) . '=' . $forum['id_objet']
  218. . '&id_forum=' . $id_parent;
  219. } else {
  220. return '';
  221. }
  222. }
  223. // Ce n'est pas une reponse, on prend la boucle mere
  224. if ($type and $primary) {
  225. return id_table_objet($type) . '=' . intval($primary);
  226. }
  227. // dernier recours, on regarde pour chacun des objets forumables
  228. // ce que nous propose le contexte #ENV
  229. foreach ($env as $k => $v) {
  230. if (preg_match(',^id_([a-z_]+)$,S', $k)
  231. and $id = intval($v)
  232. ) {
  233. return id_table_objet($k) . '=' . $v;
  234. }
  235. }
  236. return '';
  237. }
  238. # retourne le champ 'accepter_forum' d'un article
  239. function quete_accepter_forum($id_article) {
  240. // si la fonction est appelee en dehors d'une boucle
  241. // article (forum de breves), $id_article est nul
  242. // mais il faut neanmoins accepter l'affichage du forum
  243. // d'ou le 0=>'' (et pas 0=>'non').
  244. static $cache = array(0 => '');
  245. $id_article = intval($id_article);
  246. if (isset($cache[$id_article])) {
  247. return $cache[$id_article];
  248. }
  249. return $cache[$id_article] = sql_getfetsel('accepter_forum', 'spip_articles', "id_article=$id_article");
  250. }
  251. // Ajouter "&lang=..." si la langue du forum n'est pas celle du site.
  252. // Si le 2e parametre n'est pas une chaine, c'est qu'on n'a pas pu
  253. // determiner la table a la compil, on le fait maintenant.
  254. // Il faudrait encore completer: on ne connait pas la langue
  255. // pour une boucle forum sans id_article ou id_rubrique donne par le contexte
  256. // et c'est signale par un message d'erreur abscons: "table inconnue forum".
  257. //
  258. // https://code.spip.net/@lang_parametres_forum
  259. function lang_parametres_forum($qs, $lang) {
  260. if (is_array($lang) and preg_match(',id_([a-z_]+)=([0-9]+),', $qs, $r)) {
  261. $id = 'id_' . $r[1];
  262. if ($t = $lang[$id]) {
  263. $lang = sql_getfetsel('lang', $t, "$id=" . $r[2]);
  264. }
  265. }
  266. // Si ce n'est pas la meme que celle du site, l'ajouter aux parametres
  267. if ($lang and $lang <> $GLOBALS['meta']['langue_site']) {
  268. return $qs . "&lang=" . $lang;
  269. }
  270. return $qs;
  271. }
  272. // Pour que le compilo ajoute un invalideur a la balise #PARAMETRES_FORUM
  273. // Noter l'invalideur de la page contenant ces parametres,
  274. // en cas de premier post sur le forum
  275. // https://code.spip.net/@code_invalideur_forums
  276. function code_invalideur_forums_dist($p, $code) {
  277. return $code;
  278. }