Laravel 实现数据软删除功能


Posted in PHP onAugust 21, 2019

对于任何一个模型,如果需要使用软删除功能,需要在模型中使用 Illuminate\Database\Eloquent\SoftDeletes 这个  trait 。软删除功能需要实现的功能有以下几点:

1.模型执行删除操作,只标记删除,不执行真正的数据删除

2.查询的时候自动过滤已经标记为删除的数据

3.可以设置是否查询已删除的数据,可以设置只查询已删除的数据

4.已删除数据可以恢复

Model的软删除功能实现

Illuminate\Database\Eloquent\Model 中delete方法源码:

public function delete()
{
 if (is_null($this->getKeyName())) {
  throw new Exception('No primary key defined on model.');
 }
 if (! $this->exists) {
  return;
 }
 if ($this->fireModelEvent('deleting') === false) {
  return false;
 }
 $this->touchOwners();
 $this->performDeleteOnModel();
 $this->fireModelEvent('deleted', false);
 return true;
}
protected function performDeleteOnModel()
{
 $this->setKeysForSaveQuery($this->newModelQuery())
 ->delete();
 $this->exists = false;
}

因为在子类中使用了 SoftDeletes trait,所以, SoftDeletes performDeleteOnModel 方法会覆盖父类的方法,最终通过  runSoftDelete 方法更新删除标记。

protected function performDeleteOnModel()
{
 if ($this->forceDeleting) {
  $this->exists = false;
  return $this->newModelQuery()->where(
    $this->getKeyName(), $this->getKey()
  )->forceDelete();
 }
 return $this->runSoftDelete();
}

protected function runSoftDelete()
{
 $query = $this->newModelQuery()
      ->where($this->getKeyName(), $this->getKey());
 $time = $this->freshTimestamp();
 $columns = [$this->getDeletedAtColumn() => $this->fromDateTime($time)];
 $this->{$this->getDeletedAtColumn()} = $time;
 if ($this->timestamps && ! is_null($this->getUpdatedAtColumn())) {
  $this->{$this->getUpdatedAtColumn()} = $time;
  $columns[$this->getUpdatedAtColumn()] = $this->fromDateTime($time);
 }
 $query->update($columns);
}

Model查询过滤删除数据

Laravel中允许在Model中 static::addGlobalScope 方法添加全局的 Scope 。这样就可以在查询条件中添加一个全局条件。Laravel中软删除数据的过滤也是使用这种方式实现的。

SoftDeletes trait中加入了 Illuminate\Database\Eloquent\SoftDeletingScope 全局的 Scope 。并在 SoftDeletingScope 中实现查询自动过滤被删除数据,指定查询已删除数据功能。

public static function bootSoftDeletes()
{
 static::addGlobalScope(new SoftDeletingScope);
}

远程关联数据的软删除处理

Scope的作用只在于当前模型,以及关联模型操作上。如果是远程关联,则还需要额外的处理。Laravel远程关联关系通过 hasManyThrough 实现。里面有两个地方涉及到软删除的查询。

protected function performJoin(Builder $query = null)
{
 $query = $query ?: $this->query;
 $farKey = $this->getQualifiedFarKeyName();
 $query->join($this->throughParent->getTable(), $this->getQualifiedParentKeyName(), '=', $farKey);
 if ($this->throughParentSoftDeletes()) {
  $query->whereNull(
   $this->throughParent->getQualifiedDeletedAtColumn()
  );
 }
}

public function throughParentSoftDeletes()
{
 return in_array(SoftDeletes::class, class_uses_recursive(
  get_class($this->throughParent)
 ));
}
public function getRelationExistenceQueryForSelfRelation(Builder $query, Builder $parentQuery, $columns = ['*'])
{
 $query->from( $query->getModel()->getTable().' as '
  .$hash = $this->getRelationCountHash()
 );
 $query->join($this->throughParent->getTable(), 
  $this->getQualifiedParentKeyName(), '=', $hash.'.'.$this->secondLocalKey
 );
 if ($this->throughParentSoftDeletes()) {
  $query->whereNull($this->throughParent->getQualifiedDeletedAtColumn());
 }
 $query->getModel()->setTable($hash);
 return $query->select($columns)->whereColumn(
  $parentQuery->getQuery()->from.'.'.$query->getModel()->getKeyName(), '=', $this->getQualifiedFirstKeyName()
 );
}

performJoin 中通过中间模型关联远程模型,会根据 throughParentSoftDeletes 判断中间模型是否有软删除,如果有软删除会过滤掉中间模型被删除的数据。

以上就是Laravel实现软删除的大概逻辑。这里有一个细节,Laravel中软删除的标记是一个时间格式的字段,默认 delete_at 。通过是否为null判断数据是否删除。

但是有的时候,项目中会使用一个整形的字段标记数据是否删除。在这样的场景下,需要对Laravel的软删除进行修改才能够实现。

主要的方案是:

1.自定义 SoftDeletes trait,修改字段名称,修改更新删除标记操作;

2.自定义 SoftDeletingScope 修改查询条件

3.自定义 HasRelationships trait,在自定义的 HasRelationships 中重写 newHasManyThrough 方法,实例化自定义的 HasManyThrough 对象

总结

以上所述是小编给大家介绍的Laravel 实现数据软删除功能,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

PHP 相关文章推荐
ADODB的数据库封包程序库
Dec 31 PHP
PHP通过COM使用ADODB的简单例子
Dec 31 PHP
PHP 实现多服务器共享 SESSION 数据
Aug 15 PHP
php控制linux服务器常用功能 关机 重启 开新站点等
Sep 05 PHP
PHP利用str_replace防注入的方法
Nov 10 PHP
php使浏览器直接下载pdf文件的方法
Nov 15 PHP
Thinkphp将二维数组变为标签适用的一维数组方法总结
Oct 30 PHP
php判断linux下程序问题实例
Jul 09 PHP
PHP获取文件扩展名的方法实例总结
Jun 10 PHP
浅谈PHP各环境下的伪静态配置
Mar 13 PHP
YII框架页面缓存操作示例
Apr 29 PHP
laravel-admin自动生成模块,及相关基础配置方法
Oct 08 PHP
PHP针对redis常用操作实例详解
Aug 17 #PHP
php5.6.x到php7.0.x特性小结
Aug 17 #PHP
PHP中非常有用却鲜有人知的函数集锦
Aug 17 #PHP
PHP中Session ID的实现原理实例分析
Aug 17 #PHP
解决php extension 加载顺序问题
Aug 16 #PHP
深入学习微信网址链接解封的防封原理visit_type
Aug 15 #PHP
Thinkphp5框架实现获取数据库数据到视图的方法
Aug 14 #PHP
You might like
php版微信公众平台接口开发之智能回复开发教程
2016/09/22 PHP
统计PHP目录中的文件数方法
2019/03/05 PHP
微信公众号之主动给用户发送消息功能
2019/06/22 PHP
一步一步教你写一个jQuery的插件教程(Plugin)
2009/09/03 Javascript
input输入框的自动匹配(原生代码)
2013/03/19 Javascript
JavaScript SetInterval与setTimeout使用方法详解
2013/11/15 Javascript
使用jquery.validate自定义方法实现"手机号码或者固话至少填写一个"的逻辑验证
2014/09/01 Javascript
Angularjs编写KindEditor,UEidtor,jQuery指令
2015/01/28 Javascript
JavaScript中Number.MIN_VALUE属性的使用示例
2015/06/04 Javascript
javascript实现的闭包简单实例
2015/07/17 Javascript
直接拿来用的页面跳转进度条JS实现
2016/01/06 Javascript
[原创]SyntaxHighlighter自动识别并加载脚本语言
2017/02/07 Javascript
Vue用v-for给src属性赋值的方法
2018/03/03 Javascript
Vue el-autocomplete远程搜索下拉框并实现自动填充功能(推荐)
2019/10/25 Javascript
[00:10]神之谴戒
2019/03/06 DOTA
[54:15]DOTA2-DPC中国联赛 正赛 DLG vs Dragon BO3 第二场2月1日
2021/03/11 DOTA
Python使用 Beanstalkd 做异步任务处理的方法
2018/04/24 Python
Python函数返回不定数量的值方法
2019/01/22 Python
python rsync服务器之间文件夹同步脚本
2019/08/29 Python
Python内置数据类型list各方法的性能测试过程解析
2020/01/07 Python
python实现串口通信的示例代码
2020/02/10 Python
对Matlab中共轭、转置和共轭装置的区别说明
2020/05/11 Python
keras-siamese用自己的数据集实现详解
2020/06/10 Python
浅谈keras通过model.fit_generator训练模型(节省内存)
2020/06/17 Python
利用Python如何制作贪吃蛇及AI版贪吃蛇详解
2020/08/24 Python
Django配置跨域并开发测试接口
2020/11/04 Python
Python操作PostgreSql数据库的方法(基本的增删改查)
2020/12/29 Python
python实现代码审查自动回复消息
2021/02/01 Python
英国家电直销:Appliances Direct
2016/09/22 全球购物
高级3D打印市场:Gambody
2019/12/26 全球购物
人力资源管理毕业生自荐信
2013/11/21 职场文书
幼儿园庆六一游园活动方案
2014/01/29 职场文书
副检察长四风问题对照检查材料思想汇报
2014/10/07 职场文书
古见同学有交流障碍症 第二季宣传CM公开播出
2022/04/11 日漫
如何Tomcat中使用ipv6地址
2022/05/06 Servers
鸿蒙3.0体验感怎么样? 鸿蒙3.0系统评测向
2022/08/14 数码科技