3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
6 * Copyright (c) 2001-2019 *
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 * API d'édition de liens
16 * Cette API gère la création, modification et suppressions de liens
17 * entre deux objets éditoriaux par l'intermédiaire de tables de liaison
18 * tel que spip_xx_liens.
20 * L'unicité est assurée dans les fonctions sur le trio (id_x, objet, id_objet)
21 * par défaut, ce qui correspond à la déclaration de clé primaire.
23 * Des rôles peuvent être déclarés pour des liaisons. À ce moment là,
24 * une colonne spécifique doit être présente dans la table de liens
25 * et l'unicité est alors assurée sur le quatuor (id_x, objet, id_objet, role)
26 * et la clé primaire adaptée en conséquence.
28 * @package SPIP\Core\Liens\API
31 if (!defined('_ECRIRE_INC_VERSION')) {
35 // charger la gestion les rôles sur les objets
36 include_spip('inc/roles');
40 * Teste l'existence de la table de liaison xxx_liens d'un objet
43 * @param string $objet
46 * - false si l'objet n'est pas associable.
47 * - array(clé primaire, nom de la table de lien) si associable
49 function objet_associable($objet) {
50 $trouver_table = charger_fonction('trouver_table', 'base');
51 $table_sql = table_objet_sql($objet);
54 if ($primary = id_table_objet($objet)
55 and $trouver_table($l = $table_sql . "_liens")
56 and !preg_match(',[^\w],', $primary)
57 and !preg_match(',[^\w],', $l)
59 return array($primary, $l);
62 spip_log("Objet $objet non associable : ne dispose pas d'une cle primaire $primary OU d'une table liens $l");
68 * Associer un ou des objets à des objets listés
70 * `$objets_source` et `$objets_lies` sont de la forme
71 * `array($objet=>$id_objets,...)`
72 * `$id_objets` peut lui même être un scalaire ou un tableau pour une liste d'objets du même type
73 * ou de la forme `array("NOT", $id_objets)` pour une sélection par exclusion
75 * Les objets sources sont les pivots qui portent les liens
76 * et pour lesquels une table spip_xxx_liens existe
77 * (auteurs, documents, mots)
79 * On peut passer optionnellement une qualification du (des) lien(s) qui sera
80 * alors appliquée dans la foulée.
81 * En cas de lot de liens, c'est la même qualification qui est appliquée a tous
84 * @param array $objets_source
85 * @param array|string $objets_lies
86 * @param array $qualif
89 function objet_associer($objets_source, $objets_lies, $qualif = null) {
90 $modifs = objet_traiter_liaisons('lien_insert', $objets_source, $objets_lies, $qualif);
93 objet_qualifier_liens($objets_source, $objets_lies, $qualif);
96 return $modifs; // pas d'erreur
101 * Dissocier un (ou des) objet(s) des objets listés
103 * `$objets_source` et `$objets_lies` sont de la forme
104 * `array($objet=>$id_objets,...)`
105 * `$id_objets` peut lui-même être un scalaire ou un tableau pour une liste d'objets du même type
107 * Les objets sources sont les pivots qui portent les liens
108 * et pour lesquels une table spip_xxx_liens existe
109 * (auteurs, documents, mots)
111 * un * pour $objet, $id_objet permet de traiter par lot
112 * seul le type de l'objet source ne peut pas accepter de joker et doit etre explicite
114 * S'il y a des rôles possibles entre les 2 objets, et qu'aucune condition
115 * sur la colonne du rôle n'est transmise, on ne supprime que les liens
116 * avec le rôle par défaut. Si on veut supprimer tous les rôles,
117 * il faut spécifier $cond => array('role' => '*')
120 * @param array $objets_source
121 * @param array|string $objets_lies
122 * @param array|null $cond
123 * Condition du where supplémentaires
125 * À l'exception de l'index 'role' qui permet de sélectionner un rôle
126 * ou tous les rôles (*), en s'affranchissant du vrai nom de la colonne.
129 function objet_dissocier($objets_source, $objets_lies, $cond = null) {
130 return objet_traiter_liaisons('lien_delete', $objets_source, $objets_lies, $cond);
135 * Qualifier le lien entre un (ou des) objet(s) et des objets listés
137 * $objets_source et $objets sont de la forme
138 * array($objet=>$id_objets,...)
139 * $id_objets peut lui meme etre un scalaire ou un tableau pour une liste d'objets du meme type
141 * Les objets sources sont les pivots qui portent les liens
142 * et pour lesquels une table spip_xxx_liens existe
143 * (auteurs, documents, mots)
145 * un * pour $objet,$id_objet permet de traiter par lot
146 * seul le type de l'objet source ne peut pas accepter de joker et doit etre explicite
149 * @param array $objets_source
150 * @param array|string $objets_lies
151 * @param array $qualif
154 function objet_qualifier_liens($objets_source, $objets_lies, $qualif) {
155 return objet_traiter_liaisons('lien_set', $objets_source, $objets_lies, $qualif);
160 * Trouver les liens entre objets
162 * $objets_source et $objets sont de la forme
163 * array($objet=>$id_objets,...)
164 * $id_objets peut lui meme etre un scalaire ou un tableau pour une liste d'objets du meme type
166 * Les objets sources sont les pivots qui portent les liens
167 * et pour lesquels une table spip_xxx_liens existe
168 * (auteurs, documents, mots)
170 * un * pour $objet,$id_objet permet de traiter par lot
171 * seul le type de l'objet source ne peut pas accepter de joker et doit etre explicite
173 * renvoie une liste de tableaux decrivant chaque lien
174 * dans lequel objet_source et objet_lie sont aussi affectes avec l'id de chaque
178 * array('id_document'=>23,'objet'=>'article','id_objet'=>12,'vu'=>'oui',
179 * 'document'=>23,'article'=>12)
183 * @param array $objets_source Couples (objets_source => identifiants) (objet qui a la table de lien)
184 * @param array|string $objets_lies Couples (objets_lies => identifiants)
185 * @param array|null $cond Condition du where supplémentaires
187 * Liste des trouvailles
189 function objet_trouver_liens($objets_source, $objets_lies, $cond = null) {
190 return objet_traiter_liaisons('lien_find', $objets_source, $objets_lies, $cond);
195 * Nettoyer les liens morts vers des objets qui n'existent plus
197 * $objets_source et $objets sont de la forme
198 * array($objet=>$id_objets,...)
199 * $id_objets peut lui meme etre un scalaire ou un tableau pour une liste d'objets du meme type
201 * Les objets sources sont les pivots qui portent les liens
202 * et pour lesquels une table spip_xxx_liens existe
203 * (auteurs, documents, mots)
205 * un * pour $objet,$id_objet permet de traiter par lot
206 * seul le type de l'objet source ne peut pas accepter de joker et doit etre explicite
209 * @param array $objets_source
210 * @param array|string $objets_lies
213 function objet_optimiser_liens($objets_source, $objets_lies) {
214 spip_log("objet_optimiser_liens : ".json_encode($objets_source) . ', ' . json_encode($objets_lies), 'genie'._LOG_DEBUG
);
215 return objet_traiter_liaisons('lien_optimise', $objets_source, $objets_lies);
220 * Dupliquer tous les liens entrant ou sortants d'un objet
221 * vers un autre (meme type d'objet, mais id different)
222 * si $types est fourni, seuls les liens depuis/vers les types listes seront copies
223 * si $exclure_types est fourni, les liens depuis/vers les types listes seront ignores
226 * @param string $objet
227 * @param int $id_source
228 * @param int $id_cible
229 * @param array $types
230 * @param array $exclure_types
232 * Nombre de liens copiés
234 function objet_dupliquer_liens($objet, $id_source, $id_cible, $types = null, $exclure_types = null) {
235 include_spip('base/objets');
236 $tables = lister_tables_objets_sql();
238 foreach ($tables as $table_sql => $infos) {
240 (is_null($types) or in_array($infos['type'], $types))
241 and (is_null($exclure_types) or !in_array($infos['type'], $exclure_types))
243 if (objet_associable($infos['type'])) {
244 $liens = (($infos['type'] == $objet) ?
245 objet_trouver_liens(array($objet => $id_source), '*')
247 objet_trouver_liens(array($infos['type'] => '*'), array($objet => $id_source)));
248 foreach ($liens as $lien) {
250 if ($infos['type'] == $objet) {
252 (is_null($types) or in_array($lien['objet'], $types))
253 and (is_null($exclure_types) or !in_array($lien['objet'], $exclure_types))
255 objet_associer(array($objet => $id_cible), array($lien['objet'] => $lien[$lien['objet']]), $lien);
258 objet_associer(array($infos['type'] => $lien[$infos['type']]), array($objet => $id_cible), $lien);
269 * Fonctions techniques
270 * ne pas les appeler directement
275 * Fonction générique qui
276 * applique une operation de liaison entre un ou des objets et des objets listés
278 * $objets_source et $objets_lies sont de la forme
279 * array($objet=>$id_objets,...)
280 * $id_objets peut lui meme etre un scalaire ou un tableau pour une liste d'objets du meme type
282 * Les objets sources sont les pivots qui portent les liens
283 * et pour lesquels une table spip_xxx_liens existe
284 * (auteurs, documents, mots)
286 * on peut passer optionnellement une qualification du (des) lien(s) qui sera
287 * alors appliquee dans la foulee.
288 * En cas de lot de liens, c'est la meme qualification qui est appliquee a tous
291 * @param string $operation
292 * Nom de la fonction PHP qui traitera l'opération
293 * @param array $objets_source
294 * Liste de ou des objets source
295 * De la forme array($objet=>$id_objets,...), où $id_objets peut lui
296 * même être un scalaire ou un tableau pour une liste d'objets du même type
297 * @param array $objets_lies
298 * Liste de ou des objets liés
299 * De la forme array($objet=>$id_objets,...), où $id_objets peut lui
300 * même être un scalaire ou un tableau pour une liste d'objets du même type
301 * @param null|array $set
302 * Liste de coupels champs valeur, soit array(champs => valeur)
303 * En fonction des opérations il peut servir à différentes utilisations
304 * @return bool|int|array
306 function objet_traiter_liaisons($operation, $objets_source, $objets_lies, $set = null) {
307 // accepter une syntaxe minimale pour supprimer tous les liens
308 if ($objets_lies == '*') {
309 $objets_lies = array('*' => '*');
311 $modifs = 0; // compter le nombre de modifications
313 foreach ($objets_source as $objet => $ids) {
314 if ($a = objet_associable($objet)) {
315 list($primary, $l) = $a;
316 if (!is_array($ids)) {
318 } elseif (reset($ids) == "NOT") {
319 // si on demande un array('NOT',...) => recuperer la liste d'ids correspondants
320 $where = lien_where($primary, $ids, '*', '*');
321 $ids = sql_allfetsel($primary, $l, $where);
322 $ids = array_map('reset', $ids);
324 foreach ($ids as $id) {
325 $res = $operation($objet, $primary, $l, $id, $objets_lies, $set);
326 if ($res === false) {
327 spip_log("objet_traiter_liaisons [Echec] : $operation sur $objet/$primary/$l/$id", _LOG_ERREUR
);
330 $modifs = ($modifs ?
(is_array($res) ?
array_merge($modifs, $res) : $modifs +
$res) : $res);
338 return ($echec ?
false : $modifs); // pas d'erreur
343 * Sous fonction insertion
344 * qui traite les liens pour un objet source dont la clé primaire
345 * et la table de lien sont fournies
347 * $objets et de la forme
348 * array($objet=>$id_objets,...)
350 * Retourne le nombre d'insertions réalisées
353 * @param string $objet_source Objet source de l'insertion (celui qui a la table de liaison)
354 * @param string $primary Nom de la clé primaire de cet objet
355 * @param string $table_lien Nom de la table de lien de cet objet
356 * @param int $id Identifiant de l'objet sur lesquels on va insérer des liaisons
357 * @param array $objets Liste des liaisons à faire, de la forme array($objet=>$id_objets)
358 * @param array $qualif
359 * Liste des qualifications à appliquer (qui seront faites par lien_set()),
360 * dont on cherche un rôle à insérer également.
361 * Si l'objet dispose d'un champ rôle, on extrait des qualifications
362 * le rôle s'il est présent, sinon on applique le rôle par défaut.
364 * Nombre d'insertions faites, false si échec.
366 function lien_insert($objet_source, $primary, $table_lien, $id, $objets, $qualif) {
369 if (is_null($qualif)) {
373 foreach ($objets as $objet => $id_objets) {
374 if (!is_array($id_objets)) {
375 $id_objets = array($id_objets);
378 // role, colonne, where par défaut
379 list($role, $colonne_role, $cond) =
380 roles_trouver_dans_qualif($objet_source, $objet, $qualif);
382 foreach ($id_objets as $id_objet) {
383 $objet = ($objet == '*') ?
$objet : objet_type($objet); # securite
386 'id_objet' => $id_objet,
390 // rôle en plus s'il est défini
392 $insertions +
= array(
393 $colonne_role => $role
397 'table_lien' => $table_lien,
398 'objet_source' => $objet_source,
399 'id_objet_source' => $id,
401 'id_objet' => $id_objet,
403 'colonne_role' => $colonne_role,
404 'action' => 'insert',
407 // Envoyer aux plugins
408 $insertions = pipeline('pre_edition_lien',
411 'data' => $insertions
414 $args['id_objet'] = $insertions['id_objet'];
416 $where = lien_where($primary, $id, $objet, $id_objet, $cond);
418 if ($id_objet = intval($insertions['id_objet'])
419 and !sql_getfetsel($primary, $table_lien, $where)
422 $e = sql_insertq($table_lien, $insertions);
425 lien_propage_date_modif($objet, $id_objet);
426 lien_propage_date_modif($objet_source, $id);
427 // Envoyer aux plugins
428 pipeline('post_edition_lien',
431 'data' => $insertions
441 return ($echec ?
false : $ins);
445 * Fabriquer la condition where en tenant compte des jokers *
448 * @param string $primary Nom de la clé primaire
449 * @param int|string|array $id_source Identifiant de la clé primaire
450 * @param string $objet Nom de l'objet lié
451 * @param int|string|array $id_objet Identifiant de l'objet lié
452 * @param array $cond Conditions par défaut
453 * @return array Liste des conditions
455 function lien_where($primary, $id_source, $objet, $id_objet, $cond = array()) {
456 if ((!is_array($id_source) and !strlen($id_source))
458 or (!is_array($id_objet) and !strlen($id_objet))
464 if (is_array($id_source) and reset($id_source) == "NOT") {
465 $not = array_shift($id_source);
466 $id_source = reset($id_source);
471 if ($id_source !== '*') {
472 $where[] = (is_array($id_source) ?
sql_in(addslashes($primary), array_map('intval', $id_source),
473 $not) : addslashes($primary) . ($not ?
"<>" : "=") . intval($id_source));
476 } // idiot mais quand meme
479 if (is_array($id_objet) and reset($id_objet) == "NOT") {
480 $not = array_shift($id_objet);
481 $id_objet = reset($id_objet);
484 if ($objet !== '*') {
485 $where[] = "objet=" . sql_quote($objet);
487 if ($id_objet !== '*') {
488 $where[] = (is_array($id_objet) ?
sql_in('id_objet', array_map('intval', $id_objet),
489 $not) : "id_objet" . ($not ?
"<>" : "=") . intval($id_objet));
492 } // idiot mais quand meme
498 * Sous fonction suppression
499 * qui traite les liens pour un objet source dont la clé primaire
500 * et la table de lien sont fournies
502 * $objets et de la forme
503 * array($objet=>$id_objets,...)
504 * un * pour $id,$objet,$id_objets permet de traiter par lot
506 * On supprime tous les liens entre les objets indiqués par défaut,
507 * sauf s'il y a des rôles déclarés entre ces 2 objets, auquel cas on ne
508 * supprime que les liaisons avec le role déclaré par défaut si rien n'est
509 * précisé dans $cond. Il faut alors passer $cond=array('role'=>'*') pour
510 * supprimer tous les roles, ou array('role'=>'un_role') pour un role précis.
513 * @param string $objet_source
514 * @param string $primary
515 * @param string $table_lien
517 * @param array $objets
518 * @param array|null $cond
519 * Conditions where par défaut.
520 * Un cas particulier est géré lorsque l'index 'role' est présent (ou absent)
523 function lien_delete($objet_source, $primary, $table_lien, $id, $objets, $cond = null) {
528 if (is_null($cond)) {
532 foreach ($objets as $objet => $id_objets) {
533 $objet = ($objet == '*') ?
$objet : objet_type($objet); # securite
534 if (!is_array($id_objets) or reset($id_objets) == "NOT") {
535 $id_objets = array($id_objets);
537 foreach ($id_objets as $id_objet) {
538 list($cond, $colonne_role, $role) = roles_creer_condition_role($objet_source, $objet, $cond);
539 // id_objet peut valoir '*'
540 $where = lien_where($primary, $id, $objet, $id_objet, $cond);
542 // lire les liens existants pour propager la date de modif
543 $select = "$primary,id_objet,objet";
545 $select .= ",$colonne_role";
547 $liens = sql_allfetsel($select, $table_lien, $where);
549 // iterer sur les liens pour permettre aux plugins de gerer
550 foreach ($liens as $l) {
553 'table_lien' => $table_lien,
554 'objet_source' => $objet_source,
555 'id_objet_source' => $l[$primary],
556 'objet' => $l['objet'],
557 'id_objet' => $l['id_objet'],
558 'colonne_role' => $colonne_role,
559 'role' => ($colonne_role ?
$l[$colonne_role] : ''),
560 'action' => 'delete',
563 // Envoyer aux plugins
564 $l = pipeline('pre_edition_lien',
570 $args['id_objet'] = $id_o = $l['id_objet'];
572 if ($id_o = intval($l['id_objet'])) {
573 $where = lien_where($primary, $l[$primary], $l['objet'], $id_o, $cond);
574 $e = sql_delete($table_lien, $where);
577 lien_propage_date_modif($l['objet'], $id_o);
578 lien_propage_date_modif($objet_source, $l[$primary]);
583 'source' => array($objet_source => $l[$primary]),
584 'lien' => array($l['objet'] => $id_o),
585 'type' => $l['objet'],
586 'role' => ($colonne_role ?
$l[$colonne_role] : ''),
589 // Envoyer aux plugins
590 pipeline('post_edition_lien',
601 pipeline('trig_supprimer_objets_lies', $retire);
603 return ($echec ?
false : $dels);
608 * Sous fonction optimisation
609 * qui nettoie les liens morts (vers un objet inexistant)
610 * pour un objet source dont la clé primaire
611 * et la table de lien sont fournies
613 * $objets et de la forme
614 * array($objet=>$id_objets,...)
615 * un * pour $id,$objet,$id_objets permet de traiter par lot
618 * @param string $objet_source
619 * @param string $primary
620 * @param string $table_lien
622 * @param array $objets
625 function lien_optimise($objet_source, $primary, $table_lien, $id, $objets) {
626 include_spip('genie/optimiser');
629 foreach ($objets as $objet => $id_objets) {
630 $objet = ($objet == '*') ?
$objet : objet_type($objet); # securite
631 if (!is_array($id_objets) or reset($id_objets) == "NOT") {
632 $id_objets = array($id_objets);
634 foreach ($id_objets as $id_objet) {
635 $where = lien_where($primary, $id, $objet, $id_objet);
636 # les liens vers un objet inexistant
637 $r = sql_select("DISTINCT objet", $table_lien, $where);
638 while ($t = sql_fetch($r)) {
640 $spip_table_objet = table_objet_sql($type);
641 $id_table_objet = id_table_objet($type);
642 $res = sql_select("L.$primary AS id,L.id_objet",
643 // la condition de jointure inclue L.objet='xxx' pour ne joindre que les bonnes lignes
644 // du coups toutes les lignes avec un autre objet ont un id_xxx=NULL puisque LEFT JOIN
645 // il faut les eliminier en repetant la condition dans le where L.objet='xxx'
647 LEFT JOIN $spip_table_objet AS O
648 ON (O.$id_table_objet=L.id_objet AND L.objet=" . sql_quote($type) . ")",
649 "L.objet=" . sql_quote($type) . " AND O.$id_table_objet IS NULL");
650 // sur une cle primaire composee, pas d'autres solutions que de virer un a un
651 while ($row = sql_fetch($res)) {
652 $e = sql_delete($table_lien,
653 array("$primary=" . $row['id'], "id_objet=" . $row['id_objet'], "objet=" . sql_quote($type)));
657 "lien_optimise: Entree " . $row['id'] . "/" . $row['id_objet'] . "/$type supprimee dans la table $table_lien",
658 'genie'._LOG_INFO_IMPORTANTE
664 # les liens depuis un objet inexistant
665 $table_source = table_objet_sql($objet_source);
666 // filtrer selon $id, $objet, $id_objet eventuellement fournis
667 // (en general '*' pour chaque)
668 $where = lien_where("L.$primary", $id, $objet, $id_objet);
669 $where[] = "O.$primary IS NULL";
670 $res = sql_select("L.$primary AS id",
671 "$table_lien AS L LEFT JOIN $table_source AS O ON L.$primary=O.$primary",
673 $dels +
= optimiser_sansref($table_lien, $primary, $res);
677 return ($echec ?
false : $dels);
682 * Sous fonction qualification
683 * qui traite les liens pour un objet source dont la clé primaire
684 * et la table de lien sont fournies
686 * $objets et de la forme
687 * array($objet=>$id_objets,...)
688 * un * pour $id,$objet,$id_objets permet de traiter par lot
691 * $qualif = array('vu'=>'oui');
694 * @param string $objet_source Objet source de l'insertion (celui qui a la table de liaison)
695 * @param string $primary Nom de la clé primaire de cet objet
696 * @param string $table_lien Nom de la table de lien de cet objet
697 * @param int $id Identifiant de l'objet sur lesquels on va insérer des liaisons
698 * @param array $objets Liste des liaisons à faire, de la forme array($objet=>$id_objets)
699 * @param array $qualif
700 * Liste des qualifications à appliquer.
702 * Si l'objet dispose d'un champ rôle, on extrait des qualifications
703 * le rôle s'il est présent, sinon on applique les qualifications
704 * sur le rôle par défaut.
706 * Nombre de modifications faites, false si échec.
708 function lien_set($objet_source, $primary, $table_lien, $id, $objets, $qualif) {
714 // nettoyer qualif qui peut venir directement d'un objet_trouver_lien :
715 unset($qualif[$primary]);
716 unset($qualif[$objet_source]);
717 if (isset($qualif['objet'])) {
718 unset($qualif[$qualif['objet']]);
720 unset($qualif['objet']);
721 unset($qualif['id_objet']);
722 foreach ($objets as $objet => $id_objets) {
724 // role, colonne, where par défaut
725 list($role, $colonne_role, $cond) =
726 roles_trouver_dans_qualif($objet_source, $objet, $qualif);
728 $objet = ($objet == '*') ?
$objet : objet_type($objet); # securite
729 if (!is_array($id_objets) or reset($id_objets) == "NOT") {
730 $id_objets = array($id_objets);
732 foreach ($id_objets as $id_objet) {
735 'table_lien' => $table_lien,
736 'objet_source' => $objet_source,
737 'id_objet_source' => $id,
739 'id_objet' => $id_objet,
741 'colonne_role' => $colonne_role,
742 'action' => 'modifier',
745 // Envoyer aux plugins
746 $qualif = pipeline('pre_edition_lien',
752 $args['id_objet'] = $id_objet;
754 $where = lien_where($primary, $id, $objet, $id_objet, $cond);
755 $e = sql_updateq($table_lien, $qualif, $where);
760 // Envoyer aux plugins
761 pipeline('post_edition_lien',
772 return ($echec ?
false : $ok);
776 * Sous fonction trouver
777 * qui cherche les liens pour un objet source dont la clé primaire
778 * et la table de lien sont fournies
780 * $objets et de la forme
781 * array($objet=>$id_objets,...)
782 * un * pour $id,$objet,$id_objets permet de traiter par lot
784 * Le tableau de condition peut avoir un index 'role' indiquant de
785 * chercher un rôle précis, ou * pour tous les roles (alors équivalent
786 * à l'absence de l'index)
789 * @param string $objet_source
790 * @param string $primary
791 * @param string $table_lien
793 * @param array $objets
794 * @param array|null $cond
795 * Condition du where par défaut
797 * On peut passer un index 'role' pour sélectionner uniquement
798 * le role défini dedans (et '*' pour tous les rôles).
801 function lien_find($objet_source, $primary, $table_lien, $id, $objets, $cond = null) {
803 foreach ($objets as $objet => $id_objets) {
804 $objet = ($objet == '*') ?
$objet : objet_type($objet); # securite
805 // gerer les roles s'il y en a dans $cond
806 list($cond) = roles_creer_condition_role($objet_source, $objet, $cond, true);
807 // lien_where prend en charge les $id_objets sous forme int ou array
808 $where = lien_where($primary, $id, $objet, $id_objets, $cond);
809 $liens = sql_allfetsel('*', $table_lien, $where);
810 // ajouter les entrees objet_source et objet cible par convenance
811 foreach ($liens as $l) {
812 $l[$objet_source] = $l[$primary];
813 $l[$l['objet']] = $l['id_objet'];
822 * Propager la date_modif sur les objets dont un lien a été modifié
825 * @param string $objet
826 * @param array|int $ids
828 function lien_propage_date_modif($objet, $ids) {
829 static $done = array();
830 $hash = md5($objet . serialize($ids));
832 // sql_updateq, peut être un rien lent.
833 // On évite de l'appeler 2 fois sur les mêmes choses
834 if (isset($done[$hash])) {
838 $trouver_table = charger_fonction('trouver_table', 'base');
840 $table = table_objet_sql($objet);
841 if ($desc = $trouver_table($table)
842 and isset($desc['field']['date_modif'])
844 $primary = id_table_objet($objet);
845 $where = (is_array($ids) ?
sql_in($primary, array_map('intval', $ids)) : "$primary=" . intval($ids));
846 sql_updateq($table, array('date_modif' => date('Y-m-d H:i:s')), $where);