Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
<?php
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Query\Builder as QueryBuilder;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Queue\SerializableClosure;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
trait SerializesQuery
{
/**
* Serialize from Eloquent Query Builder.
*
* @param \Illuminate\Database\Eloquent\Builder|array $eloquentBuilder
* @return array
*/
public function serializeEloquentBuilder($eloquentBuilder): array
{
if (is_array($eloquentBuilder)) {
return $eloquentBuilder;
}
return [
'model' => [
'class' => get_class($eloquentBuilder->getModel()),
'eager' => collect($eloquentBuilder->getEagerLoads())->map(function ($callback) {
return serialize(new SerializableClosure($callback));
})->all(),
],
'builder' => $this->serializeQueryBuilder($eloquentBuilder->getQuery()),
];
}
/**
* Unserialize to Eloquent Query Builder.
*
* @param array|\Illuminate\Database\Eloquent\Builder $payload
* @return \Illuminate\Database\Eloquent\Builder
*/
public function unserializeEloquentBuilder($payload): EloquentBuilder
{
if ($payload instanceof EloquentBuilder) {
return $payload;
}
return (new EloquentBuilder($this->unserializeQueryBuilder($payload['builder'])))
->setModel(new $payload['model']['class']())
->setEagerLoads(
collect($payload['model']['eager'])->map(function ($callback) {
return unserialize($callback);
})->all()
);
}
/**
* Serialize to basic Query Builder.
*
* @param \Illuminate\Database\Query\Builder $queryBuilder
* @return array
*/
public function serializeQueryBuilder(QueryBuilder $queryBuilder): array
{
return array_filter([
'columns' => $queryBuilder->columns,
'wheres' => collect($queryBuilder->wheres)->map(function ($where) {
if (isset($where['query'])) {
$where['query'] = $this->serializeQueryBuilder($where['query']);
}
return $where;
})->all(),
'bindings' => $queryBuilder->bindings,
'distinct' => $queryBuilder->distinct,
'from' => $queryBuilder->from,
'joins' => collect($queryBuilder->joins)->map(function ($join) {
return $this->serializeJoinClause($join);
})->all(),
'groups' => $queryBuilder->groups,
'orders' => $queryBuilder->orders,
]);
}
/**
* Unserialize to basic Query Builder.
*
* @param iterable $builder
* @return \Illuminate\Database\Query\Builder
*/
public function unserializeQueryBuilder(array $builder): QueryBuilder
{
$queryBuilder = DB::query();
collect($builder)->transform(function ($value, $type) {
if ($type === 'wheres') {
foreach ($value as $index => $where) {
if (isset($where['query']) && is_array($where['query'])) {
$value[$index]['query'] = $this->unserializeQueryBuilder($where['query']);
}
}
}
if ($type === 'joins') {
$value = $this->unserializeJoinClause($value);
}
return $value;
})->each(function ($value, $type) use ($queryBuilder) {
$queryBuilder->{$type} = $value;
});
return $queryBuilder;
}
/**
* Serialize to Join Clause Query Builder.
*
* @param \Illuminate\Database\Query\Builder $queryBuilder
* @return array
*/
public function serializeJoinClause(JoinClause $queryBuilder): array
{
return array_merge($this->serializeQueryBuilder($queryBuilder), [
'type' => $queryBuilder->type,
'table' => $queryBuilder->table,
]);
}
/**
* Unserialize to Join Clause Query Builder.
*
* @param iterable $joins
* @return iterable
*/
public function unserializeJoinClause(array $joins): array
{
$results = [];
foreach ($joins as $join) {
$type = $join['type'];
$table = $join['table'];
$result[] = new JoinClause(
$this->unserializeQueryBuilder(Arr::except($join, ['type', 'table'])), $type, $table
);
}
return $results;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment