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 选项及相关信息函数库
Dec 04 PHP
PHP 配置文件中open_basedir选项作用
Jul 19 PHP
PHP 写文本日志实现代码
May 18 PHP
PHP文件上传原理简单分析
May 29 PHP
PHP函数in_array()使用详解
Aug 20 PHP
php中的字符编码转换函数用法示例
Oct 20 PHP
php的mssql数据库连接类实例
Nov 28 PHP
YII使用url组件美化管理的方法
Dec 28 PHP
php blowfish加密解密算法
Jul 02 PHP
PHP实现上传图片到 zimg 服务器
Oct 19 PHP
PHP简单实现遍历目录下特定文件的方法小结
May 22 PHP
php实现 master-worker 守护多进程模式的实例代码
Jul 20 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集成FCK的函数代码
2008/09/27 PHP
PHP 简易输出CSV表格文件的方法详解
2013/06/20 PHP
php开发微信支付获取用户地址
2015/10/04 PHP
JavaScript中的Location地址对象
2008/01/16 Javascript
巧用局部变量提升javascript性能
2014/02/24 Javascript
DOM操作一些常用的属性汇总
2015/03/13 Javascript
JavaScript实现获取某个元素相邻兄弟节点的prev与next方法
2016/01/25 Javascript
JavaScript判断DIV内容是否为空的方法
2016/01/29 Javascript
浅谈jQuery animate easing的具体使用方法(推荐)
2016/06/17 Javascript
dul无法加载bootstrap实现unload table/user恢复
2016/09/29 Javascript
KnockoutJS 3.X API 第四章之事件event绑定
2016/10/10 Javascript
基于jQuery实现咖啡订单管理简单应用
2017/02/10 Javascript
jquery实现限制textarea输入字数的方法
2017/09/06 jQuery
Vue实现按钮旋转和移动位置的实例代码
2018/08/09 Javascript
Vue组件为什么data必须是一个函数
2020/06/11 Javascript
简单理解Python中的装饰器
2015/07/31 Python
Python实现简单的四则运算计算器
2016/11/02 Python
Python实现的质因式分解算法示例
2018/05/03 Python
Python 中 -m 的典型用法、原理解析与发展演变
2019/11/11 Python
flask框架自定义url转换器操作详解
2020/01/25 Python
使用PyQt的QLabel组件实现选定目标框功能的方法示例
2020/05/19 Python
通过实例了解Python异常处理机制底层实现
2020/07/23 Python
Python离线安装各种库及pip的方法
2020/11/28 Python
夏威夷咖啡公司:Hawaii Coffee Company
2019/09/19 全球购物
泰国第一在线超市:Tops
2021/02/13 全球购物
师范生教师实习自我鉴定
2013/09/27 职场文书
商务英语毕业生自荐信范文
2013/11/08 职场文书
2015国际残疾人日活动总结
2015/03/24 职场文书
2015年业务工作总结范文
2015/04/10 职场文书
舞出我人生观后感
2015/06/16 职场文书
初一数学教学反思
2016/02/17 职场文书
2019感恩宣传标语!
2019/07/05 职场文书
Vue3.0中Ref与Reactive的区别示例详析
2021/07/07 Vue.js
AngularJS实现多级下拉框
2022/03/25 Javascript
Java 定时任务技术趋势简介
2022/05/04 Java/Android
python playwright之元素定位示例详解
2022/07/23 Python