2016-11-16 2 views
1

У меня есть три модели, Advertiser, PtcAd и PtcCampaign. При удалении Рекламодатель Я хочу удалить все связанные PtcAds и PtcCampaigns. Рекламодатель имеет множество PtcCampaigns через PtcAds.Удалить hasManyThrough relatioship rows using Laravel's Eloquent

Рекламодатель Модель

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 Модель

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 Модель

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'); 
} 

Мои тесты:

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)); 
} 

$this->assertFalse(PtcCampaign::all()->contains($ptcCampaign)) в тесте test_delete_advertiser() не удается, почему?

У меня есть больше тестов, чтобы убедиться, что все отношения работают, поэтому я действительно не знаю, что может быть неправильно. Моей следующей попыткой было бы сделать foreach в методе delete() рекламодателя, но, возможно, есть что-то более простое, и я хочу понять, почему это не работает.

ответ

1

Похоже, проблема связана с последовательностью инструкции delete.

Try путем изменения последовательности, как показано ниже:

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

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

    return parent::delete(); 
} 
+0

Это делает его! Спасибо! Теперь у меня есть другой связанный вопрос, так как модель 'PtcAd' имеет метод' delete() ', настроенный для удаления' PtcCampaign 'в отношении, почему мне нужно вызвать' $ this-> ptcCampaigns() -> delete(); 'из модели« Рекламодатель »? Разве это не цепь? – DanVeira

+1

Когда вы делаете '$ this-> ptcAds() -> delete()', он создает запрос и удаляет строки, чтобы он вызывал класс построителя запросов 'delete'. Но если вы удалите 'ptcAds' с помощью' foreach', тогда он вызывает функцию delete класса Model, и он также удалит 'ptcCampaigns'. –

1

Вы можете использовать Модель события Laravel (в deleting), чтобы удалить связанные модели, как это:

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... 
     }); 
    } 
} 

Надеется, что это помогает!

Смежные вопросы