From feea64d724675a3123a4fbe43890c1189eca7b8e Mon Sep 17 00:00:00 2001 From: Cerdic <cedric@yterium.com> Date: Thu, 26 Aug 2021 17:11:00 +0200 Subject: [PATCH] Fix #4866 : tous les comptages de rang se font avec un where calcule via la fonction lien_rang_where() qui par defaut calcule un where correspondant a "tous les id_xx associes a objet-id_objet" mais dont le comportement peut etre personalise au cas par cas via une fonction perso lien_rang_where_{$table_lien}() Par ailleurs si un rang_lien est fourni lors de l'appel a objet_associer() il est directement pris en compte pour l'insertion du lien plutot que de calculer un rang automatique, inserer avec ce rang, puis modifier ensuite Enfin, dans ce dernier cas, on appelle pas lien_ordonner() immediatement apres l'insertion, mais on laisse d'abord lien_set() faire son job (a savoir eventuellement mettre le meme rang sur les autres liens id_xx/objet/id_objet identiques mais avec un role different), et finalement finir par un lien_ordonner() Additionnellement, la fonction lien_ordonner() ne presume plus du mode de comptage des rangs : - elle se repose aussi sur la fonction lien_rang_where() - elle utilise les infos des liens trouves - elle note les liens deja ordonnes pour eviter un double recomptage (notamment si on l'appelle avec plusieurs objets/id_objets qui sont tous comptes en une seule fois parce que c'est le primary qui sert de regroupement) (finger crossed) --- ecrire/action/editer_liens.php | 94 +++++++++++++++++++++++++--------- 1 file changed, 71 insertions(+), 23 deletions(-) diff --git a/ecrire/action/editer_liens.php b/ecrire/action/editer_liens.php index fb732293ef..35272ee6ea 100644 --- a/ecrire/action/editer_liens.php +++ b/ecrire/action/editer_liens.php @@ -396,14 +396,19 @@ function lien_insert($objet_source, $primary, $table_lien, $id, $objets, $qualif } if (lien_triables($table_lien)) { - $where = lien_where($primary, $id, $objet, $id_objet); - // si il y a deja un lien pour ce couple (avec un autre role?) on reprend le meme rang si non nul - if (!$rang = intval(sql_getfetsel('rang_lien', $table_lien, $where))) { - $where = lien_where($primary, '*', $objet, $id_objet); - $rang = intval(sql_getfetsel('max(rang_lien)', $table_lien, $where)); - // si aucun lien n'a de rang, on en introduit pas, on garde zero - if ($rang > 0) { - $rang = intval($rang) + 1; + if (isset($qualif['rang_lien'])) { + $rang = $qualif['rang_lien']; + } + else { + $where = lien_where($primary, $id, $objet, $id_objet); + // si il y a deja un lien pour ce couple (avec un autre role?) on reprend le meme rang si non nul + if (!$rang = intval(sql_getfetsel('rang_lien', $table_lien, $where))) { + $where = lien_rang_where($table_lien, $primary, $id, $objet, $id_objet); + $rang = intval(sql_getfetsel('max(rang_lien)', $table_lien, $where)); + // si aucun lien n'a de rang, on en introduit pas, on garde zero + if ($rang > 0) { + $rang = intval($rang) + 1; + } } } $insertions['rang_lien'] = $rang; @@ -437,8 +442,11 @@ function lien_insert($objet_source, $primary, $table_lien, $id, $objets, $qualif and !sql_getfetsel($primary, $table_lien, $where) ) { if (lien_triables($table_lien) and isset($insertions['rang_lien']) and intval($insertions['rang_lien'])) { + $where_meme_lien = lien_where($primary, $id, $objet, $id_objet); + $where_meme_lien = implode(' AND ', $where_meme_lien); // on decale les liens de rang_lien>=la valeur inseree pour faire la place - $w = lien_where($primary, '*', $objet, $id_objet, ['rang_lien>=' . intval($insertions['rang_lien']),"$primary!=" . intval($id)]); + // sauf sur le meme lien avec un role eventuellement different + $w = lien_rang_where($table_lien, $primary, $id, $objet, $id_objet, ['rang_lien>=' . intval($insertions['rang_lien']), "NOT($where_meme_lien)"]); sql_update($table_lien, ['rang_lien' => 'rang_lien+1'], $w); } @@ -462,7 +470,8 @@ function lien_insert($objet_source, $primary, $table_lien, $id, $objets, $qualif } } // si on a fait des insertions, on reordonne les liens concernes - if ($ins > 0) { + // pas la peine si $qualif['rang_lien'] etait fournie, on va passer dans lien_set a suivre et donc finir le recomptage + if ($ins > 0 and empty($qualif['rang_lien'])) { lien_ordonner($objet_source, $primary, $table_lien, $id, $objets); } @@ -483,24 +492,39 @@ function lien_ordonner($objet_source, $primary, $table_lien, $id, $objets) { return; } + $deja_reordonne = []; + foreach ($objets as $objet => $id_objets) { if (!is_array($id_objets)) { $id_objets = [$id_objets]; } foreach ($id_objets as $id_objet) { - $objet = (($objet == '*') ? $objet : objet_type($objet)); # securite - - $where = lien_where($primary, '*', $objet, $id_objet); - $liens = sql_allfetsel("$primary, id_objet, objet, rang_lien", $table_lien, $where, $primary, 'rang_lien'); - - $rangs = array_column($liens, 'rang_lien'); - if (count($rangs) and (max($rangs) > 0 or min($rangs) < 0)) { - $rang = 1; - foreach ($liens as $lien) { - $where = lien_where($primary, $lien[$primary], $objet, $id_objet, ['rang_lien!=' . intval($rang)]); - sql_updateq($table_lien, ['rang_lien' => $rang], $where); - $rang++; + if (empty($deja_reordonne[$id][$objet][$id_objet])) { + $objet = (($objet == '*') ? $objet : objet_type($objet)); # securite + + $where = lien_rang_where($table_lien, $primary, $id, $objet, $id_objet); + $liens = sql_allfetsel("$primary, id_objet, objet, rang_lien", $table_lien, $where, '', 'rang_lien'); + + $rangs = array_column($liens, 'rang_lien'); + if (count($rangs) and (max($rangs) > 0 or min($rangs) < 0)) { + $rang = 1; + foreach ($liens as $lien) { + if (empty($deja_reordonne[$lien[$primary]][$lien['objet']][$lien['id_objet']])) { + $where = lien_where($primary, $lien[$primary], $lien['objet'], $lien['id_objet'], ['rang_lien!=' . intval($rang)]); + sql_updateq($table_lien, ['rang_lien' => $rang], $where); + + if (empty($deja_reordonne[$lien[$primary]])) { + $deja_reordonne[$lien[$primary]] = []; + } + if (empty($deja_reordonne[$lien[$primary]][$lien['objet']])) { + $deja_reordonne[$lien[$primary]][$lien['objet']] = []; + } + $deja_reordonne[$lien[$primary]][$lien['objet']][$lien['id_objet']] = $rang; + + $rang++; + } + } } } } @@ -590,6 +614,27 @@ function lien_where($primary, $id_source, $objet, $id_objet, $cond = []) { return $where; } +/** + * Fabriquer la condition where pour compter les rangs + * @param string $table_lien + * @param string $primary + * @param int|string|array $id_source + * @param string $objet + * @param int|string|array $id_objet + * @param array $cond + * @return array Liste des conditions + */ +function lien_rang_where($table_lien, $primary, $id_source, $objet, $id_objet, $cond = []) { + + // si on veut compter les rangs autrement que le core ne le fait par defaut, fournir le where adhoc + if (function_exists($f = 'lien_rang_where_' . $table_lien)) { + return $f($primary, $id_source, $objet, $id_objet, $cond); + } + + // par defaut c'est un rang compté pour tous les id_source d'un couple objet-id_objet + return lien_where($primary, '*', $objet, $id_objet, $cond); +} + /** * Sous fonction suppression * qui traite les liens pour un objet source dont la clé primaire @@ -864,7 +909,10 @@ function lien_set($objet_source, $primary, $table_lien, $id, $objets, $qualif) { if (lien_triables($table_lien) and isset($qualif['rang_lien'])) { if (intval($qualif['rang_lien'])) { // on decale les liens de rang_lien>=la valeur inseree pour faire la place - $w = lien_where($primary, '*', $objet, $id_objet, ['rang_lien>=' . intval($qualif['rang_lien']),"$primary!=" . intval($id)]); + // sauf sur le meme lien avec un role eventuellement different + $where_meme_lien = lien_where($primary, $id, $objet, $id_objet); + $where_meme_lien = implode(' AND ', $where_meme_lien); + $w = lien_rang_where($table_lien, $primary, $id, $objet, $id_objet, ['rang_lien>=' . intval($qualif['rang_lien']), "NOT($where_meme_lien)"]); sql_update($table_lien, ['rang_lien' => 'rang_lien+1'], $w); } // tous les liens de même rôle recoivent le rang indiqué aussi -- GitLab