Created
April 30, 2025 04:33
-
-
Save bayareawebpro/2934a03f8764f48fbc4a1198969dfe56 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 Jgw555\CmsCore\Resources; | |
use Closure; | |
use Illuminate\Contracts\Pagination\Paginator; | |
use Illuminate\Contracts\Support\Responsable; | |
use Illuminate\Contracts\View\View; | |
use Illuminate\Database\Eloquent\Builder; | |
use Illuminate\Http\JsonResponse; | |
use Illuminate\Http\Request; | |
use Illuminate\Http\Resources\Json\JsonResource; | |
use Illuminate\Support\Collection; | |
use Illuminate\Support\Facades\App; | |
use Illuminate\Validation\Rule; | |
use Laravel\Scout\Builder as ScoutBuilder; | |
class Resource implements Responsable | |
{ | |
protected Request $request; | |
protected Collection $scopeBag; | |
protected Collection $parameterBag; | |
protected Builder|ScoutBuilder|Closure $query; | |
protected string $resource = JsonResource::class; | |
protected array|null $view = null; | |
protected array $rules = []; | |
protected array $options = [ | |
'sort' => [ | |
['label' => 'Asc', 'value' => 'asc'], | |
['label' => 'Desc', 'value' => 'desc'], | |
], | |
]; | |
protected array $with = []; | |
protected array $additional = []; | |
protected array $parameters = [ | |
'per_page' => 12, | |
'sort' => 'desc', | |
]; | |
public function __construct(Request $request, Builder|ScoutBuilder|Closure $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', | |
'query' => 'sometimes|nullable|string', | |
], $this->rules); | |
} | |
public static function fromQuery(Builder|ScoutBuilder|Closure $query): self | |
{ | |
return App::make(static::class, compact('query')); | |
} | |
public static function fromSearchable(string $searchable): self | |
{ | |
return App::make(static::class, ['query' => function (Collection $params) use ($searchable) { | |
return call_user_func([$searchable, 'search'], $params->get('query')); | |
}]); | |
} | |
public function rules(array $rules): self | |
{ | |
$this->rules = array_merge($this->rules, $rules); | |
return $this; | |
} | |
public function forget(string $name): self | |
{ | |
unset($this->rules[$name]); | |
unset($this->options[$name]); | |
$this->scopeBag->forget($name); | |
$this->parameterBag->forget($name); | |
return $this; | |
} | |
public function sortable(array $columns): self | |
{ | |
$this->rules([ | |
'order_by' => ['sometimes', 'string', Rule::in($columns)], | |
]); | |
return $this; | |
} | |
public function with(array $relations = []): self | |
{ | |
$this->with = $relations; | |
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, $key) => is_null($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, $key) => is_null($value)); | |
} | |
protected function executePaginator(Collection $parameters, Collection $scopes): Paginator | |
{ | |
if ($this->query instanceof Closure) { | |
$this->query = call_user_func($this->query, $parameters); | |
} | |
if ($this->query instanceof ScoutBuilder) { | |
$this->query->query(function (Builder $builder) use ($scopes) { | |
$builder->with($this->with); | |
$builder->scopes($scopes->toArray()); | |
}); | |
} else { | |
$this->query->with($this->with); | |
$this->query->scopes($scopes->toArray()); | |
} | |
if ($parameters->has('order_by')) { | |
$this->query->orderBy($parameters->get('order_by'), $parameters->get('sort')); | |
} | |
// append "null" to remove the scout "query" param in favor of "search". | |
return $this->query | |
->simplePaginate($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->only($parameters->keys()))->toArray(); | |
return $this | |
->makeResourceCollection( | |
$this->executePaginator($parameters, $scopes)->appends($combined) | |
) | |
->additional(array_merge($this->additional, [ | |
'query' => $combined, | |
'options' => $this->options | |
])) | |
->toResponse($request); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment