228 lines
6.4 KiB
PHP
228 lines
6.4 KiB
PHP
<?php
|
|
|
|
namespace Illuminate\Database\Concerns;
|
|
|
|
use Illuminate\Container\Container;
|
|
use Illuminate\Pagination\LengthAwarePaginator;
|
|
use Illuminate\Pagination\Paginator;
|
|
|
|
trait BuildsQueries
|
|
{
|
|
/**
|
|
* Chunk the results of the query.
|
|
*
|
|
* @param int $count
|
|
* @param callable $callback
|
|
* @return bool
|
|
*/
|
|
public function chunk($count, callable $callback)
|
|
{
|
|
$this->enforceOrderBy();
|
|
|
|
$page = 1;
|
|
|
|
do {
|
|
// We'll execute the query for the given page and get the results. If there are
|
|
// no results we can just break and return from here. When there are results
|
|
// we will call the callback with the current chunk of these results here.
|
|
$results = $this->forPage($page, $count)->get();
|
|
|
|
$countResults = $results->count();
|
|
|
|
if ($countResults == 0) {
|
|
break;
|
|
}
|
|
|
|
// On each chunk result set, we will pass them to the callback and then let the
|
|
// developer take care of everything within the callback, which allows us to
|
|
// keep the memory low for spinning through large result sets for working.
|
|
if ($callback($results, $page) === false) {
|
|
return false;
|
|
}
|
|
|
|
unset($results);
|
|
|
|
$page++;
|
|
} while ($countResults == $count);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Execute a callback over each item while chunking.
|
|
*
|
|
* @param callable $callback
|
|
* @param int $count
|
|
* @return bool
|
|
*/
|
|
public function each(callable $callback, $count = 1000)
|
|
{
|
|
return $this->chunk($count, function ($results) use ($callback) {
|
|
foreach ($results as $key => $value) {
|
|
if ($callback($value, $key) === false) {
|
|
return false;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Chunk the results of a query by comparing IDs.
|
|
*
|
|
* @param int $count
|
|
* @param callable $callback
|
|
* @param string|null $column
|
|
* @param string|null $alias
|
|
* @return bool
|
|
*/
|
|
public function chunkById($count, callable $callback, $column = null, $alias = null)
|
|
{
|
|
$column = $column ?? $this->defaultKeyName();
|
|
|
|
$alias = $alias ?? $column;
|
|
|
|
$lastId = null;
|
|
|
|
do {
|
|
$clone = clone $this;
|
|
|
|
// We'll execute the query for the given page and get the results. If there are
|
|
// no results we can just break and return from here. When there are results
|
|
// we will call the callback with the current chunk of these results here.
|
|
$results = $clone->forPageAfterId($count, $lastId, $column)->get();
|
|
|
|
$countResults = $results->count();
|
|
|
|
if ($countResults == 0) {
|
|
break;
|
|
}
|
|
|
|
// On each chunk result set, we will pass them to the callback and then let the
|
|
// developer take care of everything within the callback, which allows us to
|
|
// keep the memory low for spinning through large result sets for working.
|
|
if ($callback($results) === false) {
|
|
return false;
|
|
}
|
|
|
|
$lastId = $results->last()->{$alias};
|
|
|
|
unset($results);
|
|
} while ($countResults == $count);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Execute a callback over each item while chunking by ID.
|
|
*
|
|
* @param callable $callback
|
|
* @param int $count
|
|
* @param string|null $column
|
|
* @param string|null $alias
|
|
* @return bool
|
|
*/
|
|
public function eachById(callable $callback, $count = 1000, $column = null, $alias = null)
|
|
{
|
|
return $this->chunkById($count, function ($results) use ($callback) {
|
|
foreach ($results as $key => $value) {
|
|
if ($callback($value, $key) === false) {
|
|
return false;
|
|
}
|
|
}
|
|
}, $column, $alias);
|
|
}
|
|
|
|
/**
|
|
* Execute the query and get the first result.
|
|
*
|
|
* @param array|string $columns
|
|
* @return \Illuminate\Database\Eloquent\Model|object|static|null
|
|
*/
|
|
public function first($columns = ['*'])
|
|
{
|
|
return $this->take(1)->get($columns)->first();
|
|
}
|
|
|
|
/**
|
|
* Apply the callback's query changes if the given "value" is true.
|
|
*
|
|
* @param mixed $value
|
|
* @param callable $callback
|
|
* @param callable|null $default
|
|
* @return mixed|$this
|
|
*/
|
|
public function when($value, $callback, $default = null)
|
|
{
|
|
if ($value) {
|
|
return $callback($this, $value) ?: $this;
|
|
} elseif ($default) {
|
|
return $default($this, $value) ?: $this;
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Pass the query to a given callback.
|
|
*
|
|
* @param callable $callback
|
|
* @return $this
|
|
*/
|
|
public function tap($callback)
|
|
{
|
|
return $this->when(true, $callback);
|
|
}
|
|
|
|
/**
|
|
* Apply the callback's query changes if the given "value" is false.
|
|
*
|
|
* @param mixed $value
|
|
* @param callable $callback
|
|
* @param callable|null $default
|
|
* @return mixed|$this
|
|
*/
|
|
public function unless($value, $callback, $default = null)
|
|
{
|
|
if (! $value) {
|
|
return $callback($this, $value) ?: $this;
|
|
} elseif ($default) {
|
|
return $default($this, $value) ?: $this;
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Create a new length-aware paginator instance.
|
|
*
|
|
* @param \Illuminate\Support\Collection $items
|
|
* @param int $total
|
|
* @param int $perPage
|
|
* @param int $currentPage
|
|
* @param array $options
|
|
* @return \Illuminate\Pagination\LengthAwarePaginator
|
|
*/
|
|
protected function paginator($items, $total, $perPage, $currentPage, $options)
|
|
{
|
|
return Container::getInstance()->makeWith(LengthAwarePaginator::class, compact(
|
|
'items', 'total', 'perPage', 'currentPage', 'options'
|
|
));
|
|
}
|
|
|
|
/**
|
|
* Create a new simple paginator instance.
|
|
*
|
|
* @param \Illuminate\Support\Collection $items
|
|
* @param int $perPage
|
|
* @param int $currentPage
|
|
* @param array $options
|
|
* @return \Illuminate\Pagination\Paginator
|
|
*/
|
|
protected function simplePaginator($items, $perPage, $currentPage, $options)
|
|
{
|
|
return Container::getInstance()->makeWith(Paginator::class, compact(
|
|
'items', 'perPage', 'currentPage', 'options'
|
|
));
|
|
}
|
|
}
|