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制作新闻系统的思路
Oct 09 PHP
PHP的FTP学习(三)
Oct 09 PHP
基于在生产环境中使用php性能测试工具xhprof的详解
Jun 03 PHP
ThinkPHP使用心得分享-分页类Page的用法
May 15 PHP
php中使用in_array() foreach array_search() 查找数组是否包含时的性能对比
Apr 14 PHP
php实现面包屑导航例子分享
Dec 19 PHP
简介PHP的Yii框架中缓存的一些高级用法
Mar 29 PHP
PHP获取客户端及服务器端IP的封装类
Jul 21 PHP
PHP基本语法实例总结
Sep 09 PHP
Yii2 hasOne(), hasMany() 实现三表关联的方法(两种)
Feb 15 PHP
php安装扩展mysqli的实现步骤及报错解决办法
Sep 23 PHP
php PDO属性设置与操作方法分析
Dec 27 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学习笔记之数组篇
2011/06/28 PHP
浅谈COOKIE和SESSION区别
2015/07/19 PHP
PHP实现微信网页授权开发教程
2016/01/19 PHP
PHP实现的限制IP投票程序IP来源分析
2016/05/04 PHP
tp5框架使用cookie加密算法实现登录功能示例
2020/02/10 PHP
JQuery 学习笔记 选择器之二
2009/07/23 Javascript
jqPlot jquery的页面图表绘制工具
2009/07/25 Javascript
Ruffy javascript 学习笔记
2009/11/30 Javascript
js对字符的验证方法汇总
2015/02/04 Javascript
jQuery事件绑定on()、bind()与delegate() 方法详解
2015/06/03 Javascript
jquery插件锦集【推荐】
2016/12/16 Javascript
JS得到当前时间的方法示例
2017/03/24 Javascript
bootstrap suggest下拉框使用详解
2017/04/10 Javascript
Javascript中Promise的四种常用方法总结
2017/07/14 Javascript
基于vue2.x的电商图片放大镜插件的使用
2018/01/22 Javascript
vue和webpack打包项目相对路径修改的方法
2018/06/15 Javascript
如何使用JavaScript实现栈与队列
2019/06/24 Javascript
Vue实现验证码功能
2019/12/03 Javascript
Python3遍历目录树实现方法
2015/05/22 Python
Python的面向对象编程方式学习笔记
2016/07/12 Python
使用python实现knn算法
2017/12/20 Python
详解python3安装pillow后报错没有pillow模块以及没有PIL模块问题解决
2019/04/17 Python
Django框架模板文件使用及模板文件加载顺序分析
2019/05/23 Python
pycharm中import呈现灰色原因的解决方法
2020/03/04 Python
Python Celery异步任务队列使用方法解析
2020/08/10 Python
pandas参数设置的实用小技巧
2020/08/23 Python
一款利用纯css3实现的超炫3D表单的实例教程
2014/12/01 HTML / CSS
基于CSS3实现图片模糊过滤效果
2015/11/19 HTML / CSS
css3 clip实现圆环进度条的示例代码
2018/02/07 HTML / CSS
面向对象概念面试题(.NET)
2016/11/04 面试题
配置管理计划的主要内容有哪些
2014/06/20 面试题
EJB的激活机制
2013/10/25 面试题
如何写毕业求职自荐信
2013/11/06 职场文书
个人整改方案范文
2014/10/25 职场文书
成本会计实训报告
2014/11/05 职场文书
MySQL中distinct与group by之间的性能进行比较
2021/05/26 MySQL