[spip-dev] Suppression automatique des pièces jointes des articles mis à la poubelle sauf si elles sont utilisées dans d'autres articles

Un article qui a été mis à la poubelle est supprimé physiquement de la base de
données 24 heures après par un mécanisme d’optimisation de la base. Toutefois
les pièces jointes de cet article ne sont pas supprimées par SPIP. En effet, les
concepteurs de SPIP indiquent dans leur forum qu’il est possible d’insérer dans
le texte d’un article un lien vers une pièce jointe d’un autre article et que
dans ce cas la suppression de la pièce jointe serait préjudiciable à l’article
qui contient le lien. Ainsi, on risque d’avoir un volume croissant de pièces
jointes devenues inutiles.

Aussi, j’ai modifié une partie du code du fichier ecrire/inc_optimiser.php3 de
SPIP afin d’obtenir le fonctionnement suivant :

a) si les pièces jointes à l’article, qui a été mis à la poubelle, ne sont pas
utilisées dans le texte d’autres articles (lien ou ou ), alors l’article et ses
pièces jointes sont supprimés au moins 24 heures après.

b) si les pièces jointes à l’article, qui a été mis à la poubelle, sont
utilisées dans le texte d’autres articles (lien ou ou ), alors l’article et ses
pièces jointes ne sont pas supprimés. En effet, si l’article était supprimé, on
n’aurait plus la possibilité de supprimer manuellement ses pièces jointes.

Dans ecrire/inc_optimiser.php3

Remplacer les lignes suivantes (50 à 55) :

//
// Articles
//

$query = "DELETE FROM spip_articles WHERE statut='poubelle' AND maj < $mydate";
spip_query($query);

par le code suivant :

//
// Articles
//

//---------------- Début ajout ----------------
// On désactive l’ancien code
// $query = "DELETE FROM spip_articles WHERE statut='poubelle' AND maj <
$mydate";
// spip_query($query);

