删除多个模型并扩展 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]);
我不会告诉你错误是什么,但绝对不是要走的路:
- 您正在获取 N 行并创建 N 模型
- 然后调用N查询
一一删除
所有这些都是多余的,无法扩展。即使没有那么多行,它也可能很慢,因为删除比 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);
我正在制作一个通用函数,它接受属性并删除所有具有这些属性的模型。它在一个名为 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]);
我不会告诉你错误是什么,但绝对不是要走的路:
- 您正在获取 N 行并创建 N 模型
- 然后调用N查询 一一删除
所有这些都是多余的,无法扩展。即使没有那么多行,它也可能很慢,因为删除比 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);