Proposer une corbeille et une annulation pour les suppressions

Une des fonctionnalité les plus utiles disponibles sur toute application de bureau est la possibilité d’annuler les suppressions de données. Sur les systèmes d’exploitation, il existe une corbeille qui liste les éléments effacés et permet de les restaurer.

Nous souhaitons proposer une solution équivalente sur un site CakePHP, avec une corbeille et un lien “Annuler” lors de la suppression d’un enregistrement. Si la taille de la base de données n’est pas une préoccupation cruciale sur un projet, cette fonctionnalité est extrêmement appréciable.

Partons d’un blog avec des articles. Nous avons créé une interface pour gérer l’ajout, la modification et la suppression des articles, et nous souhaitons que lorsque l’utilisateur supprime un article, le message de confirmation fasse apparaître un lien “Annuler”. Nous souhaitons également faire apparaître une petite corbeille sous la liste des articles : un clic sur la corbeille nous mène sur la liste des articles supprimés, que nous pouvons soit restaurer soit supprimer définitivement.

Nous allons utiliser un Behavior (Comportement) créé par Mariano Iglesias : Soft Deletable Behavior. Ce Comportement va prendre le pas sur les actions de suppression (un simple champ numérique passera de 0 à 1 en cas de suppression) et les actions de sélection (une restriction sera ajoutée sur la valeur de ce même champ numérique).

1. Mise en place

1.1. Installation du Comportement

Nous téléchargeons le Comportement et installons le fichier soft_deletable.php dans le répertoire {app}/models/behaviors/

1.2. Modification du schéma de la table

Le Comportement Soft Deletable a besoin de deux champs supplémentaires dans la table concernée pour pouvoir fonctionner : un champ numérique qui passera de la valeur 0 (enregistrement non effacé) à 1 (enregistrement effacé) et un champ date qui aura pour valeur l’éventuelle date de suppression de l’enregistrement. Le nom de ces champs n’a pas d’importance, il suffira de renseigner le Comportement sur les noms choisis.

ALTER TABLE `articles`
ADD `supprime` TINYINT(1) UNSIGNED NOT NULL,
ADD `date_suppression` DATETIME NOT NULL;

1.3. Configuration du Comportement

Nous allons indiquer au Modèle Article qu’il doit calquer son comportement sur celui du Soft Deletable :

1
2
3
4
5
6
7
8
9
10
11
12
// {app}/models/article.php
class Article extends AppModel
{
  var $name = "Article";
 
  var $actsAs = array(
    'SoftDeletable' => array(
      'field' => 'supprime',
      'field_date' => 'date_suppression'
    )
  );
}

2. Gestion des articles

2.1 Liste des articles

Commençons par la liste des articles du blog. Voyons l’action index, qui passe simplement à la Vue la liste des articles classés par date de création décroissante :

1
2
3
4
5
6
// {app}/controllers/articles_controller.php
function index()
{
  $articles = $this->Article->findAll(null, null, 'created DESC');
  $this->set('articles', $articles);
}

Si nous regardons le dump MySQL (debug = 2), nous constatons que le Comportement a rajouté de lui-même une restriction sur la sélection des articles : " AND `Article`.`supprime` != 1" : nous avons donc bien sous les yeux la liste des articles non supprimés.

Notre Vue affiche la liste des articles : pour chacun, nous avons un lien vers l’édition de l’article (action edit($id), tout à fait classique) et un lien vers sa suppression (action delete($id)).

2.2. Suppression d’un enregistrement et annulation

Nous n’avons ici rien à changer au processus habituel de suppression, nous appelons toujours la méthode Model::delete($id), c’est le Comportement qui va se charger de prendre la main et de ne pas réellement supprimer l’article, mais de changer la valeur des champs supprime et date_suppression. La seule chose que nous allons changer, c’est le message de confirmation de suppression qui va maintenant faire apparaître un lien “Annuler”, et ce lien pointera vers une action undelete ajoutée par le Comportement qui rétablira la valeur des champs supprime et date_suppression à 0.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// {app}/controllers/articles_controller.php
 
// Action de suppression
function delete($id)
{
  // Suppression : le Comportement prendra la main.
  $this->Article->delete($id);
 
  // Construction du lien "Annuler" :
  $undo_url  = Router::url(array('controller' => 'articles', 'action' => 'undelete', $id));
  $undo_link = '<a href="'.$undo_url.'">Annuler</a>';
 
  // Message de confirmation, avec le lien "Annuler" :
  $this->Session->setFlash('Article effacé. '.$undo_link, 'message_ok');
 
  // Redirection vers la liste des articles :
  $this->redirect(array('action' => 'index'));
}
 
// Action de restauration
function undelete($id)
{
  // Méthode de restauration ajoutée par le Comportement :
  $this->Article->undelete($id);
 
  // Message de confirmation :
  $this->Session->setFlash('Article restauré.', 'message_ok');
 
  // Redirection vers la liste des articles :
  $this->redirect(array('action' => 'index'));
}

3. La corbeille

Nous allons maintenant voir comment créer une corbeille qui va lister les articles supprimés et permettre de les restaurer.

3.1 Liste des enregistrements supprimés

Nous créons une action index_deleted, notre corbeille, qui ressemble beaucoup à l’action index, à ceci près que nous forçons l’affichage des articles dont le champ supprime a pour valeur 1, et que nous les classons par ordre de date de suppression décroissante.

1
2
3
4
5
6
// {app}/controllers/articles_controller.php
function index_deleted()
{
  $articles = $this->Article->findAll(array('supprime' => 1), null, 'date_suppression DESC');
  $this->set('articles', $articles);
}

3.2 Suppression définitive d’un enregistrement

Dans notre corbeille (la liste des articles supprimés), nous pouvons ajouter à côté de chaque article un lien vers une action de suppression définitive fournie par le Comportement. Nous pouvons également prévoir un lien pour vider définitivement la corbeille, qui va supprimer réellement tous les articles de la corbeille. Voyons ces deux actions :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// {app}/controllers/articles_controller.php
 
// Suppression définitive d'un article :
function hard_delete($id)
{
  // Méthode de suppression réelle ajoutée par le Comportement :
  $this->Article->hardDelete($id);
 
  // Message de confirmation :
  $this->Session->setFlash('Article supprimé définitivement.', 'message_ok');
 
  // Redirection vers la corbeille :
  $this->redirect(array('action' => 'index_deleted'));
}
 
// Vider la corbeille
function empty_bin()
{
  // Méthode de suppression réelle ajoutée par le Comportement :
  $this->Article->purge();
 
  // Message de confirmation :
  $this->Session->setFlash('Corbeille vidée.', 'message_ok');
 
  // Redirection vers la liste des articles :
  $this->redirect(array('action' => 'index'));
 
}

Merci encore à Mariano Iglesias pour ce Comportement qui une fois essayé, est adopté.

Pierre-Emmanuel Fringant

Participez