SoftDeletingScope.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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 function Hyperf\Tappable\tap;
  13. class SoftDeletingScope implements Scope
  14. {
  15. /**
  16. * All the extensions to be added to the builder.
  17. */
  18. protected array $extensions = ['Restore', 'RestoreOrCreate', 'WithTrashed', 'WithoutTrashed', 'OnlyTrashed'];
  19. /**
  20. * Apply the scope to a given Model query builder.
  21. */
  22. public function apply(Builder $builder, Model $model)
  23. {
  24. $builder->whereNull($model->getQualifiedDeletedAtColumn());
  25. }
  26. /**
  27. * Extend the query builder with the needed functions.
  28. */
  29. public function extend(Builder $builder)
  30. {
  31. foreach ($this->extensions as $extension) {
  32. $this->{"add{$extension}"}($builder);
  33. }
  34. $builder->onDelete(function (Builder $builder) {
  35. $column = $this->getDeletedAtColumn($builder);
  36. return $builder->update([
  37. $column => $builder->getModel()->freshTimestampString(),
  38. ]);
  39. });
  40. }
  41. /**
  42. * Get the "deleted at" column for the builder.
  43. *
  44. * @return string
  45. */
  46. protected function getDeletedAtColumn(Builder $builder)
  47. {
  48. if (count((array) $builder->getQuery()->joins) > 0) {
  49. return $builder->getModel()->getQualifiedDeletedAtColumn();
  50. }
  51. return $builder->getModel()->getDeletedAtColumn();
  52. }
  53. /**
  54. * Add the restore extension to the builder.
  55. */
  56. protected function addRestore(Builder $builder)
  57. {
  58. $builder->macro('restore', function (Builder $builder) {
  59. $builder->withTrashed();
  60. return $builder->update([$builder->getModel()->getDeletedAtColumn() => null]);
  61. });
  62. }
  63. /**
  64. * Add the restore-or-create extension to the builder.
  65. */
  66. protected function addRestoreOrCreate(Builder $builder)
  67. {
  68. $builder->macro('restoreOrCreate', function (Builder $builder, array $attributes = [], array $values = []) {
  69. $builder->withTrashed();
  70. return tap($builder->firstOrCreate($attributes, $values), function ($instance) {
  71. $instance->restore();
  72. });
  73. });
  74. }
  75. /**
  76. * Add the with-trashed extension to the builder.
  77. */
  78. protected function addWithTrashed(Builder $builder)
  79. {
  80. $builder->macro('withTrashed', function (Builder $builder, $withTrashed = true) {
  81. if (! $withTrashed) {
  82. return $builder->withoutTrashed();
  83. }
  84. return $builder->withoutGlobalScope($this);
  85. });
  86. }
  87. /**
  88. * Add the without-trashed extension to the builder.
  89. */
  90. protected function addWithoutTrashed(Builder $builder)
  91. {
  92. $builder->macro('withoutTrashed', function (Builder $builder) {
  93. $model = $builder->getModel();
  94. $builder->withoutGlobalScope($this)->whereNull(
  95. $model->getQualifiedDeletedAtColumn()
  96. );
  97. return $builder;
  98. });
  99. }
  100. /**
  101. * Add the only-trashed extension to the builder.
  102. */
  103. protected function addOnlyTrashed(Builder $builder)
  104. {
  105. $builder->macro('onlyTrashed', function (Builder $builder) {
  106. $model = $builder->getModel();
  107. $builder->withoutGlobalScope($this)->whereNotNull(
  108. $model->getQualifiedDeletedAtColumn()
  109. );
  110. return $builder;
  111. });
  112. }
  113. }