From 89ca99bb9f19ec5a6fe1ae5c4ea39a4c82632304 Mon Sep 17 00:00:00 2001
From: Cerdic <cedric@yterium.com>
Date: Tue, 8 Jul 2008 12:19:38 +0000
Subject: [PATCH] la table spip_documents_liens unifiee sur le modele
 (id_document,id_objet,objet) ce qui la rend extensible et utilisable par les
 plugins pour tout type d'objet l'upgrade devrait se faire a partir de la
 table spip_documents_liens precedente ou des anciennes tables
 spip_documents_xxx selon le point de depart

---
 dist/inc-documents.html          |  2 +-
 ecrire/action/documenter.php     |  8 ++++----
 ecrire/action/editer_article.php |  2 +-
 ecrire/base/auxiliaires.php      | 10 +++-------
 ecrire/exec/controle_forum.php   |  2 +-
 ecrire/exec/documents_liste.php  |  2 +-
 ecrire/exec/naviguer.php         |  2 +-
 ecrire/genie/optimiser.php       | 24 ++++++++++++++++++++---
 ecrire/inc/agenda.php            |  2 +-
 ecrire/inc/ajouter_documents.php |  3 ++-
 ecrire/inc/autoriser.php         | 33 ++++++++++++++------------------
 ecrire/inc/boutons.php           |  2 +-
 ecrire/inc/documenter.php        |  4 ++--
 ecrire/inc/documents.php         | 32 +++++++++----------------------
 ecrire/inc/legender.php          |  2 +-
 ecrire/inc/modifier.php          |  9 ++++-----
 ecrire/inc/rubriques.php         |  4 ++--
 ecrire/inc/tourner.php           |  2 +-
 ecrire/inc_version.php           |  4 ++--
 ecrire/maj/svn10000.php          | 31 +++++++++++++++++++++++-------
 ecrire/public/boucles.php        | 15 ++++++---------
 21 files changed, 102 insertions(+), 93 deletions(-)

diff --git a/dist/inc-documents.html b/dist/inc-documents.html
index 44ddc37bf6..16762a8bd0 100644
--- a/dist/inc-documents.html
+++ b/dist/inc-documents.html
@@ -42,7 +42,7 @@
 		Si un seul document est joint a l'article, et si le texte est vide,
 		on incruste automatiquement ce document
 	]
-	<BOUCLE_documents_decompte(DOCUMENTS documents_liens articles)
+	<BOUCLE_documents_decompte(DOCUMENTS spip_documents_liens articles)
 	{id_article}
 	{mode=document}
 	{texte=''}
diff --git a/ecrire/action/documenter.php b/ecrire/action/documenter.php
index 0405781b61..1dcb0c51d3 100644
--- a/ecrire/action/documenter.php
+++ b/ecrire/action/documenter.php
@@ -35,7 +35,7 @@ function action_documenter_post($r)
 		// supprimer_document_et_vignette($vignette);
 		// on dissocie, mais si le doc est utilise dans le texte, il sera reassocie ..., donc condition sur vu !
 		sql_delete("spip_documents_liens",
-			"id_$type=".sql_quote($id)." AND id_document=".sql_quote($vignette)." AND (vu='non' OR vu IS NULL)");
+			"id_objet=".intval($id)."objet=".sql_quote($type)." AND id_document=".sql_quote($vignette)." AND (vu='non' OR vu IS NULL)");
 		// Cas de destruction de la vignette seulement
 		if ($suite)
 			sql_updateq("spip_documents", array('id_vignette' => 0), "id_document=$suite");
