SoftDeletes.php 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * This file is part of Hyperf.
  5. *
  6. * @link https://www.hyperf.io
  7. * @document https://hyperf.wiki
  8. * @contact group@hyperf.io
  9. * @license https://github.com/hyperf/hyperf/blob/master/LICENSE
  10. */
  11. namespace Hyperf\Database\Model;
  12. use Psr\EventDispatcher\StoppableEventInterface;
  13. use function Hyperf\Tappable\tap;
  14. /**
  15. * @method static static|\Hyperf\Database\Model\Builder|\Hyperf\Database\Query\Builder restoreOrCreate(array $attributes = [], array $values = [])
  16. * @method static static|\Hyperf\Database\Model\Builder|\Hyperf\Database\Query\Builder withTrashed(bool $withTrashed = true)
  17. * @method static static|\Hyperf\Database\Model\Builder|\Hyperf\Database\Query\Builder onlyTrashed()
  18. * @method static static|\Hyperf\Database\Model\Builder|\Hyperf\Database\Query\Builder withoutTrashed()
  19. */
  20. trait SoftDeletes
  21. {
  22. /**
  23. * Indicates if the model is currently force deleting.
  24. */
  25. protected bool $forceDeleting = false;
  26. /**
  27. * Boot the soft deleting trait for a model.
  28. */
  29. public static function bootSoftDeletes()
  30. {
  31. static::addGlobalScope(new SoftDeletingScope());
  32. }
  33. /**
  34. * Force a hard delete on a soft deleted model.
  35. *
  36. * @return null|bool
  37. */
  38. public function forceDelete()
  39. {
  40. if ($event = $this->fireModelEvent('forceDeleting')) {
  41. if ($event instanceof StoppableEventInterface && $event->isPropagationStopped()) {
  42. return false;
  43. }
  44. }
  45. $this->forceDeleting = true;
  46. return tap($this->delete(), function ($deleted) {
  47. $this->forceDeleting = false;
  48. if ($deleted) {
  49. $this->fireModelEvent('forceDeleted');
  50. }
  51. });
  52. }
  53. /**
  54. * Restore a soft-deleted model instance.
  55. *
  56. * @return null|bool
  57. */
  58. public function restore()
  59. {
  60. // If the restoring event does not return false, we will proceed with this
  61. // restore operation. Otherwise, we bail out so the developer will stop
  62. // the restore totally. We will clear the deleted timestamp and save.
  63. if ($event = $this->fireModelEvent('restoring')) {
  64. if ($event instanceof StoppableEventInterface && $event->isPropagationStopped()) {
  65. return false;
  66. }
  67. }
  68. $this->{$this->getDeletedAtColumn()} = null;
  69. // Once we have saved the model, we will fire the "restored" event so this
  70. // developer will do anything they need to after a restore operation is
  71. // totally finished. Then we will return the result of the save call.
  72. $this->exists = true;
  73. $result = $this->save();
  74. $this->fireModelEvent('restored');
  75. return $result;
  76. }
  77. /**
  78. * Determine if the model instance has been soft-deleted.
  79. *
  80. * @return bool
  81. */
  82. public function trashed()
  83. {
  84. return ! is_null($this->{$this->getDeletedAtColumn()});
  85. }
  86. /**
  87. * Determine if the model is currently force deleting.
  88. *
  89. * @return bool
  90. */
  91. public function isForceDeleting()
  92. {
  93. return $this->forceDeleting;
  94. }
  95. /**
  96. * Get the name of the "deleted at" column.
  97. *
  98. * @return string
  99. */
  100. public function getDeletedAtColumn()
  101. {
  102. return defined('static::DELETED_AT') ? static::DELETED_AT : 'deleted_at';
  103. }
  104. /**
  105. * Get the fully qualified "deleted at" column.
  106. *
  107. * @return string
  108. */
  109. public function getQualifiedDeletedAtColumn()
  110. {
  111. return $this->qualifyColumn($this->getDeletedAtColumn());
  112. }
  113. /**
  114. * Perform the actual delete query on this model instance.
  115. */
  116. protected function performDeleteOnModel()
  117. {
  118. if ($this->forceDeleting) {
  119. $this->exists = false;
  120. return $this->newModelQuery()->where($this->getKeyName(), $this->getKey())->forceDelete();
  121. }
  122. return $this->runSoftDelete();
  123. }
  124. /**
  125. * Perform the actual delete query on this model instance.
  126. */
  127. protected function runSoftDelete()
  128. {
  129. $query = $this->newModelQuery()->where($this->getKeyName(), $this->getKey());
  130. $time = $this->freshTimestamp();
  131. $columns = [$this->getDeletedAtColumn() => $this->fromDateTime($time)];
  132. $this->{$this->getDeletedAtColumn()} = $time;
  133. if ($this->timestamps && ! is_null($this->getUpdatedAtColumn())) {
  134. $this->{$this->getUpdatedAtColumn()} = $time;
  135. $columns[$this->getUpdatedAtColumn()] = $this->fromDateTime($time);
  136. }
  137. $query->update($columns);
  138. }
  139. }