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 相关文章推荐
PHP 采集心得技巧
May 15 PHP
PHP strtotime函数详解
Dec 18 PHP
PHP查询MySQL大量数据的时候内存占用分析
Jul 22 PHP
PHPExcel读取Excel文件的实现代码
Dec 06 PHP
PHP中new static()与new self()的区别异同分析
Aug 22 PHP
thinkPHP学习笔记之安装配置篇
Mar 05 PHP
PHP使用mysqldump命令导出数据库
Apr 14 PHP
深入浅出php socket编程
May 13 PHP
Yii框架参数化查询中IN查询只能查询一个的解决方法
May 20 PHP
php实现微信企业号支付个人的方法详解
Jul 26 PHP
关于 Laravel Redis 多个进程同时取队列问题详解
Dec 25 PHP
PHP实现基于3DES算法加密解密字符串示例
Aug 24 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
探讨:如何使用PhpDocumentor生成文档
2013/06/25 PHP
枚举JavaScript对象的函数
2006/12/22 Javascript
JavaScript中常见陷阱小结
2010/04/27 Javascript
js日历功能对象
2012/01/12 Javascript
JS Loading功能的简单实现
2013/11/29 Javascript
jQuery中操控hidden、disable等无值属性的方法
2014/01/06 Javascript
jquery组件使用中遇到的问题整理及解决
2014/02/21 Javascript
基于socket.io和node.js搭建即时通信系统
2014/07/30 Javascript
jQuery+PHP实现动态数字展示特效
2015/03/14 Javascript
jQuery点击弹出层弹出模态框点击模态框消失代码分享
2017/01/21 Javascript
canvas实现钟表效果
2017/02/13 Javascript
NodeJS处理Express中异步错误
2017/03/26 NodeJs
Angular 2父子组件数据传递之局部变量获取子组件其他成员
2017/07/04 Javascript
Vuejs 单文件组件实例详解
2018/02/09 Javascript
收集前端面试题之url、href、src
2018/03/22 Javascript
为vue项目自动设置请求状态的配置方法
2019/06/09 Javascript
js实现窗口全屏示例详解
2019/09/17 Javascript
vue-router 路由传参用法实例分析
2020/03/06 Javascript
微信小程序实现简单购物车功能
2020/12/30 Javascript
python使用clear方法清除字典内全部数据实例
2015/07/11 Python
详解Python中最难理解的点-装饰器
2017/04/03 Python
Python连接phoenix的方法示例
2017/09/29 Python
Python操作json的方法实例分析
2018/12/06 Python
使用 Python 合并多个格式一致的 Excel 文件(推荐)
2019/12/09 Python
关于Keras模型可视化教程及关键问题的解决
2020/01/24 Python
Python连接HDFS实现文件上传下载及Pandas转换文本文件到CSV操作
2020/06/06 Python
html5中嵌入视频自动播放的问题解决
2020/05/25 HTML / CSS
德国高品质男装及配饰商城:Cultizm(Raw Denim原色牛仔裤)
2018/04/16 全球购物
日本航空官方网站:JAL
2019/06/19 全球购物
Windows和Linux动态库应用异同
2016/07/28 面试题
管道维修工岗位职责
2013/12/27 职场文书
英语生日邀请函
2014/01/23 职场文书
保护环境倡议书300字
2014/05/19 职场文书
保护动物的宣传语
2015/07/13 职场文书
2015秋季开学典礼演讲稿
2015/07/16 职场文书
JS前端轻量fabric.js系列物体基类
2022/08/05 Javascript