Macroable global scope with caching pagination
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model as BaseModel;
use App\Support\Eloquent\MacroableQueryTrait;
class Model extends BaseModel
{
use MacroableQueryTrait;
protected $macros = ['uniqid', 'paginateOrCache'];
public function macroUniqid(Builder $builder, $salt) {
$name = $builder->getModel()->getConnection()->getName();
return md5($salt . $name . $builder->toSql() . serialize($builder->getQuery()->getBindings()));
}
public function macroPaginateOrCache(Builder $builder, \Illuminate\Contracts\Cache\Repository $cache, $minutes = 1, $perPage = null)
{
$page = \Illuminate\Pagination\Paginator::resolveCurrentPage();
$perPage = $perPage ?: $builder->getModel()->getPerPage();
$key = $builder->uniqid($perPage);
$total = $cache->remember("{$key}-total", $minutes, function () use ($builder) {
return $builder->getQuery()->getCountForPagination();
});
$results = $cache->remember("{$key}-page-{$page}", $minutes, function () use ($builder, $page, $perPage) {
return $builder->getQuery()->forPage($page, $perPage)->get();
});
return new \Illuminate\Pagination\LengthAwarePaginator($results, $total, $perPage, $page, [
'path' => \Illuminate\Pagination\Paginator::resolveCurrentPath(),
]);
}
}
<?php
namespace App\Support\Eloquent;
trait MacroableQueryTrait
{
public static function bootMacroableQueryTrait()
{
static::addGlobalScope(new MacroableQueryScope());
}
public function getMacroses()
{
return isset($this->macros) ? $this->macros : [];
}
}
<?php
namespace App\Support\Eloquent;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\ScopeInterface;
class MacroableQueryScope implements ScopeInterface
{
/**
* Apply the scope to a given Eloquent query builder.
*
* @param Builder $builder
* @param Model $model
*/
public function apply(Builder $builder, Model $model)
{
foreach ($model->getMacroses() as $macro) {
$method = 'macro' . studly_case($macro);
$builder->macro($macro, function(Builder $builder) use ($model, $method) {
$parameters = func_get_args();
return call_user_func_array([$model, $method], $parameters) ?: $this;
});
}
}
/**
* Remove the scope from the given Eloquent query builder.
*
* @param Builder $builder
* @param Model $model
*/
public function remove(Builder $builder, Model $model)
{
// do nothing
}
}