删除多个模型并扩展 Eloquent Builder

Deleting multiple models & extending Eloquent Builder

我正在制作一个通用函数,它接受属性并删除所有具有这些属性的模型。它在一个名为 BaseModel 的 class 中定义,它扩展了 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. 您正在获取 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);