src/Foundation/Webonyx/Builder/FieldBuilder.php
<?php
/**
* This file is part of Railt package.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Railt\Foundation\Webonyx\Builder;
use GraphQL\Type\Definition\FieldDefinition;
use GraphQL\Type\Definition\ResolveInfo;
use Railt\Foundation\Event\Resolver\FieldResolve;
use Railt\Foundation\Exception\BadResponseException;
use Railt\Foundation\Webonyx\Builder\Common\FieldDefinitionResolverTrait;
use Railt\Foundation\Webonyx\Context;
use Railt\Foundation\Webonyx\Input;
use Railt\Http\RequestInterface;
use Railt\SDL\Contracts\Definitions\EnumDefinition;
use Railt\SDL\Contracts\Definitions\ScalarDefinition;
use Railt\SDL\Contracts\Dependent\Argument\HasArguments;
use Railt\SDL\Contracts\Dependent\FieldDefinition as FieldDefinitionInterface;
/**
* Class FieldBuilder
* @property FieldDefinitionInterface $reflection
*/
class FieldBuilder extends Builder
{
use FieldDefinitionResolverTrait;
/**
* @return FieldDefinition
* @throws \Exception
*/
public function build(): FieldDefinition
{
return FieldDefinition::create(\array_filter([
'name' => $this->reflection->getName(),
'description' => $this->reflection->getDescription(),
'deprecationReason' => $this->reflection->getDeprecationReason(),
'type' => $this->buildTypeHint($this->reflection),
'resolve' => $this->getResolver(),
'args' => $this->buildArguments($this->reflection),
]));
}
/**
* @return \Closure
*/
private function getResolver(): \Closure
{
return function ($parent, array $args, Context $ctx, ResolveInfo $info) {
$event = $this->fireResolving($parent, $args, $ctx, $info);
if ($event->hasResult() && ! $event->isPropagationStopped()) {
return $event->getResult();
}
return $this->default();
};
}
/**
* @param mixed $result
* @return string
*/
private function getTypeString($result): string
{
if (\is_object($result)) {
return \get_class($result);
}
return \strtolower(\gettype($result));
}
/**
* @param mixed $parent
* @param array $args
* @param Context $ctx
* @param ResolveInfo $info
* @return FieldResolve
*/
private function fireResolving($parent, array $args, Context $ctx, ResolveInfo $info): FieldResolve
{
$event = new FieldResolve($ctx->getConnection(), $ctx->getRequest(), $this->reflection);
$event->withInputResolver($this->getInputResolver($ctx->getRequest(), $args, $info));
$event->withParentResult($parent);
return $this->fire($event);
}
/**
* @param RequestInterface $request
* @param array $args
* @param ResolveInfo $info
* @return \Closure
*/
protected function getInputResolver(RequestInterface $request, array $args, ResolveInfo $info): \Closure
{
return function () use ($request, $args, $info) {
return new Input($request, $info, $this->reflection, $args);
};
}
/**
* @return array|null
*/
private function default(): ?array
{
if ($this->reflection->isNonNull() && $this->reflection->isList()) {
return [];
}
return $this->reflection->isNonNull() && ! $this->isScalar() ? [] : null;
}
/**
* @return bool
*/
private function isScalar(): bool
{
$type = $this->reflection->getTypeDefinition();
return $type instanceof ScalarDefinition || $type instanceof EnumDefinition;
}
/**
* @param HasArguments $arguments
* @return array
* @throws \Exception
*/
private function buildArguments(HasArguments $arguments): array
{
$result = [];
foreach ($arguments->getArguments() as $argument) {
if ($this->shouldSkip($argument)) {
continue;
}
$item = \array_filter([
'name' => $argument->getName(),
'description' => $argument->getDescription(),
'type' => $this->buildTypeHint($argument),
'deprecationReason' => $argument->getDeprecationReason(),
]);
if ($argument->hasDefaultValue()) {
$item['defaultValue'] = $argument->getDefaultValue();
}
$result[] = $item;
}
return $result;
}
}