Files
animethemes-server/app/GraphQL/Schema/Fields/Relations/Relation.php
T

168 lines
3.9 KiB
PHP

<?php
declare(strict_types=1);
namespace App\GraphQL\Schema\Fields\Relations;
use App\Concerns\Actions\GraphQL\FiltersModels;
use App\Contracts\GraphQL\EnumSort;
use App\Enums\GraphQL\PaginationType;
use App\GraphQL\Argument\Argument;
use App\GraphQL\Argument\FirstArgument;
use App\GraphQL\Argument\PageArgument;
use App\GraphQL\Argument\SortArgument;
use App\GraphQL\Criteria\Filter\FilterCriteria;
use App\GraphQL\Filter\Filter;
use App\GraphQL\Schema\Fields\Field;
use App\GraphQL\Schema\Types\BaseType;
use App\GraphQL\Schema\Types\Pivot\PivotType;
use App\GraphQL\Schema\Unions\BaseUnion;
use GraphQL\Type\Definition\ResolveInfo;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use UnitEnum;
abstract class Relation extends Field
{
use FiltersModels;
protected bool $asPivot = false;
/** @var class-string<UnitEnum&EnumSort>|null */
protected ?string $sortEnum = null;
public function __construct(
protected BaseType|BaseUnion $relatedType,
protected string $relationName,
) {
parent::__construct($relationName);
}
/**
* Rename the relation to something else.
*/
public function renameTo(string $name): static
{
$this->name = $name;
return $this;
}
/**
* Mark the relation as non-nullable.
*/
public function nonNullable(): static
{
$this->nullable = false;
return $this;
}
/**
* Mark the relation as a relation of the pivot model.
*/
public function asPivot(): static
{
$this->asPivot = true;
return $this;
}
/**
* @param class-string<UnitEnum&EnumSort> $enum
*/
public function setSortEnum(string $enum): static
{
$this->sortEnum = $enum;
return $this;
}
/**
* Get the relation name in the model.
*/
public function getRelationName(): string
{
return $this->getColumn();
}
public function isPivot(): bool
{
return $this->asPivot;
}
/**
* Resolve the arguments of the sub-query.
*
* @return Argument[]
*/
public function arguments(): array
{
$arguments = [];
$type = $this->relatedType;
if ($this->paginationType() !== PaginationType::NONE && $type instanceof BaseType && $type->hasFilterableColumns()) {
$arguments[] = FilterCriteria::getFilters($type)
->map(fn (Filter $filter): array => $filter->getArguments())
->flatten();
}
if ($this->paginationType() !== PaginationType::NONE) {
$arguments[] = new FirstArgument(true);
$arguments[] = new PageArgument();
if ($type instanceof BaseType && $type->getEnumSortClass() !== null) {
$arguments[] = new SortArgument($type);
}
}
return Arr::flatten($arguments);
}
/**
* @return BaseType|BaseUnion
*/
public function baseType()
{
return $this->relatedType;
}
/**
* Get the pivot type if it exists.
*/
public function getPivotType(): ?PivotType
{
return null;
}
/**
* Resolve the relation.
*
* @param Model $root
* @param array<string, mixed> $args
*/
public function resolve($root, array $args, $context, ResolveInfo $resolveInfo): mixed
{
/** @var Collection $collection */
$collection = $root->{$this->getRelationName()};
$first = max(1, Arr::integer($args, 'first'));
$page = Arr::get($args, 'page');
return new LengthAwarePaginator(
$collection->forPage($page, $first),
$collection->count(),
$first,
$page
);
}
/**
* The pagination type.
*/
abstract public function paginationType(): PaginationType;
}