Created
April 22, 2022 05:02
-
-
Save bayareawebpro/faee40719707f7d781126d1274b770e4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php declare(strict_types=1); | |
namespace App\Services; | |
use Illuminate\Http\Request; | |
use Illuminate\Validation\Rule; | |
use Illuminate\Support\Collection; | |
use Illuminate\Support\Facades\App; | |
use Illuminate\Database\Eloquent\Builder; | |
use Illuminate\Contracts\Pagination\Paginator; | |
use Illuminate\Http\JsonResponse; | |
use Illuminate\Contracts\View\View; | |
use Illuminate\Contracts\Support\Responsable; | |
use Illuminate\Http\Resources\Json\JsonResource; | |
class Resource implements Responsable | |
{ | |
protected Builder $query; | |
protected Request $request; | |
protected Collection $scopeBag; | |
protected Collection $parameterBag; | |
protected array|null $view = null; | |
protected string $resource = JsonResource::class; | |
protected array $rules = []; | |
protected array $options = []; | |
protected array $additional = []; | |
protected array $parameters = [ | |
'per_page' => 12, | |
'order_by' => 'id', | |
'sort' => 'desc', | |
]; | |
public function __construct(Request $request, Builder $query) | |
{ | |
$this->query = $query; | |
$this->request = $request; | |
$this->scopeBag = Collection::make(); | |
$this->parameterBag = Collection::make($this->parameters); | |
$this->rules = array_merge([ | |
'sort' => 'sometimes|string|in:asc,desc', | |
'per_page' => 'sometimes|numeric|min:1,max:50', | |
], $this->rules); | |
} | |
public static function fromQuery(Builder $query): self | |
{ | |
return App::make(static::class, compact('query')); | |
} | |
public function rules(array $rules): self | |
{ | |
$this->rules = array_merge($this->rules, $rules); | |
return $this; | |
} | |
public function sortable(array $columns): self | |
{ | |
$this->rules([ | |
'order_by' => ['sometimes', 'string', Rule::in($columns)], | |
]); | |
return $this; | |
} | |
public function scopes(array $scopes): self | |
{ | |
$this->scopeBag = $this->scopeBag->merge($scopes); | |
return $this; | |
} | |
public function params(array $params): self | |
{ | |
$this->parameterBag = $this->parameterBag->merge($params); | |
return $this; | |
} | |
public function options(array $options): self | |
{ | |
$this->options = array_merge($this->options, $options); | |
return $this; | |
} | |
public function additional(array $additional): self | |
{ | |
$this->additional = array_merge($this->additional, $additional); | |
return $this; | |
} | |
public function resource(string $resourceClassString): self | |
{ | |
$this->resource = $resourceClassString; | |
return $this; | |
} | |
protected function validateParameters(): Collection | |
{ | |
return $this->parameterBag | |
->merge($this->request->validate($this->rules)) | |
->reject(fn($value) => empty($value)); | |
} | |
protected function buildScopes(Collection $parameters): Collection | |
{ | |
return $this->scopeBag | |
->map(fn($value, $key) => ( | |
$value instanceof \Closure | |
? call_user_func($value, $parameters) | |
: $parameters->get($key, $value) | |
)) | |
->reject(fn($value) => empty($value)); | |
} | |
protected function executePaginator(Collection $parameters, Collection $scopes): Paginator | |
{ | |
return $this->query | |
->scopes($scopes->toArray()) | |
->orderBy($parameters->get('order_by'), $parameters->get('sort')) | |
->paginate($parameters->get('per_page')); | |
} | |
protected function makeResourceCollection(Paginator $paginator): JsonResource | |
{ | |
return call_user_func([$this->resource, "collection"], $paginator); | |
} | |
public function view(string $view, array $data = []): self | |
{ | |
$this->view = compact('view', 'data'); | |
return $this; | |
} | |
public function toResponse($request): View|JsonResponse | |
{ | |
if ($this->view && !($request->wantsJson() || $request->ajax())) { | |
return view($this->view['view'], $this->view['data']); | |
} | |
$parameters = $this->validateParameters(); | |
$scopes = $this->buildScopes($parameters); | |
$combined = $parameters->merge($scopes)->toArray(); | |
return $this | |
->makeResourceCollection( | |
$this->executePaginator($parameters, $scopes)->appends($combined) | |
) | |
->additional(array_merge($this->additional, [ | |
'query' => $combined, | |
'options' => $this->options | |
])) | |
->toResponse($request ?? $this->request); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment