删除多个模型&扩展Eloquent Builder

时间:2015-01-14 12:02:39

标签: php laravel eloquent

我正在制作一个通用函数,它接受属性并删除所有具有这些属性的模型。它在名为BaseModel的类中定义,该类扩展Eloquent,而所有其他模型都扩展它。

模型被检索但是删除它们会生成500但是没有异常细节可以通过try catch块来捕获。似乎该应用程序完全中止了。

代码

/**
 * @param string|array $attributes
 * @param string $value
 * @param string $operator
 * @return int
 */
public static function deleteAllWithAttributes
    ($attributes, $value = '', $operator = '=')
{
    $instance = new static;
    if (is_array($attributes)) {
        foreach ($attributes as $key => $value) {
            $instance = $instance->where($key, $operator, $value);
        }
    } else {
        $instance = $instance->where($attributes, $operator, $value);
    }
    $models = $instance->get();
    foreach ($models as $model) {
        try {
            $model->delete();
        } catch (Exception $e) {
            dd($e);
        }
    }
    return count($models);
}

用法

`[Model class name]::deleteAllWithAttributes([Attribute name], [value], [operator]);`

[Model class name]::deleteAllWithAttributes([Attributes associative array], [operator]);

1 个答案:

答案 0 :(得分:1)

我不会告诉你错误是什么,但绝对不是这样:

  1. 您正在提取 N 行并创建 N 模型
  2. 然后,您逐个删除它们,调用 N 查询
  3. 这一切都是多余的,不会扩大规模。即使没有那么多行,它也可能很慢,因为删除比select更耗时。而是运行2个查询 - 第一个用于count,第二个用于delete

    另外,我extend Eloquent\Builder而非创建静态方法以获得灵活性:

    use Illuminate\Database\Eloquent\ScopeInterface;
    use Illuminate\Database\Eloquent\Builder;
    
    class DeleteAllScope implements ScopeInterface {
    
        /**
         * Apply the scope to a given Eloquent query builder.
         *
         * @param  \Illuminate\Database\Eloquent\Builder  $builder
         * @return int
         */
        public function apply(Builder $builder)
        {
            $builder->macro('deleteAllWhere', function(
                              Builder $builder, 
                              $column, 
                              $operator = '=', 
                              $value = null, 
                              $boolean = 'and'
            )
            {
                if (is_array($column))
                {
                    $builder->whereNested(function($query) use ($column, $operator, $value)
                    {
                        foreach ( (array)$column as $field => $value)
                        {
                            $query->where($field, $operator, $value);
                        }
                    }, $boolean);
                }
                else
                {
                    $builder->where($column, $operator, $value, $boolean);
                }
    
                $count = $builder->count();
    
                $builder->delete();
    
                return $count;
            });
        }
    
        // no need for implementation, just to satisfy the interface
        public function remove(Builder $builder) {}
    }
    

    并在BaseModel中使用:

    //  Base model
    public static function boot()
    {
        parent::boot();
    
        static::addGlobalScope(new \Your\Namespace\DeleteAllScope);
    }
    

    然后你可以使用它:

    SomeModel::deleteAllWhere('column', '=', 'value'); // 8
    
    $wheres = ['col' => 'val', 'other_col' => 'other_val'];
    SomeModel::deleteAllWhere($wheres); // 1
    
    // and lets you add more complex constraints
    SomeModel::whereIn('id', [1,10,15,20])->deleteAllWhere($wheres); // 3
    
    SomeModel::whereIn('id', [1,10,15,20])->deleteAllWhere($wheres, null, '<>', 'or');
    // DELETE FROM table WHERE id in (1,10,15,20) OR (col <> val AND other_col <> other_val);