2016-11-16 1 views
1

J'ai trois modèles, Advertiser, PtcAd et PtcCampaign. Lors de la suppression d'un Annonceur Je veux supprimer tous les connexes PtcAds et PtcCampaigns. Le Annonceur a beaucoup PtcCampaigns à PtcAds.Supprimer hasManyThrough lignes de relation en utilisant Eloquent de Laravel

Annonceur Modèle

use SoftDeletes; 

protected $dates = ['deleted_at']; 

public function ptcAds() 
{ 
    return $this->hasMany('App\PtcAd'); 
} 

public function ptcCampaigns() 
{ 
    return $this->hasManyThrough('App\PtcCampaign', 'App\PtcAd'); 
} 

public function delete() 
{ 
    $this->ptcAds()->delete(); 
    // I'VE TRIED WITH AND WITHOUT THIS 
    $this->ptcCampaigns()->delete(); 

    return parent::delete(); 
} 

PtcAd Modèle

use SoftDeletes; 

protected $fillable = ['advertiser_id', 'title']; 

protected $dates = ['deleted_at']; 

public function advertiser() 
{ 
    return $this->belongsTo('App\Advertiser'); 
} 

public function ptcCampaigns() 
{ 
    return $this->hasMany('App\ptcCampaign'); 
} 

public function delete() 
{ 
    $this->ptcCampaigns()->delete(); 

    return parent::delete(); 
} 

PtcCampaign Modèle

use SoftDeletes; 

public $timestamps = false; 

protected $fillable = ['ptc_ad_id', 'clicks']; 

protected $dates = ['paused_at', 'deleted_at']; 

public function ptcAd() 
{ 
    return $this->belongsTo('App\PtcAd'); 
} 

Mes tests:

public function test_delete_advertiser() 
{ 
    $advertiser = factory(Advertiser::class)->create(); 

    $ptcAd = factory(PtcAd::class)->create(['advertiser_id' => $advertiser->id]); 

    $ptcCampaign = factory(PtcCampaign::class)->create(['ptc_ad_id' => $ptcAd->id]); 

    $this->assertTrue($advertiser->delete()); 
    $this->assertFalse(Advertiser::all()->contains($advertiser)); 
    $this->assertFalse(PtcAd::all()->contains($ptcAd)); 

    // THE FOLLOWING TEST DOESN'T WORK! 
    $this->assertFalse(PtcCampaign::all()->contains($ptcCampaign)); 
} 

// ALL OF THE FOLLOWING TESTS WORK! 
public function test_delete_ad() 
{ 
    $ptcAd = factory(PtcAd::class)->create(); 

    $ptcCampaign = factory(PtcCampaign::class)->create(['ptc_ad_id' => $ptcAd->id]); 

    $this->assertTrue($ptcAd->delete()); 
    $this->assertFalse(PtcAd::all()->contains($ptcAd)); 
    $this->assertFalse(PtcCampaign::all()->contains($ptcCampaign)); 
} 

Le $this->assertFalse(PtcCampaign::all()->contains($ptcCampaign)) dans le test échoue test_delete_advertiser(), pourquoi?

J'ai plus de tests pour m'assurer que toutes les relations fonctionnent donc je ne sais vraiment pas ce qui pourrait éventuellement être faux. Ma prochaine tentative serait de faire foreach dans la méthode delete() de l'Annonceur mais peut-être qu'il y a quelque chose de plus simple et je veux comprendre pourquoi cela ne fonctionne pas.

Répondre

1

Il semble que le problème réside dans la séquence de l'instruction delete.

Essayez en changeant la séquence comme ci-dessous:

public function delete() 
{ 
    $this->ptcCampaigns()->delete(); 

    $this->ptcAds()->delete(); 

    return parent::delete(); 
} 
+0

qui le fait! Je vous remercie! Maintenant j'ai une autre question connexe, puisque le modèle 'PtcAd' a la méthode' delete() 'configurée pour supprimer' PtcCampaign's dans la relation, pourquoi ai-je besoin d'appeler '$ this-> ptcCampaigns() -> delete(); 'à partir du modèle' Advertiser'? Ne devrait-il pas enchaîner? – DanVeira

+1

Lorsque vous faites $ this-> ptcAds() -> delete() 'il crée une requête et supprime les lignes de sorte qu'il appelle la classe builder de la fonction' delete'. Mais si vous supprimez 'ptcAds' en utilisant' foreach', alors il appelle la fonction de suppression de la classe Model et supprime également 'ptcCampaigns'. –

1

Vous pouvez utiliser les événements du modèle de Laravel (deleting) pour supprimer les modèles connexes comme ceci:

class Advertiser extends Eloquent 
{ 
    public function ptcAds() 
    { 
     return $this->hasMany('PtcAd'); 
    } 

    // this is a recommended way to declare event handlers 
    protected static function boot() { 
     parent::boot(); 

     static::deleting(function($adv) { // before delete() method call this 
      $adv->ptcAds()->delete(); 
      // do the rest of the cleanup... 
     }); 
    } 
} 

// Same for PtcCompaigns 

class PtcAd extends Eloquent 
{ 
    public function ptcCompaigns() 
    { 
     return $this->hasMany('PtcCompaigns'); 
    } 

    // this is a recommended way to declare event handlers 
    protected static function boot() { 
     parent::boot(); 

     static::deleting(function($ptc_ad) { // before delete() method call this 
      $ptc_ad->ptcCompaigns()->delete(); 
      // do the rest of the cleanup... 
     }); 
    } 
} 

Hope this helps!