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 随机生成10位字符代码
Mar 26 PHP
一个简单php扩展介绍与开发教程
Aug 19 PHP
PHP读取txt文件的内容并赋值给数组的代码
Nov 03 PHP
那些年一起学习的PHP(三)
Mar 22 PHP
如何利用PHP执行.SQL文件
Jul 05 PHP
php操作XML、读取数据和写入数据的实现代码
Aug 15 PHP
Javascript与PHP验证用户输入URL地址是否正确
Oct 09 PHP
PHP模板引擎Smarty内建函数section,sectionelse用法详解
Apr 11 PHP
php+ajax登录跳转登录实现思路
Jul 31 PHP
Laravel如何友好的修改.env配置文件详解
Jun 07 PHP
swoole和websocket简单聊天室开发
Nov 18 PHP
PHP中rename()函数的妙用讲解
Feb 28 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
全国FM电台频率大全 - 26 西藏自治区
2020/03/11 无线电
Yii使用技巧大汇总
2015/12/29 PHP
php短信接口代码
2016/05/13 PHP
javascript 点击整页变灰的效果(可做退出效果)。
2008/01/09 Javascript
jQuery Validation实例代码 让验证变得如此容易
2010/10/18 Javascript
js判断输入是否为正整数、浮点数等数字的函数代码
2010/11/17 Javascript
js获取当前日期代码适用于网页头部
2013/06/27 Javascript
jQuery中append()方法用法实例
2015/01/08 Javascript
深入分析javascript中的错误处理机制
2016/07/17 Javascript
JS判断iframe是否加载完成的方法
2016/08/03 Javascript
JS 获取HTML标签内的子节点的方法
2016/09/21 Javascript
Boostrap实现的登录界面实例代码
2016/10/09 Javascript
关于BootStrap modal 在IOS9中不能弹出的解决方法(IOS 9 bootstrap modal ios 9 noticework)
2016/12/14 Javascript
node+vue实现用户注册和头像上传的实例代码
2017/07/20 Javascript
慕课网题目之js实现抽奖系统功能
2017/09/19 Javascript
详解Vue组件实现tips的总结
2017/11/01 Javascript
快速了解vue-cli 3.0 新特性
2018/02/28 Javascript
vue2.0模拟锚点的实例
2018/03/14 Javascript
解决iview多表头动态更改列元素发生的错误的方法
2018/11/02 Javascript
vue回到顶部监听滚动事件详解
2019/08/02 Javascript
Vue实现星级评价效果实例详解
2019/12/30 Javascript
Python基于scrapy采集数据时使用代理服务器的方法
2015/04/16 Python
基于python3 类的属性、方法、封装、继承实例讲解
2017/09/19 Python
python将回车作为输入内容的实例
2018/06/23 Python
对pandas中iloc,loc取数据差别及按条件取值的方法详解
2018/11/06 Python
Django高级编程之自定义Field实现多语言
2019/07/02 Python
python从Oracle读取数据生成图表
2020/10/14 Python
Spy++的使用方法及下载教程
2021/01/29 Python
违纪检讨书2000字
2014/02/08 职场文书
委托书模板
2014/04/04 职场文书
倡议书范文格式
2014/05/12 职场文书
2014年作风建设心得体会
2014/10/22 职场文书
优秀班主任主要事迹材料
2014/12/16 职场文书
写给老师的保证书
2015/05/09 职场文书
2016年心理学教育培训学习心得体会
2016/01/12 职场文书
全家福照片寄语怎么写?
2019/04/02 职场文书