vendor and env first commit
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\QueryBuilder\Concerns;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Str;
|
||||
use Spatie\QueryBuilder\Exceptions\AllowedFieldsMustBeCalledBeforeAllowedIncludes;
|
||||
use Spatie\QueryBuilder\Exceptions\InvalidFieldQuery;
|
||||
use Spatie\QueryBuilder\Exceptions\UnknownIncludedFieldsQuery;
|
||||
|
||||
trait AddsFieldsToQuery
|
||||
{
|
||||
protected ?Collection $allowedFields = null;
|
||||
|
||||
public function allowedFields($fields): static
|
||||
{
|
||||
if ($this->allowedIncludes instanceof Collection) {
|
||||
throw new AllowedFieldsMustBeCalledBeforeAllowedIncludes();
|
||||
}
|
||||
|
||||
$fields = is_array($fields) ? $fields : func_get_args();
|
||||
|
||||
$this->allowedFields = collect($fields)
|
||||
->map(function (string $fieldName) {
|
||||
return $this->prependField($fieldName);
|
||||
});
|
||||
|
||||
$this->ensureAllFieldsExist();
|
||||
|
||||
$this->addRequestedModelFieldsToQuery();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function addRequestedModelFieldsToQuery()
|
||||
{
|
||||
$modelTableName = $this->getModel()->getTable();
|
||||
|
||||
$fields = $this->request->fields();
|
||||
|
||||
$modelFields = $fields->has($modelTableName) ? $fields->get($modelTableName) : $fields->get('_');
|
||||
|
||||
if (empty($modelFields)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$prependedFields = $this->prependFieldsWithTableName($modelFields, $modelTableName);
|
||||
|
||||
$this->select($prependedFields);
|
||||
}
|
||||
|
||||
public function getRequestedFieldsForRelatedTable(string $relation): array
|
||||
{
|
||||
$tableOrRelation = config('query-builder.convert_relation_names_to_snake_case_plural', true)
|
||||
? Str::plural(Str::snake($relation))
|
||||
: $relation;
|
||||
|
||||
$fields = $this->request->fields()
|
||||
->mapWithKeys(fn ($fields, $table) => [$table => $fields])
|
||||
->get($tableOrRelation);
|
||||
|
||||
if (! $fields) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (! $this->allowedFields instanceof Collection) {
|
||||
// We have requested fields but no allowed fields (yet?)
|
||||
|
||||
throw new UnknownIncludedFieldsQuery($fields);
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
protected function ensureAllFieldsExist()
|
||||
{
|
||||
$modelTable = $this->getModel()->getTable();
|
||||
|
||||
$requestedFields = $this->request->fields()
|
||||
->map(function ($fields, $model) use ($modelTable) {
|
||||
$tableName = $model;
|
||||
|
||||
return $this->prependFieldsWithTableName($fields, $model === '_' ? $modelTable : $tableName);
|
||||
})
|
||||
->flatten()
|
||||
->unique();
|
||||
|
||||
$unknownFields = $requestedFields->diff($this->allowedFields);
|
||||
|
||||
if ($unknownFields->isNotEmpty()) {
|
||||
throw InvalidFieldQuery::fieldsNotAllowed($unknownFields, $this->allowedFields);
|
||||
}
|
||||
}
|
||||
|
||||
protected function prependFieldsWithTableName(array $fields, string $tableName): array
|
||||
{
|
||||
return array_map(function ($field) use ($tableName) {
|
||||
return $this->prependField($field, $tableName);
|
||||
}, $fields);
|
||||
}
|
||||
|
||||
protected function prependField(string $field, ?string $table = null): string
|
||||
{
|
||||
if (! $table) {
|
||||
$table = $this->getModel()->getTable();
|
||||
}
|
||||
|
||||
if (Str::contains($field, '.')) {
|
||||
// Already prepended
|
||||
|
||||
return $field;
|
||||
}
|
||||
|
||||
return "{$table}.{$field}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\QueryBuilder\Concerns;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Str;
|
||||
use Spatie\QueryBuilder\AllowedInclude;
|
||||
use Spatie\QueryBuilder\Exceptions\InvalidIncludeQuery;
|
||||
use Spatie\QueryBuilder\Includes\IncludeInterface;
|
||||
|
||||
trait AddsIncludesToQuery
|
||||
{
|
||||
protected ?Collection $allowedIncludes = null;
|
||||
|
||||
public function allowedIncludes($includes): static
|
||||
{
|
||||
$includes = is_array($includes) ? $includes : func_get_args();
|
||||
|
||||
$this->allowedIncludes = collect($includes)
|
||||
->reject(function ($include) {
|
||||
return empty($include);
|
||||
})
|
||||
->flatMap(function ($include): Collection {
|
||||
if ($include instanceof Collection) {
|
||||
return $include;
|
||||
}
|
||||
|
||||
if ($include instanceof IncludeInterface) {
|
||||
return collect([$include]);
|
||||
}
|
||||
|
||||
if (Str::endsWith($include, config('query-builder.count_suffix', 'Count'))) {
|
||||
return AllowedInclude::count($include);
|
||||
}
|
||||
|
||||
if (Str::endsWith($include, config('query-builder.exists_suffix', 'Exists'))) {
|
||||
return AllowedInclude::exists($include);
|
||||
}
|
||||
|
||||
return AllowedInclude::relationship($include);
|
||||
})
|
||||
->unique(function (AllowedInclude $allowedInclude) {
|
||||
return $allowedInclude->getName();
|
||||
});
|
||||
|
||||
$this->ensureAllIncludesExist();
|
||||
|
||||
$includes = $this->filterNonExistingIncludes($this->request->includes());
|
||||
|
||||
$this->addIncludesToQuery($includes);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function addIncludesToQuery(Collection $includes)
|
||||
{
|
||||
$includes->each(function ($include) {
|
||||
$include = $this->findInclude($include);
|
||||
|
||||
$include->include($this);
|
||||
});
|
||||
}
|
||||
|
||||
protected function findInclude(string $include): ?AllowedInclude
|
||||
{
|
||||
return $this->allowedIncludes
|
||||
->first(function (AllowedInclude $included) use ($include) {
|
||||
return $included->isForInclude($include);
|
||||
});
|
||||
}
|
||||
|
||||
protected function ensureAllIncludesExist()
|
||||
{
|
||||
if (config('query-builder.disable_invalid_includes_query_exception', false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$includes = $this->request->includes();
|
||||
|
||||
$allowedIncludeNames = $this->allowedIncludes->map(function (AllowedInclude $allowedInclude) {
|
||||
return $allowedInclude->getName();
|
||||
});
|
||||
|
||||
$diff = $includes->diff($allowedIncludeNames);
|
||||
|
||||
if ($diff->count()) {
|
||||
throw InvalidIncludeQuery::includesNotAllowed($diff, $allowedIncludeNames);
|
||||
}
|
||||
|
||||
// TODO: Check for non-existing relationships?
|
||||
}
|
||||
|
||||
protected function filterNonExistingIncludes(Collection $includes): Collection
|
||||
{
|
||||
if (config('query-builder.disable_invalid_includes_query_exception', false) == false) {
|
||||
return $includes;
|
||||
}
|
||||
|
||||
return $includes->filter(function ($include) {
|
||||
return $this->findInclude($include);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\QueryBuilder\Concerns;
|
||||
|
||||
use Spatie\QueryBuilder\AllowedFilter;
|
||||
use Spatie\QueryBuilder\Exceptions\InvalidFilterQuery;
|
||||
|
||||
trait FiltersQuery
|
||||
{
|
||||
/** @var \Illuminate\Support\Collection */
|
||||
protected $allowedFilters;
|
||||
|
||||
public function allowedFilters($filters): static
|
||||
{
|
||||
$filters = is_array($filters) ? $filters : func_get_args();
|
||||
|
||||
$this->allowedFilters = collect($filters)->map(function ($filter) {
|
||||
if ($filter instanceof AllowedFilter) {
|
||||
return $filter;
|
||||
}
|
||||
|
||||
return AllowedFilter::partial($filter);
|
||||
});
|
||||
|
||||
$this->ensureAllFiltersExist();
|
||||
|
||||
$this->addFiltersToQuery();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function addFiltersToQuery()
|
||||
{
|
||||
$this->allowedFilters->each(function (AllowedFilter $filter) {
|
||||
if ($this->isFilterRequested($filter)) {
|
||||
$value = $this->request->filters()->get($filter->getName());
|
||||
$filter->filter($this, $value);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($filter->hasDefault()) {
|
||||
$filter->filter($this, $filter->getDefault());
|
||||
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected function findFilter(string $property): ?AllowedFilter
|
||||
{
|
||||
return $this->allowedFilters
|
||||
->first(function (AllowedFilter $filter) use ($property) {
|
||||
return $filter->isForFilter($property);
|
||||
});
|
||||
}
|
||||
|
||||
protected function isFilterRequested(AllowedFilter $allowedFilter): bool
|
||||
{
|
||||
return $this->request->filters()->has($allowedFilter->getName());
|
||||
}
|
||||
|
||||
protected function ensureAllFiltersExist()
|
||||
{
|
||||
if (config('query-builder.disable_invalid_filter_query_exception', false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$filterNames = $this->request->filters()->keys();
|
||||
|
||||
$allowedFilterNames = $this->allowedFilters->map(function (AllowedFilter $allowedFilter) {
|
||||
return $allowedFilter->getName();
|
||||
});
|
||||
|
||||
$diff = $filterNames->diff($allowedFilterNames);
|
||||
|
||||
if ($diff->count()) {
|
||||
throw InvalidFilterQuery::filtersNotAllowed($diff, $allowedFilterNames);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\QueryBuilder\Concerns;
|
||||
|
||||
use Spatie\QueryBuilder\AllowedSort;
|
||||
use Spatie\QueryBuilder\Exceptions\InvalidSortQuery;
|
||||
|
||||
trait SortsQuery
|
||||
{
|
||||
/** @var \Illuminate\Support\Collection */
|
||||
protected $allowedSorts;
|
||||
|
||||
public function allowedSorts($sorts): static
|
||||
{
|
||||
$sorts = is_array($sorts) ? $sorts : func_get_args();
|
||||
|
||||
$this->allowedSorts = collect($sorts)->map(function ($sort) {
|
||||
if ($sort instanceof AllowedSort) {
|
||||
return $sort;
|
||||
}
|
||||
|
||||
return AllowedSort::field(ltrim($sort, '-'));
|
||||
});
|
||||
|
||||
$this->ensureAllSortsExist();
|
||||
|
||||
$this->addRequestedSortsToQuery(); // allowed is known & request is known, add what we can, if there is no request, -wait
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string|\Spatie\QueryBuilder\AllowedSort $sorts
|
||||
*
|
||||
* @return \Spatie\QueryBuilder\QueryBuilder
|
||||
*/
|
||||
public function defaultSort($sorts): static
|
||||
{
|
||||
$sorts = is_array($sorts) ? $sorts : func_get_args();
|
||||
|
||||
return $this->defaultSorts($sorts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string|\Spatie\QueryBuilder\AllowedSort $sorts
|
||||
*
|
||||
* @return \Spatie\QueryBuilder\QueryBuilder
|
||||
*/
|
||||
public function defaultSorts($sorts): static
|
||||
{
|
||||
if ($this->request->sorts()->isNotEmpty()) {
|
||||
// We've got requested sorts. No need to parse defaults.
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
$sorts = is_array($sorts) ? $sorts : func_get_args();
|
||||
|
||||
collect($sorts)
|
||||
->map(function ($sort) {
|
||||
if ($sort instanceof AllowedSort) {
|
||||
return $sort;
|
||||
}
|
||||
|
||||
return AllowedSort::field($sort);
|
||||
})
|
||||
->each(function (AllowedSort $sort) {
|
||||
$sort->sort($this);
|
||||
});
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function addRequestedSortsToQuery()
|
||||
{
|
||||
$this->request->sorts()
|
||||
->each(function (string $property) {
|
||||
$descending = $property[0] === '-';
|
||||
|
||||
$key = ltrim($property, '-');
|
||||
|
||||
$sort = $this->findSort($key);
|
||||
|
||||
$sort?->sort($this, $descending);
|
||||
});
|
||||
}
|
||||
|
||||
protected function findSort(string $property): ?AllowedSort
|
||||
{
|
||||
return $this->allowedSorts
|
||||
->first(function (AllowedSort $sort) use ($property) {
|
||||
return $sort->isSort($property);
|
||||
});
|
||||
}
|
||||
|
||||
protected function ensureAllSortsExist(): void
|
||||
{
|
||||
if (config('query-builder.disable_invalid_sort_query_exception', false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$requestedSortNames = $this->request->sorts()->map(function (string $sort) {
|
||||
return ltrim($sort, '-');
|
||||
});
|
||||
|
||||
$allowedSortNames = $this->allowedSorts->map(function (AllowedSort $sort) {
|
||||
return $sort->getName();
|
||||
});
|
||||
|
||||
$unknownSorts = $requestedSortNames->diff($allowedSortNames);
|
||||
|
||||
if ($unknownSorts->isNotEmpty()) {
|
||||
throw InvalidSortQuery::sortsNotAllowed($unknownSorts, $allowedSortNames);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user