2015-07-08 6 views
14

Ho 2 modelli che sono uniti da una relazione che ha una chiave composta - questi sono Prodotto e Categoria. Devo utilizzare eliminazioni software su tutte le tabelle, in modo che i modelli e le relazioni possano essere ripristinati, se necessario.Soft eliminazione/scollegamento e ripristino/associazione di relazioni con i tasti compositi

Nel mio modello prodotto che ho:

function categories() 
{ 
    return $this->belongsToMany('App\Category', 'product_categories')->whereNull('product_categories.deleted_at')->withTimestamps(); 
} 

nella mia categoria modello che ho:

function products() 
{ 
    return $this->belongsToMany('App\Product', 'product_categories')->whereNull('product_categories.deleted_at')->withTimestamps(); 
} 

ho letto altrove su concatenamento il metodo whereNull, come query come $category->products->contains($product->id) sono stati altrimenti tornando il soft relazioni cancellate.

La mia domanda è qual è il modo migliore per gestire l'eliminazione e il ripristino di queste relazioni eliminate dall'utente? Per il ripristino, per esempio, ho provato:

$product->categories()->restore($category_id); 

che questo prodotto un errore SQL dicendo che il campo deleted_at era ambigua (perché è entrato nel tavolo categorie a product_categories).

Aggiornamento - Sembra che il problema principale è che la classe BelongsToMany non supporta eliminazioni soffici - così attaccare, staccare e sincronizzare tutti eseguire eliminazioni duri. Quale sarebbe l'approccio migliore per ignorare questa classe?

risposta

5

In sostanza, non ci sarà un solo deleted_at campo e invece di utilizzare il $product->categories() uso due personalizzati metodi (comuni) sia (Product e Category) modelli per esempio, è possibile creare un tratto come questo:

// SoftDeletePC.php 
trait SoftDeletePC { 
    // SoftDelete 
    public function softDeleteProductCategory($productId, $categoryId) 
    { 
     \DB::table('product_categories') 
     ->where('product_id', $productId) 
     ->where('category_id', $categoryId) 
     ->update(['deleted_at' => \DB::raw('NOW()')]); 
    } 

    // Restore 
    public function restoreProductCategory($productId, $categoryId) 
    { 
     \DB::table('product_categories') 
     ->where('product_id', $productId) 
     ->where('category_id', $categoryId) 
     ->update(['deleted_at' => null]); 
    } 
} 

quindi utilizzare questa caratteristica in entrambi i modelli utilizzando use TraitProductCategory e chiamare il metodo da entrambi i modelli, ad esempio:

// App/Product.php 
class product extends Model { 
    use SoftDeletePC; 
} 

// App/Category.php 
class Category extends Model { 
    use SoftDeletePC; 
} 

Così, invece di utilizzare questo:

Product->find(1)->categories()->restore(2); 

È possibile utilizzare qualcosa di simile:

$product = Product->find(1); 

$product->softDeleteProductCategory(1, 2); // Set timestamp to deleted_at 

$product->restoreProductCategory(1, 2); // Set null to deleted_at 

Spero che questo può funzionare per voi.

+0

grazie per il suggerimento. Ho appena iniziato con Laravel e non ho mai incontrato caratteristiche particolari. Il tuo approccio è in realtà simile a quello che ho scoperto, cioè metodi personalizzati per gestirlo. Idealmente, mi piacerebbe semplicemente che i metodi predefiniti supportino le eliminazioni software, anche se, onestamente, non sono sicuro di quanto sia fattibile. Pubblicherò come risposta la mia versione di sincronizzazione che ho creato. – BrynJ

1

Ho finito per creare alcuni metodi personalizzati nel mio modello di prodotto per realizzare ciò che richiedevo, non la mia soluzione ideale, ma funziona comunque. La mia sincronizzazione personalizzata simile a questa:

class Product extends Model 
{ 
    // update relationship to categories 
    function categories_sync($category_ids) 
    { 
     // categories 
     $existing_category_ids = $this->categories()->lists('category_id')->all(); 
     $trashed_category_ids = $this->categories('onlyTrashed')->lists('category_id')->all(); 

     if(is_array($category_ids)) { 

      foreach($category_ids as $category_id) { 
       if(in_array($category_id, $trashed_category_ids)) { 
        $this->categories()->updateExistingPivot($category_id, ['deleted_at' => null]); 
       } 
       elseif(!in_array($category_id, $existing_category_ids)) { 
        $this->categories()->attach($category_id); 
       } 
      } 

      foreach($existing_category_ids as $category_id) { 
       if(!in_array($category_id, $category_ids)) { 
        $this->categories()->updateExistingPivot($category_id, ['deleted_at' => date('YmdHis')]); 
       } 
      } 
     } 
     else { 
      foreach($existing_category_ids as $category_id) { 
       $this->categories()->updateExistingPivot($category_id, ['deleted_at' => date('YmdHis')]); 
      } 
     } 
    } 
} 

È possibile che si basa su un categorie estesi() metodo:

// relationship to categories 
function categories($trashed=false) 
{ 
    if($trashed=='withTrashed') { 
     return $this->belongsToMany('App\Category', 'product_categories')->withTimestamps(); 
    } 
    elseif($trashed=='onlyTrashed') { 
     return $this->belongsToMany('App\Category', 'product_categories')->whereNotNull('product_categories.deleted_at')->withTimestamps(); 
    } 
    else { 
     return $this->belongsToMany('App\Category', 'product_categories')->whereNull('product_categories.deleted_at')->withTimestamps(); 
    } 
} 
Problemi correlati