diff --git a/ecrire/action/editer_liens.php b/ecrire/action/editer_liens.php index 3b33fbd61c7c0b3e0c827aaad8fc29e09a461b06..967dd17c917c93ba8c6c36abc34d3c2aecad575f 100644 --- a/ecrire/action/editer_liens.php +++ b/ecrire/action/editer_liens.php @@ -374,7 +374,7 @@ function lien_insert($objet_source, $primary, $table_lien, $id, $objets, $qualif roles_trouver_dans_qualif($objet_source, $objet, $qualif); foreach ($id_objets as $id_objet) { - $objet = ($objet == '*') ? $objet : objet_type($objet); # securite + $objet = (($objet == '*') ? $objet : objet_type($objet)); # securite $insertions = array( 'id_objet' => $id_objet, @@ -387,6 +387,21 @@ function lien_insert($objet_source, $primary, $table_lien, $id, $objets, $qualif $colonne_role => $role ); } + + 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; + } + } + $insertions['rang_lien'] = $rang; + } + $args = array( 'table_lien' => $table_lien, 'objet_source' => $objet_source, @@ -413,6 +428,12 @@ 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'])) { + // on decale les liens de rang_lien>=la valeur inseree pour faire la place + $w = lien_where($primary, '*', $objet, $id_objet, array('rang_lien>='.intval($insertions['rang_lien']),"$primary!=".intval($id))); + sql_update($table_lien, array('rang_lien'=>'rang_lien+1'), $w); + } + $e = sql_insertq($table_lien, $insertions); if ($e !== false) { $ins++; @@ -431,10 +452,75 @@ 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) { + lien_ordonner($objet_source, $primary, $table_lien, $id, $objets); + } return ($echec ? false : $ins); } + +/** + * Reordonner les liens sur lesquels on est intervenus + * @param string $objet_source + * @param string $primary + * @param string $table_lien + * @param int $id + * @param array|string $objets + */ +function lien_ordonner($objet_source, $primary, $table_lien, $id, $objets) { + if (!lien_triables($table_lien)) { + return; + } + + foreach ($objets as $objet => $id_objets) { + if (!is_array($id_objets)) { + $id_objets = array($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 (max($rangs)>0 or min($rangs)<0) { + $rang = 1; + foreach ($liens as $lien) { + $where = lien_where($primary, $lien[$primary], $objet, $id_objet, array('rang_lien!='.intval($rang))); + sql_updateq($table_lien, array('rang_lien' => $rang), $where); + $rang++; + } + } + } + } +} + + +/** + * Une table de lien est-elle triable ? + * elle doit disposer d'un champ rang_lien pour cela + * @param $table_lien + * @return mixed + */ +function lien_triables($table_lien) { + static $triables = array(); + if (!isset($triables[$table_lien])) { + $trouver_table = charger_fonction('trouver_table', 'base'); + $desc = $trouver_table($table_lien); + if ($desc and isset($desc['field']['rang_lien'])) { + $triables[$table_lien] = true; + } + else { + $triables[$table_lien] = false; + } + } + return $triables[$table_lien]; +} + + /** * Fabriquer la condition where en tenant compte des jokers * * @@ -591,6 +677,10 @@ function lien_delete($objet_source, $primary, $table_lien, $id, $objets, $cond = } } } + // si on a supprime des liens, on reordonne les liens concernes + if ($dels) { + lien_ordonner($objet_source, $primary, $table_lien, $id, $objets); + } pipeline('trig_supprimer_objets_lies', $retire); @@ -700,6 +790,7 @@ function lien_optimise($objet_source, $primary, $table_lien, $id, $objets) { function lien_set($objet_source, $primary, $table_lien, $id, $objets, $qualif) { $echec = null; $ok = 0; + $reordonner = false; if (!$qualif) { return false; } @@ -743,6 +834,13 @@ function lien_set($objet_source, $primary, $table_lien, $id, $objets, $qualif) { ); $args['id_objet'] = $id_objet; + if (lien_triables($table_lien) and isset($qualif['rang_lien']) and 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, array('rang_lien>='.intval($qualif['rang_lien']),"$primary!=".intval($id))); + sql_update($table_lien, array('rang_lien'=>'rang_lien+1'), $w); + $reordonner = true; + } + $where = lien_where($primary, $id, $objet, $id_objet, $cond); $e = sql_updateq($table_lien, $qualif, $where); @@ -760,6 +858,10 @@ function lien_set($objet_source, $primary, $table_lien, $id, $objets, $qualif) { } } } + // si on a fait des modif de rang, on reordonne les liens concernes + if ($reordonner) { + lien_ordonner($objet_source, $primary, $table_lien, $id, $objets); + } return ($echec ? false : $ok); } diff --git a/ecrire/inc/filtres_ecrire.php b/ecrire/inc/filtres_ecrire.php index d13df87f52fe739a8c636e9fafea11f72aebc9cd..72379adc24b3b1b826134052950c64a760d637ab 100644 --- a/ecrire/inc/filtres_ecrire.php +++ b/ecrire/inc/filtres_ecrire.php @@ -554,6 +554,9 @@ function afficher_plus_info($lien, $titre = "+", $titre_lien = "") { } } + + + /** * Lister les id objet_source associés à l'objet id_objet * via la table de lien objet_lien @@ -567,17 +570,99 @@ function afficher_plus_info($lien, $titre = "+", $titre_lien = "") { * @return array */ function lister_objets_lies($objet_source, $objet, $id_objet, $objet_lien) { - include_spip('action/editer_liens'); - $l = array(); - // quand $objet == $objet_lien == $objet_source on reste sur le cas par defaut de $objet_lien == $objet_source - if ($objet_lien == $objet and $objet_lien !== $objet_source) { - $res = objet_trouver_liens(array($objet => $id_objet), array($objet_source => '*')); - } else { - $res = objet_trouver_liens(array($objet_source => '*'), array($objet => $id_objet)); + $res = lister_objets_liens($objet_source, $objet, $id_objet, $objet_lien); + if (count($res)) { + $r = reset($res); + if (isset($r['rang_lien'])) { + $l = array_column($res, 'rang_lien', $objet_source); + asort($l); + $l = array_keys($l); + } + else { + $l = array_column($res, $objet_source); + } } - while ($row = array_shift($res)) { - $l[] = $row[$objet_source]; + return $l; +} + + +/** + * Retrouver le rang du lien entre un objet source et un obet lie + * utilisable en direct dans un formulaire d'edition des liens, mais #RANG doit faire le travail automatiquement + * [(#ENV{objet_source}|rang_lien{#ID_AUTEUR,#ENV{objet},#ENV{id_objet},#ENV{_objet_lien}})] + * + * @param $objet_source + * @param $ids + * @param $objet_lie + * @param $idl + * @param $objet_lien + * @return string + */ +function retrouver_rang_lien($objet_source, $ids, $objet_lie, $idl, $objet_lien){ + $res = lister_objets_liens($objet_source, $objet_lie, $idl, $objet_lien); + $res = array_column($res, 'rang_lien', $objet_source); + + return (isset($res[$ids]) ? $res[$ids] : ''); +} + + +/** + * Lister les liens en le memoizant dans une static + * pour utilisation commune par lister_objets_lies et retrouver_rang_lien dans un formuluaire d'edition de liens + * (evite de multiplier les requetes) + * + * @param $objet_source + * @param $objet + * @param $id_objet + * @param $objet_lien + * @return mixed + * @private + */ +function lister_objets_liens($objet_source, $objet, $id_objet, $objet_lien) { + static $liens = array(); + if (!isset($liens["$objet_source-$objet-$id_objet-$objet_lien"])) { + include_spip('action/editer_liens'); + // quand $objet == $objet_lien == $objet_source on reste sur le cas par defaut de $objet_lien == $objet_source + if ($objet_lien == $objet and $objet_lien !== $objet_source) { + $res = objet_trouver_liens(array($objet => $id_objet), array($objet_source => '*')); + } else { + $res = objet_trouver_liens(array($objet_source => '*'), array($objet => $id_objet)); + } + + $liens["$objet_source-$objet-$id_objet-$objet_lien"] = $res; } + return $liens["$objet_source-$objet-$id_objet-$objet_lien"]; +} - return $l; +/** + * Calculer la balise #RANG + * quand ce n'est pas un champ rang : + * peut etre le num titre, le champ rang_lien ou le rang du lien en edition des liens, a retrouver avec les infos du formulaire + * @param $titre + * @param $rang_lien + * @param $objet_source + * @param $id + * @param $env + * @return int|string + */ +function calculer_rang_smart($titre, $rang_lien, $objet_source, $id, $env) { + // Cas du #RANG utilisé dans #FORMULAIRE_EDITER_LIENS -> attraper le rang du lien + if (isset($env['form']) and $env['form'] + and isset($env['_objet_lien']) and $env['_objet_lien'] + and (function_exists('lien_triables') or include_spip('action/editer_liens')) + and $r = objet_associable($env['_objet_lien']) + and list($p, $table_lien) = $r + and lien_triables($table_lien) + and isset($env['objet']) and $env['objet'] + and isset($env['id_objet']) and $env['id_objet'] + and $objet_source + and $id = intval($id) + ) { + $rang = retrouver_rang_lien($objet_source, $id, $env['objet'], $env['id_objet'], $env['_objet_lien']); + return ($rang ? $rang : ''); + } + elseif(!is_null($rang_lien) and strlen($rang_lien)) { + return $rang_lien; + } + return recuperer_numero($titre); } diff --git a/ecrire/public/balises.php b/ecrire/public/balises.php index 3a19baa2594b84feb728efd6341dafabe5896598..e160eaf4c8b24a74432f126e757956a970df2efa 100644 --- a/ecrire/public/balises.php +++ b/ecrire/public/balises.php @@ -972,6 +972,8 @@ function balise_RANG_dist($p) { // si pas trouve de champ sql rang : if (!$_rang or $_rang == "''") { $boucle = &$p->boucles[$b]; + + // on gere le cas ou #RANG est une extraction du numero dans le titre $trouver_table = charger_fonction('trouver_table', 'base'); $desc = $trouver_table($boucle->id_table); $_titre = ''; # où extraire le numero ? @@ -998,13 +1000,29 @@ function balise_RANG_dist($p) { } } } - + // si on n'a rien trouvé, on utilise le champ titre classique if (!$_titre) { $_titre = champ_sql('titre', $p); } - - $_rang = "recuperer_numero($_titre)"; + + // ca peut etre un rang sur le lien + // (mais pareil, uniquement sur la boucle immediatement englobante uniquement) + $_rang_lien = champ_sql('rang_lien', $p, '', false); + + // et on recupere aussi les infos de liaison si on est en train d'editer les liens justement + // cas des formulaires xxx_lies utilises par #FORMULAIRE_EDITER_LIENS + $type_boucle = $boucle->type_requete; + $objet = objet_type($type_boucle); + $id_table_objet = id_table_objet($type_boucle); + $_primary = champ_sql($id_table_objet, $p, '', false); + $_env = '$Pile[0]'; + + if (!$_titre) {$_titre = "''";} + if (!$_rang_lien) {$_rang_lien = "''";} + if (!$_primary) {$_primary = "''";} + $_rang = "calculer_rang_smart($_titre, $_rang_lien, '$objet', $_primary, $_env)"; + } $p->code = $_rang; diff --git a/prive/formulaires/editer_liens.php b/prive/formulaires/editer_liens.php index e9ade964ea8b05ee51e691569ec5fa2688ca6145..334e8be838f2da2d6d1facc05e206e6b3182b422 100644 --- a/prive/formulaires/editer_liens.php +++ b/prive/formulaires/editer_liens.php @@ -142,6 +142,8 @@ function formulaires_editer_liens_charger_dist($a, $b, $c, $options = array()) { 'ajouter_lien' => '', 'supprimer_lien' => '', 'qualifier_lien' => '', + 'ordonner_lien' => '', + 'desordonner_liens' => '', '_roles' => $roles, # description des roles '_oups' => _request('_oups'), 'editable' => $editable, @@ -160,6 +162,8 @@ function formulaires_editer_liens_charger_dist($a, $b, $c, $options = array()) { * - ajouter_lien et supprimer_lien * - remplacer_lien * - qualifier_lien + * - ordonner_lien + * - desordonner_liens * * Les deux premières peuvent être de trois formes différentes : * ajouter_lien[]="objet1-id1-objet2-id2" @@ -177,6 +181,11 @@ function formulaires_editer_liens_charger_dist($a, $b, $c, $options = array()) { * qualifier_lien[objet1-id1-objet2-id2][valeur] = array("truc", "chose") * produira 2 liens chacun avec array("role"=>"role1","valeur"=>"truc") et array("role"=>"autre_role","valeur"=>"chose") * + * ordonner_lien doit être de la forme, et sert pour trier les liens + * ordonner_lien[objet1-id1-objet2-id2] = nouveau_rang + * + * desordonner_liens n'a pas de forme precise, il doit simplement estre non nul/non vide + * * @param string $a * @param string|int $b * @param int|string $c @@ -233,6 +242,12 @@ function formulaires_editer_liens_traiter_dist($a, $b, $c, $options = array()) { $supprimer = _request('supprimer_lien'); $ajouter = _request('ajouter_lien'); + $ordonner = _request('ordonner_lien'); + + if (_request('desordonner_liens')) { + include_spip('action/editer_liens'); + objet_qualifier_liens(array($objet_lien => '*'), array($objet => $id_objet), array('rang_lien' => 0)); + } // il est possible de preciser dans une seule variable un remplacement : // remplacer_lien[old][new] @@ -313,6 +328,24 @@ function formulaires_editer_liens_traiter_dist($a, $b, $c, $options = array()) { set_request('_oups'); } } + + if ($ordonner) { + include_spip('action/editer_liens'); + foreach ($ordonner as $k => $rang_lien) { + if ($lien = lien_verifier_action($k, '')) { + list($objet1, $ids, $objet2, $idl) = explode('-', $lien); + $qualif = array('rang_lien' => $rang_lien); + + if ($objet_lien == $objet1) { + objet_qualifier_liens(array($objet1 => $ids), array($objet2 => $idl), $qualif); + } else { + objet_qualifier_liens(array($objet2 => $idl), array($objet1 => $ids), $qualif); + } + set_request('id_lien_ajoute', $ids); + set_request('_oups'); + } + } + } }