@@ -59,15 +59,15 @@ function action_documenter_post($r)
 	}
 	else {
 		if ($sign)
-			$x = sql_select("docs.id_document", "spip_documents AS docs, spip_documents_liens AS l", "l.id_$type=$id AND l.id_document=docs.id_document AND docs.mode='document' AND docs.extension IN ('gif', 'jpg', 'png')");
+			$x = sql_select("docs.id_document", "spip_documents AS docs, spip_documents_liens AS l", "l.id_objet=".intval($id)." AND l.objet=".sql_quote($type)." AND l.id_document=docs.id_document AND docs.mode='document' AND docs.extension IN ('gif', 'jpg', 'png')");
 		else
-			$x = sql_select("docs.id_document", "spip_documents AS docs, spip_documents_liens AS l", "l.id_$type=$id AND l.id_document=docs.id_document AND docs.mode='document'  AND docs.extension NOT IN ('gif', 'jpg', 'png')");
+			$x = sql_select("docs.id_document", "spip_documents AS docs, spip_documents_liens AS l", "l.id_objet=".intval($id)." AND l.objet=".sql_quote($type)." AND l.id_document=docs.id_document AND docs.mode='document'  AND docs.extension NOT IN ('gif', 'jpg', 'png')");
 
 		while ($r = sql_fetch($x)) {
 			// supprimer_document_et_vignette($r['id_document']);
 			// on dissocie, mais si le doc est utilise dans le texte,
 			// il sera reassocie ..., donc condition sur vu !
-			sql_delete("spip_documents_liens", "id_$type=$id AND id_document=".$r['id_document']." AND (vu='non' OR vu IS NULL)");
+			sql_delete("spip_documents_liens", "id_objet=".intval($id)." AND objet=".sql_quote($type)."  AND id_document=".$r['id_document']." AND (vu='non' OR vu IS NULL)");
 		}
 	}
 	if ($type == 'rubrique') {
diff --git a/ecrire/action/editer_article.php b/ecrire/action/editer_article.php
index dca37f3de1..2df6db159f 100644
--- a/ecrire/action/editer_article.php
+++ b/ecrire/action/editer_article.php
@@ -33,7 +33,7 @@ function action_editer_article_dist() {
 		# rattrapper les documents associes a cet article nouveau
 		# ils ont un id = 0-id_auteur
 
-			sql_updateq("spip_documents_liens", array("id_article" => $id_article), "id_article = ".(0-$id_auteur));
+			sql_updateq("spip_documents_liens", array("id_objet" => $id_article), array("id_objet = ".(0-$id_auteur),"objet='article'"));
 	} 
 
 	// Enregistre l'envoi dans la BD
diff --git a/ecrire/base/auxiliaires.php b/ecrire/base/auxiliaires.php
index becab87bc9..f0382e10a9 100644
--- a/ecrire/base/auxiliaires.php
+++ b/ecrire/base/auxiliaires.php
@@ -104,18 +104,14 @@ $spip_auteurs_messages_key = array(
 
 $spip_documents_liens = array(
 		"id_document"	=> "bigint(21) DEFAULT '0' NOT NULL",
-		"id_article"	=> "bigint(21) NULL",
-		"id_breve"	=> "bigint(21) NULL",
-		"id_rubrique"	=> "bigint(21) NULL",
-		"id_auteur"	=> "bigint(21) NULL",
-		"id_forum"	=> "bigint(21) NULL",
+		"id_objet"	=> "bigint(21) DEFAULT '0' NOT NULL",
+		"objet"	=> "VARCHAR (25) DEFAULT '' NOT NULL",
 		"vu"	=> "ENUM('non', 'oui') DEFAULT 'non' NOT NULL");
 
 $spip_documents_liens_key = array(
-		"PRIMARY KEY"		=> "id_document,id_article,id_breve,id_rubrique,id_auteur,id_forum",
+		"PRIMARY KEY"		=> "id_document,id_objet,objet",
 		"KEY id_document"	=> "id_document");
 
-
 /*
 $spip_documents_articles = array(
 		"id_document"	=> "bigint(21) DEFAULT '0' NOT NULL",
diff --git a/ecrire/exec/controle_forum.php b/ecrire/exec/controle_forum.php
index fc4ce7d8ce..eaad7af95e 100644
--- a/ecrire/exec/controle_forum.php
+++ b/ecrire/exec/controle_forum.php
@@ -135,7 +135,7 @@ function controle_forum_boucle($row) {
 
 
 	$documents = array();
-	if ($s = sql_select('doc.fichier AS fichier', 'spip_documents AS doc, spip_documents_liens AS lien', 'doc.id_document=lien.id_document AND lien.id_forum='.$id_forum))
+	if ($s = sql_select('doc.fichier AS fichier', 'spip_documents AS doc, spip_documents_liens AS lien', 'doc.id_document=lien.id_document AND lien.id_objet='.intval($id_forum)." AND objet='forum'"))
 	while ($t = sql_fetch($s)) {
 		include_spip('inc/documents');
 		$documents[] = "<a href='".get_spip_doc($t['fichier'])."'>".basename($t['fichier'])."</a>";
diff --git a/ecrire/exec/documents_liste.php b/ecrire/exec/documents_liste.php
index 9f1372cfd8..66f6dce801 100644
--- a/ecrire/exec/documents_liste.php
+++ b/ecrire/exec/documents_liste.php
@@ -46,7 +46,7 @@ echo debut_droite('', true);
 	while ($row = sql_fetch($res))
 		$types[$row['extension']] = $row;
 
-	$result = sql_select("docs.id_document AS id_doc, docs.extension AS extension, docs.fichier AS fichier, docs.date AS date, docs.titre AS titre, docs.descriptif AS descriptif, lien.id_rubrique AS id_rub, rubrique.titre AS titre_rub", "spip_documents AS docs, spip_documents_liens AS lien, spip_rubriques AS rubrique", "docs.id_document = lien.id_document AND rubrique.id_rubrique = lien.id_rubrique AND docs.mode = 'document'", "", "docs.date DESC");
+	$result = sql_select("docs.id_document AS id_doc, docs.extension AS extension, docs.fichier AS fichier, docs.date AS date, docs.titre AS titre, docs.descriptif AS descriptif, lien.id_rubrique AS id_rub, rubrique.titre AS titre_rub", "spip_documents AS docs, spip_documents_liens AS lien, spip_rubriques AS rubrique", "docs.id_document = lien.id_document AND rubrique.id_rubrique = lien.id_objet AND lien.objet='rubrique' AND docs.mode = 'document'", "", "docs.date DESC");
 
 	while ($row=sql_fetch($result)){
 		$titre=$row['titre'];
diff --git a/ecrire/exec/naviguer.php b/ecrire/exec/naviguer.php
index 8734a29cf6..9f466b5119 100644
--- a/ecrire/exec/naviguer.php
+++ b/ecrire/exec/naviguer.php
@@ -460,7 +460,7 @@ function tester_rubrique_vide($id_rubrique) {
 	if (sql_countsel('spip_syndic', "id_rubrique=$id_rubrique AND (statut='publie' OR statut='prop')"))
 		return false;
 
-	if (sql_countsel('spip_documents_liens', "id_rubrique=$id_rubrique"))
+	if (sql_countsel('spip_documents_liens', "id_objet=".intval($id_rubrique)." AND objet='rubrique'"))
 		return false;
 
 	return true;
diff --git a/ecrire/genie/optimiser.php b/ecrire/genie/optimiser.php
index e5f15e68ac..f04192a313 100644
--- a/ecrire/genie/optimiser.php
+++ b/ecrire/genie/optimiser.php
@@ -296,9 +296,27 @@ function optimiser_base_disparus($attente = 86400) {
 	//
 	// Documents
 	//
-	# liens de documents avec des objets inexistants
-	# TODO
-
+	
+	# les liens des documents qui sont lies a un objet inexistant
+	$r = sql_select("DISTINCT objet","spip_documents_liens");
+	while ($t = sql_fetch($r)){
+		$type = $t['objet'];
+		$spip_table_objet = table_objet_sql($type);
+		$id_table_objet = id_table_objet($type);
+		$res = sql_select("L.id_document AS id,id_objet",
+			      "spip_documents_liens AS L
+			        LEFT JOIN $spip_table_objet AS O
+			          ON O.$id_table_objet=L.id_objet AND L.objet=".sql_quote($type),
+				"O.$id_table_objet IS NULL");
+		// sur une cle primaire composee, pas d'autres solutions que de virer un a un
+		while ($row = sql_fetch($sel)){
+			sql_delete("spip_documents_liens", array("id_document=".$row['id'],"id_objet=".$row['id_objet'],"objet=".sql_quote($type)));
+			spip_log("Entree ".$row['id']."/".$row['id_objet']."/$type supprimee dans la table spip_documents_liens");
+		}
+	}
+	
+	// on ne nettoie volontairement pas automatiquement les documents orphelins
+	
 	//
 	// Messages prives
 	//
diff --git a/ecrire/inc/agenda.php b/ecrire/inc/agenda.php
index 37e85e0e42..5e3b7a23aa 100644
--- a/ecrire/inc/agenda.php
+++ b/ecrire/inc/agenda.php
@@ -1405,7 +1405,7 @@ function quete_calendrier_interval_articles($avant, $apres, &$evenements) {
 // http://doc.spip.org/@quete_calendrier_interval_rubriques
 function quete_calendrier_interval_rubriques($avant, $apres, &$evenements) {
 	
-  $result=sql_select('DISTINCT R.id_rubrique, titre, descriptif, date', 'spip_rubriques AS R, spip_documents_liens AS L', "statut='publie' AND	date >= $avant AND	date < $apres AND	R.id_rubrique = L.id_rubrique",'', "date");
+  $result=sql_select('DISTINCT R.id_rubrique, titre, descriptif, date', 'spip_rubriques AS R, spip_documents_liens AS L', "statut='publie' AND	date >= $avant AND	date < $apres AND	R.id_rubrique = L.id_objet AND L.objet='rubrique'",'', "date");
 	while($row=sql_fetch($result)){
 		$amj = date_anneemoisjour($row['date']);
 		$id = $row['id_rubrique'];
diff --git a/ecrire/inc/ajouter_documents.php b/ecrire/inc/ajouter_documents.php
index 361b674f40..1e858176db 100644
--- a/ecrire/inc/ajouter_documents.php
+++ b/ecrire/inc/ajouter_documents.php
@@ -245,7 +245,8 @@ function ajouter_un_document($source, $nom_envoye, $type_lien, $id_lien, $mode,
 		) {
 			sql_insertq('spip_documents_liens',
 				    array('id_document' => $id,
-					  'id_'.$type_lien => $id_lien));
+					  'id_objet' => $id_lien,
+					  'objet' => $type_lien));
 		} else spip_log("Pb d'insertion $id_lien $type_lien");
 
 		if ($id_document) {
diff --git a/ecrire/inc/autoriser.php b/ecrire/inc/autoriser.php
index 9911fedaaa..5a0202c012 100644
--- a/ecrire/inc/autoriser.php
+++ b/ecrire/inc/autoriser.php
@@ -258,21 +258,14 @@ function autoriser_document_modifier_dist($faire, $type, $id, $qui, $opt){
 		$vu = false;
 		$interdit = false;
 
-		$s = sql_select("*", "spip_documents_liens", "id_document=".sql_quote($id));
+		$s = sql_select("id_objet,objet", "spip_documents_liens", "id_document=".sql_quote($id));
 		while ($t = sql_fetch($s)) {
-			// chercher la cle non vide
-			foreach ($t as $k=>$val) {
-				if ($val
-				AND $k != 'id_document'
-				AND substr($k,0,3) == 'id_') {
-					if (autoriser('modifier', substr($k,3), $val, $qui, $opt)) {
-						$vu = true;
-					}
-					else {
-						$interdit = true;
-						break 2;
-					}
-				}
+			if (autoriser('modifier', $row['objet'], $row['id_objet'], $qui, $opt)) {
+				$vu = true;
+			}
+			else {
+				$interdit = true;
+				break;
 			}
 		}
 		$m[$id] = ($vu && !$interdit);
@@ -550,11 +543,13 @@ function autoriser_document_voir_dist($faire, $type, $id, $qui, $opt) {
 	if (in_array($qui['statut'], array('0minirezo', '1comite')))
 		return 'htaccess';
 
-	if (sql_countsel('spip_documents_liens AS rel_articles, spip_articles AS articles', "rel_articles.id_article = articles.id_article AND articles.statut = 'publie' AND rel_articles.id_document = $id") > 0
-	OR sql_countsel('spip_documents_liens AS rel_rubriques, spip_rubriques AS rubriques', "rel_rubriques.id_rubrique = rubriques.id_rubrique AND rubriques.statut = 'publie' AND rel_rubriques.id_document = $id") > 0
-	OR sql_countsel('spip_documents_liens AS rel_breves, spip_breves AS breves', "rel_breves.id_breve = breves.id_breve AND breves.statut = 'publie' AND rel_breves.id_document = $id") > 0)
-		return 'htaccess';
-	else return false;
+	foreach(array('article','rubrique','breve') as $objet){
+		$table_sql = table_objet_sql($objet);
+		$id_table = id_table_objet($objet);
+		if (sql_countsel('spip_documents_liens AS rel, $table_sql AS o', "rel.id_objet = articles.$id_table AND rel.objet='$objet' AND o.statut = 'publie' AND rel.id_document = $id") > 0)
+			return 'htaccess';
+	}
+	return false;
 }
 
 // Qui peut activer le debugueur ?
diff --git a/ecrire/inc/boutons.php b/ecrire/inc/boutons.php
index 82ad19135f..c077631e9c 100644
--- a/ecrire/inc/boutons.php
+++ b/ecrire/inc/boutons.php
@@ -130,7 +130,7 @@ function definir_barre_boutons() {
 			$sousmenu['sites_tous']=
 			  new Bouton('site-24.gif', 'icone_sites_references');
 
-	$n = sql_countsel('spip_documents_liens', 'id_rubrique>0');
+	$n = sql_countsel('spip_documents_liens', 'id_objet>0 AND objet=\'rubrique\'');
 	if ($n) {
 			$sousmenu['documents_liste']=
 			  new Bouton('doc-24.gif', 'icone_doc_rubrique');
diff --git a/ecrire/inc/documenter.php b/ecrire/inc/documenter.php
index b971564a59..5e72274607 100644
--- a/ecrire/inc/documenter.php
+++ b/ecrire/inc/documenter.php
@@ -28,9 +28,9 @@ function inc_documenter_dist(
 	if (is_int($doc)) {
 		$prim = 'id_' . $type;
 		$img = ($ancre == 'portfolio') ? '' : " NOT";
-		$select = "D.id_document, D.id_vignette, D.extension, D.titre,  D.date,  D.descriptif,  D.fichier,  D.taille, D.largeur,  D.hauteur,  D.mode,  D.distant, L.vu, L." .$prim;
+		$select = "D.id_document, D.id_vignette, D.extension, D.titre,  D.date,  D.descriptif,  D.fichier,  D.taille, D.largeur,  D.hauteur,  D.mode,  D.distant, L.vu, L.id_objet, L.id_objet as $prim";
 		$from = "spip_documents AS D LEFT JOIN spip_documents_liens AS L ON  L.id_document=D.id_document"; 
-		$where = "L.$prim=$doc AND D.mode='document' AND D.extension $img IN ('gif', 'jpg', 'png')";
+		$where = "L.id_objet=$doc AND Lobjet='$type' AND D.mode='document' AND D.extension $img IN ('gif', 'jpg', 'png')";
 		$order = "0+D.titre, D.date";
 		$docs = rows_as_array($select, $from, $where, '', $order);
 		$opt = array('objet'=>$type, 'id_objet' => $doc);
diff --git a/ecrire/inc/documents.php b/ecrire/inc/documents.php
index 2fef9f3adc..92a68793b3 100644
--- a/ecrire/inc/documents.php
+++ b/ecrire/inc/documents.php
@@ -239,7 +239,7 @@ function afficher_documents_colonne($id, $type="article",$script=NULL) {
 		. '</div><br />';
 
 	//// Documents associes
-	$res = sql_select("D.id_document", "spip_documents AS D LEFT JOIN spip_documents_liens AS T ON T.id_document=D.id_document", "T.id_".$type."=" .sql_quote($id) . " AND D.mode='document'", "", "D.id_document");
+	$res = sql_select("D.id_document", "spip_documents AS D LEFT JOIN spip_documents_liens AS T ON T.id_document=D.id_document", "T.id_objet=" . intval($id) . " AND T.objet=" . sql_quote($type) . " AND D.mode='document'", "", "D.id_document");
 
 
 	$documents_lies = array();
@@ -247,7 +247,7 @@ function afficher_documents_colonne($id, $type="article",$script=NULL) {
 		$documents_lies[]= $row['id_document'];
 
 	//// Images sans documents
-	$res = sql_select("D.id_document", "spip_documents AS D LEFT JOIN spip_documents_liens AS T ON T.id_document=D.id_document", "T.id_".$type."=" .sql_quote($id) . " AND D.mode='image'", "", "D.id_document");
+	$res = sql_select("D.id_document", "spip_documents AS D LEFT JOIN spip_documents_liens AS T ON T.id_document=D.id_document", "T.id_objet=" . intval($id) . " AND T.objet=" . sql_quote($type) . " AND D.mode='image'", "", "D.id_document");
 
 	$ret .= "\n<div id='liste_images'>";
 
@@ -331,13 +331,8 @@ function est_inclus($id_document) {
 function afficher_case_document($id_document, $id, $script, $type, $deplier=false) {
 	global $spip_lang_right;
 
-	$table = 'spip_documents_liens';
-	$prim = id_table_objet($table);
-	if (!$prim) return '';
-	$prim = 'id_' . $type;
-
 	charger_generer_url();
-	$document = sql_fetsel("docs.id_document, docs.id_vignette,docs.extension,docs.titre,docs.descriptif,docs.fichier,docs.largeur,docs.hauteur,docs.taille,docs.mode,docs.distant, docs.date, L.vu", "spip_documents AS docs JOIN $table AS L ON L.id_document=docs.id_document", "L.$prim=".sql_quote($id)." AND L.id_document=".sql_quote($id_document));
+	$document = sql_fetsel("docs.id_document, docs.id_vignette,docs.extension,docs.titre,docs.descriptif,docs.fichier,docs.largeur,docs.hauteur,docs.taille,docs.mode,docs.distant, docs.date, L.vu", "spip_documents AS docs JOIN spip_documents_liens AS L ON L.id_document=docs.id_document", "L.id_objet=".intval($id)." AND objet=".sql_quote($type)." AND L.id_document=".sql_quote($id_document));
 
 	if (!$document) return "";
 
@@ -481,27 +476,17 @@ function afficher_case_document($id_document, $id, $script, $type, $deplier=fals
 }
 
 // Etablit la liste des documents orphelins, c'est-a-dire qui ne sont lies
-// a aucun article ni breve ni rubrique ; renvoie un tableau (id_document)
+// a rien ; renvoie un tableau (id_document)
+// ici on ne join pas avec la table objet pour voir si l'objet existe vraiment
+// on considere que c'est le role d'optimiser que de nettoyer les liens morts
+// sinon eventuellement appeler avant une fonction nettoyer_liens_documents
 // http://doc.spip.org/@lister_les_documents_orphelins
 function lister_les_documents_orphelins() {
 	$s = sql_select("d.id_document, d.id_vignette",
 	"spip_documents AS d
 	LEFT JOIN spip_documents_liens AS l
-		ON d.id_document=l.id_document
-	LEFT JOIN spip_articles AS aa
-		ON aa.id_article=l.id_article
-	LEFT JOIN spip_breves AS bb
-		ON bb.id_breve=l.id_breve
-	LEFT JOIN spip_rubriques AS rr
-		ON rr.id_rubrique=l.id_rubrique
-	LEFT JOIN spip_forum AS ff
-		ON ff.id_forum=l.id_forum
 	",
-	"(aa.id_article IS NULL)
-	AND (bb.id_breve IS NULL)
-	AND (rr.id_rubrique IS NULL)
-	AND (ff.id_forum IS NULL)
-	");
+	"(l.id_objet IS NULL)");
 
 	$orphelins = array();
 	while ($t = sql_fetch($s)) {
@@ -552,6 +537,7 @@ function supprimer_documents($liste = array()) {
 
 	// Supprimer les entrees dans spip_documents et associees
 	sql_delete('spip_documents', $in);
+	// en principe il ne devrait rien y avoir ici si les documents sont bien orphelins
 	sql_delete('spip_documents_liens', $in);
 }
 
diff --git a/ecrire/inc/legender.php b/ecrire/inc/legender.php
index eeb85c4e07..1c8828a733 100644
--- a/ecrire/inc/legender.php
+++ b/ecrire/inc/legender.php
@@ -32,7 +32,7 @@ function inc_legender_dist($id_document, $document, $script, $type, $id, $ancre,
 	if ($id_document) {
 		$document = sql_fetsel("*", "spip_documents", "id_document = " . intval($id_document));
 
-		$document['vu'] = sql_getfetsel("vu", 'spip_documents_liens', "id_$type=" . intval($id) ." AND id_document=".intval($id_document));
+		$document['vu'] = sql_getfetsel("vu", 'spip_documents_liens', "id_objet=" . intval($id) ." AND objet=" . sql_quote($type) . " AND id_document=".intval($id_document));
 
 		if (!$document['vu']) $document['vu'] = 'non';
 		$flag = 'ajax';
diff --git a/ecrire/inc/modifier.php b/ecrire/inc/modifier.php
index 2e6ab68b9f..2e7fa70172 100644
--- a/ecrire/inc/modifier.php
+++ b/ecrire/inc/modifier.php
@@ -121,8 +121,7 @@ function modifier_contenu($type, $id, $options, $c=false, $serveur='') {
 
 		// marquer les documents vus dans le texte si il y a lieu
 		include_spip('base/auxiliaires');
-		if (isset($GLOBALS['tables_auxiliaires']["spip_documents_liens"]["field"][$id_table_objet]))
-			marquer_doublons_documents($champs,$id,$id_table_objet,$table_objet,$spip_table_objet, $desc, $serveur);
+		marquer_doublons_documents($champs,$id,$type,$id_table_objet,$table_objet,$spip_table_objet, $desc, $serveur);
 
 		// Notifications, gestion des revisions...
 		// en standard, appelle |nouvelle_revision ci-dessous
@@ -155,7 +154,7 @@ function modifier_contenu($type, $id, $options, $c=false, $serveur='') {
 }
 
 // http://doc.spip.org/@marquer_doublons_documents
-function marquer_doublons_documents($champs,$id,$id_table_objet,$table_objet,$spip_table_objet, $desc=array(), $serveur=''){
+function marquer_doublons_documents($champs,$id,$type,$id_table_objet,$table_objet,$spip_table_objet, $desc=array(), $serveur=''){
 	if (!isset($champs['texte']) AND !isset($champs['chapo'])) return;
 	if (!$desc) $desc = $trouver_table($table_objet, $serveur);
 	$load = "";
@@ -174,14 +173,14 @@ function marquer_doublons_documents($champs,$id,$id_table_objet,$table_objet,$sp
 	include_spip('base/abstract_sql');
 	$GLOBALS['doublons_documents_inclus'] = array();
 	traiter_modeles($champs['chapo'].$champs['texte'],true); // detecter les doublons
-	sql_updateq("spip_documents_liens", array("vu" => 'non'), "$id_table_objet=$id");
+	sql_updateq("spip_documents_liens", array("vu" => 'non'), "id_objet=$id AND objet=".sql_quote($type));
 	if (count($GLOBALS['doublons_documents_inclus'])){
 		// on repasse par une requete sur spip_documents pour verifier que les documents existent bien !
 		$in_liste = sql_in('id_document',
 			$GLOBALS['doublons_documents_inclus']);
 		$res = sql_select("id_document", "spip_documents", $in_liste);
 		while ($row = sql_fetch($res)) {
-			sql_updateq("spip_documents_liens", array("vu" => 'oui'), "$id_table_objet=$id AND id_document=" . $row['id_document']);
+			sql_updateq("spip_documents_liens", array("vu" => 'oui'), "id_objet=$id AND objet=".sql_quote($type)." AND id_document=" . $row['id_document']);
 		}
 	}
 }
diff --git a/ecrire/inc/rubriques.php b/ecrire/inc/rubriques.php
index 9e6e3a51cc..66a40683f9 100644
--- a/ecrire/inc/rubriques.php
+++ b/ecrire/inc/rubriques.php
@@ -88,7 +88,7 @@ function depublier_branche_rubrique_if($id_rubrique)
 		if (sql_countsel("spip_rubriques",  "id_parent=$id_pred AND statut='publie'"))
 			return $id_pred != $id_rubrique;;
 	
-		if (sql_countsel("spip_documents_liens",  "id_rubrique=$id_pred"))
+		if (sql_countsel("spip_documents_liens",  "id_objet=$id_pred AND objet='rubrique'"))
 			return $id_pred != $id_rubrique;;
 
 		sql_updateq("spip_rubriques", array("statut" => '0'), "id_rubrique=$id_pred");
@@ -158,7 +158,7 @@ function calculer_rubriques_publiees() {
 		sql_updateq('spip_rubriques', array('statut_tmp'=>'publie', 'date_tmp'=>$row['date_h']),"id_rubrique=".$row['id']);
 	
 	// Publier et dater les rubriques qui ont un *document* publie
-	$r = sql_select("rub.id_rubrique AS id, max(fille.date) AS date_h", "spip_rubriques AS rub, spip_documents AS fille, spip_documents_liens AS lien", "rub.id_rubrique = lien.id_rubrique AND lien.id_document=fille.id_document AND rub.date_tmp <= fille.date AND fille.mode='document' $postdates ", "rub.id_rubrique");
+	$r = sql_select("rub.id_rubrique AS id, max(fille.date) AS date_h", "spip_rubriques AS rub, spip_documents AS fille, spip_documents_liens AS lien", "rub.id_rubrique = lien.id_objet AND lien.objet='rubrique' AND lien.id_document=fille.id_document AND rub.date_tmp <= fille.date AND fille.mode='document' $postdates ", "rub.id_rubrique");
 	while ($row = sql_fetch($r))
 	  sql_updateq('spip_rubriques', array('statut_tmp'=>'publie', 'date_tmp'=>$row['date_h']),"id_rubrique=".$row['id']);
 	
diff --git a/ecrire/inc/tourner.php b/ecrire/inc/tourner.php
index 3338065ebb..00da3308b9 100644
--- a/ecrire/inc/tourner.php
+++ b/ecrire/inc/tourner.php
@@ -28,7 +28,7 @@ function inc_tourner_dist($id_document, $document, $script, $flag, $type)
 
 	$prim = 'id_' . $type;
 	// si pas de doc le hash sera inutilisable
-	$id = intval(sql_getfetsel($prim, 'spip_documents_liens', "id_document = " . intval($id_document)));
+	$id = intval(sql_getfetsel('id_objet', 'spip_documents_liens', "objet=".sql_quote($type)." AND id_document = " . intval($id_document)));
 
 	$titre = $document['titre'];
 	$id_vignette = $document['id_vignette'];
diff --git a/ecrire/inc_version.php b/ecrire/inc_version.php
index 4c49677b9f..782bdfc494 100644
--- a/ecrire/inc_version.php
+++ b/ecrire/inc_version.php
@@ -315,9 +315,9 @@ $liste_des_authentifications = array(
 $spip_version_branche = "2.0.0 dev";
 // version des signatures de fonctions PHP
 // (= numero SVN de leur derniere modif cassant la compatibilite et/ou necessitant un recalcul des squelettes)
-$spip_version_code = 11911;
+$spip_version_code = 12008;
 // version de la base SQL (= numero SVN de sa derniere modif)
-$spip_version_base = 11974;
+$spip_version_base = 12008;
 
 // version de l'interface a la base
 $spip_sql_version = 1;
diff --git a/ecrire/maj/svn10000.php b/ecrire/maj/svn10000.php
index a5e40ec526..0b487f8e7e 100644
--- a/ecrire/maj/svn10000.php
+++ b/ecrire/maj/svn10000.php
@@ -123,7 +123,7 @@ array('sql_update','spip_groupes_mots',array('tables_liees'=>"concat(tables_liee
 
 // Reunir en une seule table les liens de documents
 //  spip_documents_articles et spip_documents_forum
-function maj_11974 () {
+function maj_12008 () {
 	// Creer spip_documents_liens
 	global $tables_auxiliaires;
 	include_spip('base/auxiliaires');
@@ -136,6 +136,10 @@ function maj_11974 () {
 		OR $s = sql_select('*', 'spip_documents_'.$l)) {
 			$tampon = array();
 			while ($t = sql_fetch($s)) {
+				// transformer id_xx=N en (id_objet=N, objet=xx)
+				$t['id_objet'] = $t["id_$l"];
+				$t['objet'] = $l;
+				unset($t["id_$l"]);
 				$keys = '('.join(',',array_keys($t)).')';
 				$tampon[] = '('.join(',', array_map('sql_quote', $t)).')';
 				if (count($tampon)>100) {
@@ -149,16 +153,29 @@ function maj_11974 () {
 		}
 	}
 }
-$GLOBALS['maj'][11974] = array(array('maj_11974'));
-
-
-
-
 
+$GLOBALS['maj'][12008] = array(
+//array('sql_drop_table',"spip_documents_liens"), // tant pis pour ceux qui ont joue a 11974
+array('sql_alter',"TABLE spip_documents_liens DROP PRIMARY KEY"),
+array('sql_alter',"TABLE spip_documents_liens ADD id_objet bigint(21) DEFAULT '0' NOT NULL AFTER id_document"),
+array('sql_alter',"TABLE spip_documents_liens ADD objet VARCHAR (25) DEFAULT '' NOT NULL AFTER id_objet"),
+array('sql_update','spip_documents_liens',array('id_objet'=>"id_article",'objet'=>"'article'"),"id_article IS NOT NULL AND id_article>0"),
+array('sql_update','spip_documents_liens',array('id_objet'=>"id_rubrique",'objet'=>"'rubrique'"),"id_rubrique IS NOT NULL AND id_rubrique>0"),
+array('sql_update','spip_documents_liens',array('id_objet'=>"id_breve",'objet'=>"'breve'"),"id_breve IS NOT NULL AND id_breve>0"),
+array('sql_update','spip_documents_liens',array('id_objet'=>"id_auteur",'objet'=>"'auteur'"),"id_auteur IS NOT NULL AND id_auteur>0"),
+array('sql_update','spip_documents_liens',array('id_objet'=>"id_forum",'objet'=>"'forum'"),"id_forum IS NOT NULL AND id_forum>0"),
+array('sql_alter',"TABLE spip_documents_liens ADD PRIMARY KEY  (id_document,id_objet,objet)"),
+array('sql_alter',"TABLE spip_documents_liens DROP id_article"),
+array('sql_alter',"TABLE spip_documents_liens DROP id_rubrique"),
+array('sql_alter',"TABLE spip_documents_liens DROP id_breve"),
+array('sql_alter',"TABLE spip_documents_liens DROP id_auteur"),
+array('sql_alter',"TABLE spip_documents_liens DROP id_forum"),
+array('maj_12008'),
+);
 
 
 // penser a ajouter ici destruction des tables spip_documents_articles etc
-// une fois qu'on aura valide la procedure d'upgrade 11974
+// une fois qu'on aura valide la procedure d'upgrade 12008
 
 
 // penser a ajouter ici destruction des champs articles breves rubriques et syndic
diff --git a/ecrire/public/boucles.php b/ecrire/public/boucles.php
index 37896f01d9..16da582f82 100644
--- a/ecrire/public/boucles.php
+++ b/ecrire/public/boucles.php
@@ -173,11 +173,7 @@ function boucle_DOCUMENTS_dist($id_boucle, &$boucles) {
 	// ces complications (et tant pis si la boucle n'a pas prevu de
 	// verification du statut de l'article)
 	if (!$boucle->modificateur['tout']
-	AND !$boucle->modificateur['criteres']['id_article']
-	AND !$boucle->modificateur['criteres']['id_breve']
-	AND !$boucle->modificateur['criteres']['id_rubrique']
-	AND !$boucle->modificateur['criteres']['id_forum']
-	AND !$boucle->modificateur['criteres']['id_document']
+	AND !$boucle->modificateur['criteres']['id_objet']
 	) {
 		# Espace avant LEFT JOIN indispensable pour insertion de AS
 		# a refaire plus proprement
@@ -186,13 +182,14 @@ function boucle_DOCUMENTS_dist($id_boucle, &$boucles) {
 		$boucle->from[$id_table] = "spip_documents LEFT JOIN spip_documents_liens AS l
 			ON $id_table.id_document=l.id_document
 			LEFT JOIN spip_articles AS aa
-				ON l.id_article=aa.id_article
+				ON (l.id_objet=aa.id_article AND l.objet=\'article\')
 			LEFT JOIN spip_breves AS bb
-				ON l.id_breve=bb.id_breve
+				ON (l.id_objet=bb.id_breve AND l.objet=\'breve\')
 			LEFT JOIN spip_rubriques AS rr
-				ON l.id_rubrique=rr.id_rubrique
+				ON (l.id_objet=rr.id_rubrique AND l.objet=\'rubrique\')
 		";
-
+		$boucle->group[] = "$id_table.id_document";
+		
 		if ($GLOBALS['var_preview']) {
 			array_unshift($boucle->where,"\"(aa.statut IN ('publie','prop') OR bb.statut  IN ('publie','prop') OR rr.statut IN ('publie','prive'))\"");
 		} else {
-- 
GitLab