Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ You can find and compare releases at the [GitHub release page](https://github.co

## Unreleased

### Changed

- Use common Builder interface https://github.com/nuwave/lighthouse/pull/2389
- Do not pass `ResolveInfo` to itself in `ResolveInfo::enhanceBuilder()` https://github.com/nuwave/lighthouse/pull/2389

## v6.9.1

### Fixed
Expand Down
30 changes: 30 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,36 @@ It will prevent the following type of HTTP requests:
- `GET` requests
- `POST` requests that can be created using HTML forms

### Type hinting query builders

Lighthouse now uses `Illuminate\Contracts\Database\Query\Builder` to type hint database query builders.
If you implement `ArgBuilderDirective` or `FieldBuilderDirective`, you will have to change the signature of the `handleFieldBuilder` method accordingly:

```diff
- use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
- use Illuminate\Database\Eloquent\Relations\Relation;
- use Illuminate\Database\Query\Builder as QueryBuilder;
+ use Illuminate\Contracts\Database\Query\Builder;

- public function handleFieldBuilder(QueryBuilder|EloquentBuilder|Relation $builder, mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): QueryBuilder|EloquentBuilder|Relation;
+ public function handleFieldBuilder(Builder $builder, mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): Builder;
```

### Do not pass `ResolveInfo` to itself in `ResolveInfo::enhanceBuilder()`

`ResolveInfo::enhanceBuilder()` no longer expects to be passed an instance of `ResolveInfo`,
as it can access it via `$this`.

```diff
use Nuwave\Lighthouse\Execution\ResolveInfo;
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;

// Some resolver function or directive middleware
function (mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo) {
- $resolveInfo->enhanceBuilder($builder, $scopes, $root, $args, $context, $resolveInfo, $directiveFilter);
+ $resolveInfo->enhanceBuilder($builder, $scopes, $root, $args, $context, $directiveFilter);
```

## v5 to v6

### `messages` on `@rules` and `@rulesForArray`
Expand Down
6 changes: 2 additions & 4 deletions docs/master/custom-directives/argument-directives.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,7 @@ where the `category` column is equal to the value of the `category` argument.
So let's take a look at a simplified version of the built-in [@eq](../api-reference/directives.md#eq) directive.

```php
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Query\Builder as QueryBuilder;
use Illuminate\Contracts\Database\Query\Builder;
use Nuwave\Lighthouse\Support\Contracts\ArgBuilderDirective;

class EqDirective extends BaseDirective implements ArgBuilderDirective
Expand All @@ -171,7 +169,7 @@ GRAPHQL;
/**
* Apply a "WHERE = $value" clause.
*/
public function handleBuilder(QueryBuilder|EloquentBuilder|Relation $builder, $value): QueryBuilder|EloquentBuilder|Relation
public function handleBuilder(Builder $builder, $value): Builder
{
return $builder->where(
$this->directiveArgValue('key', $this->nodeName()),
Expand Down
2 changes: 0 additions & 2 deletions src/Auth/CanDirective.php
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,6 @@ protected function modelsToCheck(mixed $root, array $args, GraphQLContext $conte
$root,
$args,
$context,
$resolveInfo,
)
->get();
}
Expand Down Expand Up @@ -194,7 +193,6 @@ protected function modelsToCheck(mixed $root, array $args, GraphQLContext $conte
$root,
$args,
$context,
$resolveInfo,
Utils::instanceofMatcher(TrashedDirective::class),
);
assert($enhancedBuilder instanceof EloquentBuilder);
Expand Down
5 changes: 2 additions & 3 deletions src/Auth/WhereAuthDirective.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
namespace Nuwave\Lighthouse\Auth;

use Illuminate\Contracts\Auth\Factory as AuthFactory;
use Illuminate\Contracts\Database\Query\Builder;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Query\Builder as QueryBuilder;
use Nuwave\Lighthouse\Execution\ResolveInfo;
use Nuwave\Lighthouse\Schema\Directives\BaseDirective;
use Nuwave\Lighthouse\Support\Contracts\FieldBuilderDirective;
Expand Down Expand Up @@ -38,7 +37,7 @@ public static function definition(): string
GRAPHQL;
}

public function handleFieldBuilder(QueryBuilder|EloquentBuilder|Relation $builder, mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): QueryBuilder|EloquentBuilder|Relation
public function handleFieldBuilder(Builder $builder, mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): Builder
{
assert($builder instanceof EloquentBuilder);

Expand Down
41 changes: 16 additions & 25 deletions src/Execution/ResolveInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
namespace Nuwave\Lighthouse\Execution;

use GraphQL\Type\Definition\ResolveInfo as BaseResolveInfo;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Query\Builder as QueryBuilder;
use Illuminate\Contracts\Database\Query\Builder;
use Illuminate\Support\Collection;
use Laravel\Scout\Builder as ScoutBuilder;
use Nuwave\Lighthouse\Execution\Arguments\ArgumentSet;
Expand Down Expand Up @@ -37,26 +35,21 @@ public function __construct(
/**
* Apply ArgBuilderDirectives and scopes to the builder.
*
* @template TModel of \Illuminate\Database\Eloquent\Model
*
* @param \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<TModel>|\Illuminate\Database\Eloquent\Relations\Relation<TModel>|\Laravel\Scout\Builder $builder
* @param array<string> $scopes
* @param array<string, mixed> $args
* @param (callable(\Nuwave\Lighthouse\Support\Contracts\ArgBuilderDirective): bool)|null $directiveFilter
*
* @return \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<TModel>|\Illuminate\Database\Eloquent\Relations\Relation<TModel>|\Laravel\Scout\Builder
* @api
*/
public function enhanceBuilder(QueryBuilder|EloquentBuilder|Relation|ScoutBuilder $builder, array $scopes, mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo, callable $directiveFilter = null): QueryBuilder|EloquentBuilder|Relation|ScoutBuilder
public function enhanceBuilder(Builder|ScoutBuilder $builder, array $scopes, mixed $root, array $args, GraphQLContext $context, callable $directiveFilter = null): Builder|ScoutBuilder
{
$argumentSet = $resolveInfo->argumentSet;

$scoutEnhancer = new ScoutEnhancer($argumentSet, $builder);
$scoutEnhancer = new ScoutEnhancer($this->argumentSet, $builder);
if ($scoutEnhancer->canEnhanceBuilder()) {
return $scoutEnhancer->enhanceBuilder();
}

self::applyArgBuilderDirectives($argumentSet, $builder, $directiveFilter);
self::applyFieldBuilderDirectives($builder, $root, $args, $context, $resolveInfo);
self::applyArgBuilderDirectives($this->argumentSet, $builder, $directiveFilter);
self::applyFieldBuilderDirectives($builder, $root, $args, $context, $this);

foreach ($scopes as $scope) {
$builder->{$scope}($args);
Expand All @@ -72,24 +65,24 @@ public function enhanceBuilder(QueryBuilder|EloquentBuilder|Relation|ScoutBuilde
* @param array<string> $scopes
* @param array<string, mixed> $args
* @param (callable(\Nuwave\Lighthouse\Support\Contracts\ArgBuilderDirective): bool)|null $directiveFilter
*
* @api
*/
public function wouldEnhanceBuilder(QueryBuilder|EloquentBuilder|Relation|ScoutBuilder $builder, array $scopes, mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo, callable $directiveFilter = null): bool
public function wouldEnhanceBuilder(Builder|ScoutBuilder $builder, array $scopes, mixed $root, array $args, GraphQLContext $context, callable $directiveFilter = null): bool
{
$argumentSet = $resolveInfo->argumentSet;

return (new ScoutEnhancer($argumentSet, $builder))->wouldEnhanceBuilder()
|| self::wouldApplyArgBuilderDirectives($argumentSet, $builder, $directiveFilter)
|| self::wouldApplyFieldBuilderDirectives($resolveInfo)
return (new ScoutEnhancer($this->argumentSet, $builder))->wouldEnhanceBuilder()
|| self::wouldApplyArgBuilderDirectives($this->argumentSet, $builder, $directiveFilter)
|| self::wouldApplyFieldBuilderDirectives($this)
|| $scopes !== [];
}

/**
* Recursively apply the ArgBuilderDirectives onto the builder.
*
* @param \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<\Illuminate\Database\Eloquent\Model>|\Illuminate\Database\Eloquent\Relations\Relation<\Illuminate\Database\Eloquent\Model> $builder
* @param \Illuminate\Contracts\Database\Query\Builder $builder
* @param (callable(\Nuwave\Lighthouse\Support\Contracts\ArgBuilderDirective): bool)|null $directiveFilter
*/
protected static function applyArgBuilderDirectives(ArgumentSet $argumentSet, QueryBuilder|EloquentBuilder|Relation &$builder, callable $directiveFilter = null): void
protected static function applyArgBuilderDirectives(ArgumentSet $argumentSet, Builder &$builder, callable $directiveFilter = null): void
{
foreach ($argumentSet->arguments as $argument) {
$value = $argument->toPlain();
Expand Down Expand Up @@ -122,10 +115,9 @@ static function ($value) use (&$builder, $directiveFilter): void {
/**
* Would there be any ArgBuilderDirectives to apply to the builder?
*
* @param \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<\Illuminate\Database\Eloquent\Model>|\Illuminate\Database\Eloquent\Relations\Relation<\Illuminate\Database\Eloquent\Model> $builder
* @param (callable(\Nuwave\Lighthouse\Support\Contracts\ArgBuilderDirective): bool)|null $directiveFilter
*/
protected static function wouldApplyArgBuilderDirectives(ArgumentSet $argumentSet, QueryBuilder|EloquentBuilder|Relation &$builder, callable $directiveFilter = null): bool
protected static function wouldApplyArgBuilderDirectives(ArgumentSet $argumentSet, Builder &$builder, callable $directiveFilter = null): bool
{
foreach ($argumentSet->arguments as $argument) {
$filteredDirectives = $argument
Expand Down Expand Up @@ -164,10 +156,9 @@ protected static function wouldApplyArgBuilderDirectives(ArgumentSet $argumentSe
/**
* Apply the FieldBuilderDirectives onto the builder.
*
* @param \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<\Illuminate\Database\Eloquent\Model>|\Illuminate\Database\Eloquent\Relations\Relation<\Illuminate\Database\Eloquent\Model> $builder
* @param array<string, mixed> $args
*/
protected static function applyFieldBuilderDirectives(QueryBuilder|EloquentBuilder|Relation &$builder, mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): void
protected static function applyFieldBuilderDirectives(Builder &$builder, mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): void
{
foreach (self::fieldBuilderDirectives($resolveInfo) as $fieldBuilderDirective) {
$builder = $fieldBuilderDirective->handleFieldBuilder($builder, $root, $args, $context, $resolveInfo);
Expand Down
7 changes: 3 additions & 4 deletions src/OrderBy/OrderByDirective.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@
use GraphQL\Language\AST\InterfaceTypeDefinitionNode;
use GraphQL\Language\AST\ObjectTypeDefinitionNode;
use GraphQL\Language\Parser;
use Illuminate\Contracts\Database\Query\Builder;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Query\Builder as QueryBuilder;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Nuwave\Lighthouse\Exceptions\DefinitionException;
Expand Down Expand Up @@ -112,7 +111,7 @@ enum OrderByDirection {
}

/** @param array<array<string, mixed>> $value */
public function handleBuilder(QueryBuilder|EloquentBuilder|Relation $builder, $value): QueryBuilder|EloquentBuilder|Relation
public function handleBuilder(Builder $builder, $value): Builder
{
foreach ($value as $orderByClause) {
$order = Arr::pull($orderByClause, 'order');
Expand Down Expand Up @@ -260,7 +259,7 @@ public function manipulateArgDefinition(
}
}

public function handleFieldBuilder(QueryBuilder|EloquentBuilder|Relation $builder, mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): QueryBuilder|EloquentBuilder|Relation
public function handleFieldBuilder(Builder $builder, mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): Builder
{
return $builder->orderBy(
$this->directiveArgValue('column'),
Expand Down
23 changes: 4 additions & 19 deletions src/Pagination/PaginateDirective.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,11 @@
use GraphQL\Language\AST\InterfaceTypeDefinitionNode;
use GraphQL\Language\AST\ObjectTypeDefinitionNode;
use Illuminate\Contracts\Pagination\Paginator;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Query\Builder as QueryBuilder;
use Laravel\Scout\Builder as ScoutBuilder;
use Nuwave\Lighthouse\Cache\CacheDirective;
use Nuwave\Lighthouse\Execution\ResolveInfo;
use Nuwave\Lighthouse\Schema\AST\DocumentAST;
use Nuwave\Lighthouse\Schema\Directives\BaseDirective;
use Nuwave\Lighthouse\Schema\Directives\Traits\HasBuilderArgument;
use Nuwave\Lighthouse\Schema\Values\FieldValue;
use Nuwave\Lighthouse\Support\Contracts\ComplexityResolverDirective;
use Nuwave\Lighthouse\Support\Contracts\Directive;
Expand All @@ -23,6 +20,8 @@

class PaginateDirective extends BaseDirective implements FieldResolver, FieldManipulator, ComplexityResolverDirective
{
use HasBuilderArgument;

public static function definition(): string
{
return /** @lang GraphQL */ <<<'GRAPHQL'
Expand Down Expand Up @@ -152,26 +151,12 @@ public function resolveField(FieldValue $fieldValue): callable
return $paginator;
}

if ($this->directiveHasArgument('builder')) {
$builderResolver = $this->getResolverFromArgument('builder');

$query = $builderResolver($root, $args, $context, $resolveInfo);

assert(
$query instanceof QueryBuilder || $query instanceof EloquentBuilder || $query instanceof ScoutBuilder || $query instanceof Relation,
"The method referenced by the builder argument of the @{$this->name()} directive on {$this->nodeName()} must return a Builder or Relation.",
);
} else {
$query = $this->getModelClass()::query();
}

$query = $resolveInfo->enhanceBuilder(
$query,
$this->makeBuilder($root, $args, $context, $resolveInfo),
$this->directiveArgValue('scopes', []),
$root,
$args,
$context,
$resolveInfo,
);

$paginationArgs = PaginationArgs::extractArgs($args, $this->paginationType(), $this->paginateMaxCount());
Expand Down
12 changes: 3 additions & 9 deletions src/Pagination/PaginationArgs.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
namespace Nuwave\Lighthouse\Pagination;

use GraphQL\Error\Error;
use Illuminate\Contracts\Database\Query\Builder;
use Illuminate\Contracts\Pagination\Paginator;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Query\Builder as QueryBuilder;
use Illuminate\Support\Arr;
use Laravel\Scout\Builder as ScoutBuilder;

Expand Down Expand Up @@ -74,13 +72,9 @@ protected static function calculateCurrentPage(int $first, int $after, int $defa
/**
* Apply the args to a builder, constructing a paginator.
*
* @template TModel of \Illuminate\Database\Eloquent\Model
*
* @param \Illuminate\Database\Query\Builder|\Laravel\Scout\Builder|\Illuminate\Database\Eloquent\Builder<TModel>|\Illuminate\Database\Eloquent\Relations\Relation<TModel> $builder
*
* @return \Illuminate\Contracts\Pagination\Paginator<TModel>
* @return \Illuminate\Contracts\Pagination\Paginator<\Illuminate\Database\Eloquent\Model>
*/
public function applyToBuilder(QueryBuilder|ScoutBuilder|EloquentBuilder|Relation $builder): Paginator
public function applyToBuilder(Builder|ScoutBuilder $builder): Paginator
{
$methodName = $this->type->isSimple()
? 'simplePaginate'
Expand Down
8 changes: 4 additions & 4 deletions src/Schema/Directives/AggregateDirective.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
use GraphQL\Language\AST\FieldDefinitionNode;
use GraphQL\Language\AST\InterfaceTypeDefinitionNode;
use GraphQL\Language\AST\ObjectTypeDefinitionNode;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Contracts\Database\Query\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Query\Builder as QueryBuilder;
use Nuwave\Lighthouse\Exceptions\DefinitionException;
use Nuwave\Lighthouse\Execution\BatchLoader\BatchLoaderRegistry;
use Nuwave\Lighthouse\Execution\BatchLoader\RelationBatchLoader;
use Nuwave\Lighthouse\Execution\ModelsLoader\AggregateModelsLoader;
use Nuwave\Lighthouse\Execution\ResolveInfo;
use Nuwave\Lighthouse\Schema\AST\DocumentAST;
use Nuwave\Lighthouse\Schema\Directives\Traits\RelationDirectiveHelpers;
use Nuwave\Lighthouse\Schema\Values\FieldValue;
use Nuwave\Lighthouse\Support\Contracts\FieldManipulator;
use Nuwave\Lighthouse\Support\Contracts\FieldResolver;
Expand Down Expand Up @@ -144,8 +144,8 @@ public function resolveField(FieldValue $fieldValue): callable
$builder = $builderResolver($root, $args, $context, $resolveInfo);

assert(
$builder instanceof QueryBuilder || $builder instanceof EloquentBuilder,
"The method referenced by the builder argument of the @{$this->name()} directive on {$this->nodeName()} must return a Builder.",
$builder instanceof Builder,
"The method referenced by the builder argument of the @{$this->name()} directive on {$this->nodeName()} must return a Builder or Relation.",
);

$this->makeBuilderDecorator($root, $args, $context, $resolveInfo)($builder);
Expand Down
Loading