BuildsQueries.php 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  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\Concerns;
  12. use Closure;
  13. use Hyperf\Context\ApplicationContext;
  14. use Hyperf\Contract\LengthAwarePaginatorInterface;
  15. use Hyperf\Contract\PaginatorInterface;
  16. use Hyperf\Database\Model\Collection;
  17. use Hyperf\Database\Model\Model;
  18. use RuntimeException;
  19. trait BuildsQueries
  20. {
  21. /**
  22. * Chunk the results of the query.
  23. *
  24. * @param int $count
  25. * @return bool
  26. */
  27. public function chunk($count, callable $callback)
  28. {
  29. $this->enforceOrderBy();
  30. $page = 1;
  31. do {
  32. // We'll execute the query for the given page and get the results. If there are
  33. // no results we can just break and return from here. When there are results
  34. // we will call the callback with the current chunk of these results here.
  35. $results = $this->forPage($page, $count)->get();
  36. $countResults = $results->count();
  37. if ($countResults == 0) {
  38. break;
  39. }
  40. // On each chunk result set, we will pass them to the callback and then let the
  41. // developer take care of everything within the callback, which allows us to
  42. // keep the memory low for spinning through large result sets for working.
  43. if ($callback($results, $page) === false) {
  44. return false;
  45. }
  46. unset($results);
  47. ++$page;
  48. } while ($countResults == $count);
  49. return true;
  50. }
  51. /**
  52. * Execute a callback over each item while chunking.
  53. *
  54. * @param int $count
  55. * @return bool
  56. */
  57. public function each(callable $callback, $count = 1000)
  58. {
  59. return $this->chunk($count, function ($results) use ($callback) {
  60. foreach ($results as $key => $value) {
  61. if ($callback($value, $key) === false) {
  62. return false;
  63. }
  64. }
  65. });
  66. }
  67. /**
  68. * Execute the query and get the first result.
  69. *
  70. * @param array $columns
  71. * @return null|Model|object|static
  72. */
  73. public function first($columns = ['*'])
  74. {
  75. return $this->take(1)->get($columns)->first();
  76. }
  77. /**
  78. * Apply the callback's query changes if the given "value" is true.
  79. *
  80. * @param callable($this, $value): $this $callback
  81. * @param callable($this, $value): $this $default
  82. * @return $this
  83. */
  84. public function when(mixed $value, callable $callback, ?callable $default = null): static
  85. {
  86. $value = $value instanceof Closure ? $value($this) : $value;
  87. if ($value) {
  88. return $callback($this, $value) ?: $this;
  89. }
  90. if ($default) {
  91. return $default($this, $value) ?: $this;
  92. }
  93. return $this;
  94. }
  95. /**
  96. * Pass the query to a given callback.
  97. *
  98. * @param Closure $callback
  99. * @return $this|mixed
  100. */
  101. public function tap($callback)
  102. {
  103. return $this->when(true, $callback);
  104. }
  105. /**
  106. * Apply the callback's query changes if the given "value" is false.
  107. *
  108. * @param callable($this, $value): $this $callback
  109. * @param callable($this, $value): $this $default
  110. * @return $this
  111. */
  112. public function unless(mixed $value, callable $callback, ?callable $default = null): static
  113. {
  114. $value = $value instanceof Closure ? $value($this) : $value;
  115. if (! $value) {
  116. return $callback($this, $value) ?: $this;
  117. }
  118. if ($default) {
  119. return $default($this, $value) ?: $this;
  120. }
  121. return $this;
  122. }
  123. /**
  124. * Create a new length-aware paginator instance.
  125. */
  126. protected function paginator(Collection $items, int $total, int $perPage, int $currentPage, array $options): LengthAwarePaginatorInterface
  127. {
  128. $container = ApplicationContext::getContainer();
  129. if (! method_exists($container, 'make')) {
  130. throw new RuntimeException('The DI container does not support make() method.');
  131. }
  132. return $container->make(LengthAwarePaginatorInterface::class, compact('items', 'total', 'perPage', 'currentPage', 'options'));
  133. }
  134. /**
  135. * Create a new simple paginator instance.
  136. */
  137. protected function simplePaginator(Collection $items, int $perPage, int $currentPage, array $options): PaginatorInterface
  138. {
  139. $container = ApplicationContext::getContainer();
  140. if (! method_exists($container, 'make')) {
  141. throw new RuntimeException('The DI container does not support make() method.');
  142. }
  143. return $container->make(PaginatorInterface::class, compact('items', 'perPage', 'currentPage', 'options'));
  144. }
  145. }