OrphanRemoval et Persistance transitive avec Doctrine2

On va voir dans cet article comment supprimer automatiquement des objets qui ne sont plus référencés par leur objet parent.

Prenons l’exemple d’un objet Day qui comporte un ou plusieurs objet Event. Imaginons que nous ayons un formulaire nous permettant d’ajouter et supprimer des objets Events (dans notre formulaire un champ de type Collection) via du javascript. Si on supprime un des éléments de la collection des Event, et qu’on soumet le formulaire, Doctrine2 ne va pas supprimer l’objet tout seul alors que c’est le but souhaité.

Voyons d’abord le principe et comment résoudre ce problème:

Lorsqu’on souhaite qu’une opération soit cascadée le long d’une association, on va indiquer dans le mapping par exemple:
cascade={"persist"}

Mapper une association avec la méthode all en paramètre de cascade applique la possibilité de gérer simplement les associations de type parent/enfant, où la sauvegarde/mise à jour/suppression du parent, entraîne la sauvegarde/mise à jour/suppression de l’enfant ou des enfants.

Doctrine2 ajoute un style de cascade spécial, orphanRemoval, qui s’applique seulement pour les associations 1-n, ou 1-1, cela indique que l’opération de suppression devra être appliquée à n’importe quel enfant dé-référencé de son parent persistant.

Remarque :

Cela n’a pas de sens d’activer cette option sur une association n-1 ou n-n. Les cascades sont souvent utiles pour des associations 1-1 et 1-n.

Si on prend une association de type 1-n, la référence d’un objet enfant d’un parent persistant, aura pour conséquence la sauvegarde et/ou mise à jour de l’enfant.

Cependant, un enfant qui devient orphelin (non référencé) de son parent, n’est pas automatiquement supprimé, sauf si on précise l’option orphanRemoval. Détaillons quelques opérations:

  • Si un parent est passé à persist, tous les enfant sont passés à persist()
  • Si un parent est passé à merge, tous les enfants sont passés à merge()
  • Si un parent est supprimé, tous les enfants sont passés à remove()

Mais si un enfant est dé-référencé par un parent persistant, il ne se passe rien, à moins de passer l’option orphanRemoval, et au quel cas l’enfant est à ce moment là supprimé.

Exemple concret

Implémentation des entités Day et Event.

Notez l’option orphanRemoval dans la relation OneToMany:

Créons ensuite un formulaire pour l’entité Day, on précise que l’on souhaite avoir une collection d’objet Event:

Le code pour le formulaire de Event est classique:

Enfin dans notre page d’édition, directement inspirée de l’exemple du site Symfony2.

On ajoute deux liens pour ajouter et supprimer nos events, respectivement dans le code:
id="add-another-event" et class="delete-event"

Le controller, généré via la commande generate:doctrine:crud, reste basique:

Ainsi on a bien nos objets orphelins qui sont supprimés à la soumission du formulaire.

Partagez cet article