Dupliquer un modèle avec l’ensemble de ses relations dans Laravel

Dans nos projets, il arrive régulièrement d’avoir besoin de dupliquer les enregistrements d’une table avec l’ensemble de ses relations pour effectuer une sauvegarde ou bien créer une nouvelle entité à partir d’une existante.

C’est la problématique que nous avons rencontré sur un de nos projets Laravel. Notre client avait besoin d’un logiciel à destination de quelques milliers d’utilisateurs leur permettant de créer facilement des DUERP qui sont des documents obligatoires pour les entreprises lié à la gestion des risques. Ces documents consistent à lister les risques qu’encourent les employés et à définir pour chacun des mesures à mettre en place pour les limiter.

D’un point de vue développement, nous avons créé une base de données ressemblant à ceci :

Une table Document avec une relation OneToMany vers Risque avec elle-même une relation OneToMany vers Mesure .

Pour dupliquer un modèle, Laravel nous fournit la méthode replicate() qui permet de choisir les attributs à répliquer mais pour ce qui est des relations ça se complique, il faut obligatoirement pour chaque relations oneToMany parcourir l’ensemble des valeurs, les répliquer et spécifier manuellement les clefs étrangères correspondante. Ce qui peut devenir rapidement assez lourd à mettre en place.

C’est là qu’intervient le package cloner de BKWLD qui va bien nous simplifier la vie. Il nous fournis la méthode duplicate() applicable sur nos modèles utilisant le package.

Il suffit de paramétrer les relations que l’on veut dupliquer dans nos modèles et le tour est joué.

Dans notre exemple, le modèle de document devient :

class Document extends Model
{
    use  HasApiTokens, HasFactory;
		// Spécifie que le modèle est clonable
    use \\Bkwld\\Cloner\\Cloneable;

    protected $fillable = ['id','statut','nom', ...];

    // Décrit les relations qui vont être clonées lors 
    // de l'appel de la méthode duplicate()
    protected $cloneable_relations = ['risques'];

    public function risques(): hasMany
    {
        return $this->hasMany(Risque::class);
    }
}

On fait de même pour nos relations enfants ici pour les Mesures dans le modèle Risque :

protected $cloneable_relations = ['mesures'];

Enfin il ne reste plus qu’à appeler la méthode duplicate() où l’on en a besoin et celle-ci va dupliquer notre document, nos risques et nos mesures et connecter chaque éléments comme il le sont dans le modèle de base.

$document= Document::find(1);
$clone = $document->duplicate();

Le package offre également d’autre fonctionnalité comme de choisir les attributs à ne pas dupliquer si besoin. Pour en savoir plus voici le lien GitHub du package : https://github.com/BKWLD/cloner

Pour conclure, Cloner est un outil qui est entré de notre toolkit de développeur Laravel, il est simple, efficace et semble maintenu régulièrement.