使用组合键软删除/分离和恢复/附加关系


Soft deleting / detaching and restoring / attaching relationships with composite keys

我有两个模型,它们由一个具有复合键的关系连接—它们是Product和Category。我需要对所有表使用软删除,以便在需要时可以恢复模型和关系。

在我的产品模型中,我有:

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

在我的类别模型中,我有:

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

我在其他地方读到链接whereNull方法,因为像$category->products->contains($product->id)这样的查询否则会返回软删除的关系。

我的问题是什么是最好的方式来处理删除和恢复这些软删除的关系?例如,要恢复,我尝试:
$product->categories()->restore($category_id);

上面的代码产生了一个SQL错误,说deleted_at字段是不明确的(因为它将categories表连接到product_categories)。

Update -似乎根本问题是BelongsToMany类不支持软删除-所以attach, detach和sync都执行硬删除。重写这个类的最佳方法是什么?

基本上,将只有一个deleted_at字段,而不是使用$product->categories()使用两个自定义(通用)方法,例如在(ProductCategory)模型中,您可以创建这样的特征:

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

然后在两个模型中使用use TraitProductCategory并从两个模型中调用该方法,例如:

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

所以,不用这个:

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

你可以这样写:

$product = Product->find(1);
$product->softDeleteProductCategory(1, 2); // Set timestamp to deleted_at
$product->restoreProductCategory(1, 2); // Set null to deleted_at

希望这对你有用

我最终在我的Product模型中创建了一些自定义方法来完成我所需要的-这不是我理想的解决方案,但它仍然有效。我的自定义同步看起来像这样:

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

以上依赖于扩展的categories()方法:

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