我们从软删除的利用,再顺便说一说模型内的浸染域的观点。
代码韶光常规的删除操作分两步进行,一步是把数据从数据库中查询出来,利用laravel模型的方法, 则返回的是一个模型工具。第二步,调用模型工具的delete方法。代码如下:
$contact = Contact::find(5);$contact->delete();
如果像上面的代码那样,已知数据条款标ID,那么可以直策应用destroy方法进行删除:

Contact::destroy(1);
该方法可以可以用于批量删除传入的指定ID数组的条款:
Contact::destroy([1, 5, 7]);
当然了,delete方法只是链式调用的一个方法,我们通过查询布局器过滤后的数据集, 都可以调用该方法将其删除:
Contact::where('updated_at', '>', Carbon::now()->subYear())->delete();
上面代码实现的是,超过一年没有更新过的contact,将其删除。这可能会有很多,也没有问题。
上面的delete方法,destroy方法,都是对数据的物理删除。数据库的表内记录直接移除了,这在主要的表, 比如user,order,payment这些关系用户权限,资金支付等等的主要数据资源上,物理删除是不被许可的。
以是引入了软删除的观点,便是在表内添加一个字段,用于标记,这一行条款是否算是删除状态。在laravel中, 这个软删除字段默认是 deleted_at。你也可以在模型中手动指定。
如果你利用系统的migrate方法创建迁移文件,那么只用在布局方法中添加如下代码:
Schema::table('contacts', function (Blueprint $table) { $table->softDeletes();});
那么迁移成功后,天生的contacts表内会添加deleted_at字段。
然后在模型中,引入软删除的功能,将其进行全局生效的利用。模型中干系代码如下:
use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\SoftDeletes;class Contact extends Model{ use SoftDeletes; // 这是一个 trait protected $dates = ['deleted_at']; // 指定deleted_at的datetime格式}
通过追寻源代码,我们把稳到 SoftDeletes 实在是注册了一个模型内的全局浸染域方法:
public static function bootSoftDeletes(){ static::addGlobalScope(new SoftDeletingScope);}
这样在运用程序内,利用该模型的所有方法,都会被追加全局可见的查询条件。 我们看源码这样一段,便是用于标记进行删除的:
protected function runSoftDelete(){ $time = $this->freshTimestamp(); // ... $this->{$this->getDeletedAtColumn()} = $time; // ... $query->update($columns);}
为相识释问题,我们把中间几行代码都省略了。大家把稳, 想我们的常规操作一样,便是获取一个韶光戳$time, 然后把字段赋值:
$this->deleted_at = $time;
末了利用update方法更新模型,并修正数据库条款。是不是把知识点都连贯起来了?
既然说到了模型浸染域,我们不妨延伸一下,说说这个设计点,以及适用的场景。
比如说有一个查询条件在代码内到处都要用,有没有简写方法,写一次其他地方可以随意调用呢? 这便是本地浸染域的方法了。来看一个实例:
$activeVips = Contact::where('vip', true)->where('trial', false)->get();
比如说这两个where约束很常用,我们假如能简写为类似下面这样会更直不雅观:
$activeVips = Contact::activeVips()->get();
实现此方法,很大略,只需在模型文件内添加如下方法:
class Contact extends Model{ public function scopeActiveVips($query) { return $query->where('vip', true)->where('trial', false); }}
给本地的浸染域方法添加传入的参数:
class Contact extends Model{ public function scopeStatus($query, $status) { return $query->where('status', $status); }}
用的时候直接把数据作为入参传送即可:
$friends = Contact::status('friend')->get();
这些方法都是要手动显式调用才能利用的。如果是想软删除条款那样,默认把所有的查询都追加 自定义的查询条件,就须要我们上面说的全局浸染域了。
声明一个全局浸染域很大略,只需在模型文件内添加如下代码:
class Contact extends Model{ protected static function boot() { parent::boot(); static::addGlobalScope('active', function (Builder $builder) { $builder->where('active', true); }); }}
那么所有的模型查询,都会默认加上声明中的where约束。一下子节省了很多冗余的代码。
如果你的全局浸染域写的逻辑会有点多喝繁芜,可以将其独立出来,写成类,以便调用。 创建 app/Scopes/ActiveScope.php 文件:
namespace App\Scopes;use Illuminate\Database\Eloquent\Scope;use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Builder;class ActiveScope implements Scope{ public function apply(Builder $builder, Model $model) { return $builder->where('active', true); }}
在模型 Contact 内调用:
use App\Scopes\ActiveScope;use Illuminate\Database\Eloquent\Model;class Contact extends Model{ protected static function boot() { parent::boot(); static::addGlobalScope(new ActiveScope); }}
如果你的代码中这样的全局浸染域用途很多,许多表构造,或者模型的设计逻辑上, 都兼容了此用法,那么独立成一个Scope类更为实用。
写在末了本文从laravel模型的写操作删除动作,讲到了软删除的观点。进而引申出来本地浸染域和全局浸染域的利用。 软删除险些贯穿了我们运用的始终,须要大家勤学苦练。浸染域的观点,设计起来很灵巧, 但是掩护须要一些设计规范,更适宜团队作战的中型大型运用。
Happy coding :-)
我是@程序员小助手,持续分享编程知识,欢迎关注。