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生成WAP页面
Oct 09 PHP
php.ini中date.timezone设置分析
Jul 29 PHP
php的zip解压缩类pclzip使用示例
Mar 14 PHP
php遍历文件夹下的所有文件和子文件夹示例
Mar 20 PHP
PHP实现UTF-8文件BOM自动检测与移除实例
Nov 05 PHP
PHP中使用file_get_contents post数据代码例子
Feb 13 PHP
php将远程图片保存到本地服务器的实现代码
Aug 03 PHP
PHP Cookie学习笔记
Aug 23 PHP
Nginx下ThinkPHP5的配置方法详解
Aug 01 PHP
PHP实现图的邻接矩阵表示及几种简单遍历算法分析
Nov 24 PHP
php封装db类连接sqlite3数据库的方法实例
Dec 19 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入门的学习方法
2007/01/02 PHP
php使用glob函数快速查询指定目录文件的方法
2014/11/15 PHP
javascript中的parseInt和parseFloat区别
2013/07/12 Javascript
JS限制Textarea文本域字符个数的具体实现
2013/08/02 Javascript
JS定时器实例详细分析
2013/10/11 Javascript
3种不同方式的焦点图轮播特效分享
2013/10/30 Javascript
javascript实现动态侧边栏代码
2014/02/19 Javascript
60行js代码实现俄罗斯方块
2015/03/31 Javascript
JavaScript弹出对话框的三种方式
2016/03/23 Javascript
Bootstrap php制作动态分页标签
2016/12/23 Javascript
基于vue实现多引擎搜索及关键字提示
2017/03/16 Javascript
JS实现禁止用户使用Ctrl+鼠标滚轮缩放网页的方法
2017/04/28 Javascript
nodejs中解决异步嵌套循环和循环嵌套异步的问题
2017/07/12 NodeJs
解决ie img标签内存泄漏的问题
2017/10/13 Javascript
vue实现父子组件之间的通信以及兄弟组件的通信功能示例
2019/01/29 Javascript
Python牛刀小试密码爆破
2011/02/03 Python
Python将xml和xsl转换为html的方法
2015/03/10 Python
python定时执行指定函数的方法
2015/05/27 Python
Python中的复制操作及copy模块中的浅拷贝与深拷贝方法
2016/07/02 Python
python学习之hook钩子的原理和使用
2018/10/25 Python
Python运行提示缺少模块问题解决方案
2020/04/02 Python
python实现图片转换成素描和漫画格式
2020/08/19 Python
python将YUV420P文件转PNG图片格式的两种方法
2021/01/22 Python
C++:memset ,memcpy和strcpy的根本区别
2013/04/27 面试题
幼儿教师个人求职信范文
2013/09/21 职场文书
会计专业应届生自荐信
2014/06/28 职场文书
自主招生学校推荐信
2014/09/26 职场文书
事业单位个人查摆问题及整改措施
2014/10/28 职场文书
12.4全国法制宣传日活动方案
2014/11/02 职场文书
教师党的群众路线学习心得体会
2014/11/04 职场文书
升学宴答谢词
2015/01/05 职场文书
个人思想政治总结
2015/03/05 职场文书
指导老师鉴定意见
2015/06/05 职场文书
观后感开头
2015/06/19 职场文书
运动会班级前导词
2015/07/20 职场文书
《时代广场的蟋蟀》读后感:真挚友情,温暖世界!
2020/01/08 职场文书