// pour effacer les documents joints aux articles à supprimer
// lister les articles à supprimer
$query = "SELECT id_article FROM spip_articles WHERE statut='poubelle' AND maj <
$mydate";
$result = spip_query($query);
while ($row = spip_fetch_array($result)) $ciarticles[] = $row['id_article'];

        if ($ciarticles) {
                $ciarticles = join(",", $ciarticles);

       // lister les documents joints aux articles à supprimer
                $query = "SELECT id_document FROM spip_documents_articles WHERE
id_article IN ($ciarticles)";
           $result = spip_query($query);
           while ($row = spip_fetch_array($result))
       {
           $iddocument = $row['id_document'];

                        $utile = false;

           // vérifier si les documents ne sont pas utilisés dans le texte
d'autres articles
               $querydoc = "SELECT id_article FROM spip_articles WHERE
statut!='poubelle' AND (texte LIKE '%<doc$iddocument|%' OR texte LIKE
'%<emb$iddocument|%' OR texte LIKE '%<img$iddocument|%')";
               $resultdoc = spip_query($querydoc);
                        if ($row = @spip_fetch_array($resultdoc)) {
               $cidocschindler[] = $iddocument;
           } else {
               $cidocuments[] = $iddocument;
           }
       }

       // supprime les documents joints aux articles à supprimer sauf s'ils sont
utilisés dans le texte d'autres articles
           if ($cidocuments) {
                   $cidocuments = join(",", $cidocuments);

               $query = "SELECT id_document, id_vignette, fichier FROM
spip_documents WHERE id_document IN ($cidocuments)";
               $result = spip_query($query);
               while ($row = spip_fetch_array($result)) {
                       $fichier = $row['fichier'];
               $fichier = "../".$fichier;
                       $id_document = $row['id_document'];
                       $id_vignette = $row['id_vignette'];
                       spip_query("DELETE FROM spip_documents WHERE
id_document=$id_document");
                       spip_query("UPDATE spip_documents SET id_vignette=0 WHERE
id_vignette=$id_document");
                       spip_query("DELETE FROM spip_documents_articles WHERE
id_document=$id_document");
                       @unlink($fichier);

                   if ($id_vignette > 0) {
                           $query = "SELECT id_vignette, fichier FROM
spip_documents WHERE id_document=$id_vignette";
                           $result = spip_query($query);
                           if ($row = spip_fetch_array($result)) {
                                   $fichier = $row['fichier'];
                                   @unlink($fichier);
                           }
                           spip_query("DELETE FROM spip_documents WHERE
id_document=$id_vignette");
                           spip_query("DELETE FROM spip_documents_articles WHERE
id_document=$id_vignette");
                   }
               }
       }
   }

           if ($cidocschindler) {
                        $cidocschindler = join(",", $cidocschindler);
                        $query = "SELECT id_article FROM spip_documents_articles
WHERE id_document IN ($cidocschindler)";
                        $result = spip_query($query);
                        while ($row = spip_fetch_array($result))
$ciartschindler[] = $row['id_article'];

                        $ciartschindler = join(",", $ciartschindler);
                        $query = "DELETE FROM spip_articles WHERE
statut='poubelle' AND maj < $mydate AND id_article NOT IN ($ciartschindler)";
                        spip_query($query);
           } else {
                        $query = "DELETE FROM spip_articles WHERE
statut='poubelle' AND maj < $mydate";
                        spip_query($query);
           }

//--------------- Fin ajout --------------------

Interessant, mais gros traitement ...
En plus, je ne crois pas que mysql soit très performent sur les requetes
"like %".

Personnellement, je serai plus pour gerer une table des associations entre
les documents "embarqués" et les articles.
Le traitement est alors appliqué à un seul article et uniquement au moment
de sa sauvegarde.
C'est comme ca que les formulaires du lab sont gérés.

Après on peut mettre en place une securité demandant quoi faire en cas de
suppression d'un document (ou des documents d'un article qu'on supprime).
1) l'utilisateur peut tout de suite connaitre les consequences (le document
XXX est utilisé dans les articles XX et YY)
2) on peut eventuellement lui proposer de raccrocher les documents aux
premiers articles associés trouvés.

Le gros interet, c'est qu'on ne fait pas un gros traitement d'optimisation
mais un petit traitement à la modification.
en plus, c'est sur une action de l'espace redaction (si je supprime un
article avec 50 documents, je peux comprendre que le traitement soit un peu
long, quand je visite un site, je ne comprend pas pourquoi il y a des
lenteurs de temps en temps).

Mes 2 cents ...
@++

Selon equipement <christophe.imberti@equipement.gouv.fr>:

un simple lien pouvait suffire....

http://www.spip-contrib.net/article865.html

Sur l'aspect performance :
- j'effectue une requête avec "like%" uniquement si au moins un article à été
mis la poubelle.
- par ailleurs, la recherche full texte de SPIP utilise également "like %" dans
ses requêtes (ecrire/recherche.php3).

Sur le principe de la fonctionnalité :
- je ne souhaite pas modifier le modèle de données de SPIP, aussi je n'ai pas
envisagé une table des associations.
- si l'on accepte de modifier le modèle de données de SPIP, ta solution est
clairement plus performante.

Personnellement, je serai plus pour gerer une table des associations
entre les documents "embarqués" et les articles.

C'était fait dans ma table des liens internes entre éléments SPIP, mais ça n'a pas été adopté, car je n'avais fait que la partie remplissage de la table, et pas les interfaces permettant d'afficher ces données ou de bloquer les suppressions.

J'avais envoyé le code sur la liste, ça doit être quelque part dans les archives.

-Nicolas

C'était fait dans ma table des liens internes entre éléments SPIP, mais
ça n'a pas été adopté, car je n'avais fait que la partie remplissage de
la table, et pas les interfaces permettant d'afficher ces données ou de
bloquer les suppressions.

J'avais envoyé le code sur la liste, ça doit être quelque part dans les
archives.

Je vais fouiller un peu alors ...

On doit pouvoir generaliser l'ajout et la suppression des liens à
l'enregistrement pour gerer les insertions "inline".
Au passage, on pourrait aussi supprimer ou modifier les entrées dans les
tables spip_documents_xxx à la suppression des articles, breves et rubriques
et se passer du traitement d'optimisation

Qu'en pensent nos "core-dev" préférés sur le principe ?
Je suppose que le traitement par "optimisation" n'a pas été mis en place
pour rien ...

@++

PS : en attendant, la solution de Christophe a l'air efficace et il est
plutot rassurant sur les perfs, ca merite d'etre testé sur un hebergeur
gratuit avec une grosse base.
A ce propos, j'ai vu passé la question il y a peu : ne peut on pas disposer
d'une base de test (genre le contenu de spip-contrib ou une base bidon ou
encore mieux, un script qui genere un contenu type) ?
Perso, j'ai des comptes free avec plein de place pour mes tests, mais pas de
gros contenu à mettre dedans pour tester ...

J'avais envoyé le code sur la liste, ça doit être quelque part dans les
archives.

>

Je vais fouiller un peu alors ...

J'ai retrouvé ça :
http://thread.gmane.org/gmane.comp.web.spip.devel/12944

-Nicolas

Cool, je vais regarder ca.
Mais j'ai dans l'idée qu'il faut traiter le "type" de liaison
(article/document, breve/document, article/toto ...) qqpart pour ne pas
retomber dans x tables comme les documents_xxxs
ou au moins faire une table par "contenant" et gerer le type de contenu
(document, autre ...)

Je vais creuser de ce coté je pense.

Merci.
@++

Mais j'ai dans l'idée qu'il faut traiter le "type" de liaison
(article/document, breve/document, article/toto ...) qqpart pour ne pas
retomber dans x tables comme les documents_xxxs

C'est ce qui est fait.

Loin de moi l'idée de lancer un nouveau troll, mais c'est ce qui a été adopté dans SPIP-Agora, avec juste l'abstraction de données appliquée.

Exemple de rendu quand un autre article pointe vers l'article courant :
http://www.gasteroprod.com/data/spip/spip_liens_internes.png

-Nicolas