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
六酷社区论坛HOME页清新格调免费版 下载
Mar 07 PHP
在PHP中操作Excel实例代码
Apr 29 PHP
php常用ODBC函数集(详细)
Jun 24 PHP
深入php内核之php in array
Nov 10 PHP
PHP封装的字符串加密解密函数
Dec 18 PHP
Zend Framework实现多文件上传功能实例
Mar 21 PHP
YII动态模型(动态表名)支持分析
Mar 29 PHP
php基于curl重写file_get_contents函数实例
Nov 08 PHP
PHP-FPM运行状态的实时查看及监控详解
Nov 18 PHP
对laravel in 查询的使用方法详解
Oct 09 PHP
PHP学习记录之常用的魔术常量详解
Dec 12 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 preg_replace替换实例讲解
2013/11/04 PHP
PHP实现自动对图片进行滚动显示的方法
2015/03/12 PHP
php文件管理基本功能简单操作
2017/01/16 PHP
jquery 屏蔽一个区域内的所有元素,禁止输入
2009/10/22 Javascript
js 数组克隆方法 小结
2010/03/20 Javascript
获取客户端网卡MAC地址和IP地址实现JS代码
2013/03/17 Javascript
JS隐藏参数post传值实例
2013/04/18 Javascript
JavaScript中Cookies的相关使用教程
2015/06/04 Javascript
jQuery版AJAX简易封装代码
2016/09/14 Javascript
在一个页面重复使用一个js函数的方法详解
2016/12/26 Javascript
原生JS实现《别踩白块》游戏(兼容IE)
2017/02/20 Javascript
微信小程序教程系列之视图层的条件渲染(10)
2017/04/19 Javascript
VUE利用vuex模拟实现新闻点赞功能实例
2017/06/28 Javascript
es7学习教程之fetch解决异步嵌套问题的方法示例
2017/07/21 Javascript
vue实现单选和多选功能
2017/08/11 Javascript
VUEJS 2.0 子组件访问/调用父组件的实例
2018/02/10 Javascript
微信小程序自定义音乐进度条的实例代码
2018/08/28 Javascript
Angular刷新当前页面的实现方法
2018/11/21 Javascript
小程序自定义单页面、全局导航栏的实现代码
2019/03/15 Javascript
深入解析koa之中间件流程控制
2019/06/17 Javascript
[02:20]DOTA2亚洲邀请赛 EHOME战队出场宣传片
2015/02/07 DOTA
Python二叉树定义与遍历方法实例分析
2018/05/25 Python
Python if语句知识点用法总结
2018/06/10 Python
opencv3/C++实现视频读取、视频写入
2019/12/11 Python
HTML5 video 事件应用示例
2014/09/11 HTML / CSS
使用html2canvas实现将html内容写入到canvas中生成图片
2020/01/03 HTML / CSS
台湾家适得:Homeget
2019/02/11 全球购物
美国围栏公司:Walpole Outdoors
2019/11/19 全球购物
大学本科毕业生求职信范文
2013/12/18 职场文书
教堂婚礼主持词
2014/03/14 职场文书
环境建设实施方案
2014/03/14 职场文书
公司党的群众路线教育实践活动领导班子对照检查材料
2014/09/25 职场文书
毕业设计答辩开场白
2015/05/29 职场文书
初中军训感想
2015/08/07 职场文书
2016年党建工作简报
2015/11/26 职场文书
人事行政部各岗位职责说明书!
2019/07/15 职场文书