Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
90 changes: 82 additions & 8 deletions src/Support/SelectFields.php
Original file line number Diff line number Diff line change
Expand Up @@ -207,14 +207,29 @@

static::addAlwaysFields($fieldObject, $field, $parentTable, true);

$with[$relationsKey] = static::getSelectableFieldsAndRelations(
$queryArgs,
$field,
$newParentType,
$customQuery,
false,
$ctx
);
// Check if this is a MorphTo relation
if (is_a($relation, MorphTo::class)) {
// For MorphTo relations, we need to handle them specially
// because they can have different models, and we need to eager load based on the query
static::handleMorphToRelation(
$queryArgs,
$field,
$with,
$ctx,
$fieldObject,
$key,
$customQuery
);
} else {
$with[$relationsKey] = static::getSelectableFieldsAndRelations(
$queryArgs,
$field,
$newParentType,
$customQuery,
false,
$ctx
);
}
} elseif (is_a($parentTypeUnwrapped, \GraphQL\Type\Definition\InterfaceType::class)) {
static::handleInterfaceFields(
$queryArgs,
Expand Down Expand Up @@ -307,7 +322,7 @@
$selectable = true;

// If not a selectable field
if (isset($fieldObject->config['selectable']) && false === $fieldObject->config['selectable']) {

Check failure on line 325 in src/Support/SelectFields.php

View workflow job for this annotation

GitHub Actions / Static Analysis

Ignored error pattern "Result of && is always false." (booleanAnd.alwaysFalse) in path /home/runner/work/graphql-laravel/graphql-laravel/src/Support/SelectFields.php is expected to occur 1 time, but occurred 2 times.
$selectable = false;
}

Expand Down Expand Up @@ -518,6 +533,65 @@
};
}

/**
* Handle MorphTo relations
* @param mixed $ctx
*/
protected static function handleMorphToRelation(

Check failure on line 540 in src/Support/SelectFields.php

View workflow job for this annotation

GitHub Actions / Static Analysis

Method Rebing\GraphQL\Support\SelectFields::handleMorphToRelation() has parameter $with with no value type specified in iterable type array.

Check failure on line 540 in src/Support/SelectFields.php

View workflow job for this annotation

GitHub Actions / Static Analysis

Method Rebing\GraphQL\Support\SelectFields::handleMorphToRelation() has parameter $queryArgs with no value type specified in iterable type array.

Check failure on line 540 in src/Support/SelectFields.php

View workflow job for this annotation

GitHub Actions / Static Analysis

Method Rebing\GraphQL\Support\SelectFields::handleMorphToRelation() has parameter $field with no value type specified in iterable type array.
array $queryArgs,
array $field,
array &$with,
$ctx,
FieldDefinition $fieldObject,
string $key,
?Closure $customQuery
): void {
$relationsKey = Arr::get($fieldObject->config, 'alias', $key);

/* @var GraphqlType $fieldType */
$fieldType = $fieldObject->config['type'];

if ($fieldType instanceof WrappingType) {
$fieldType = $fieldType->getInnermostType();
}

/** @var UnionType $union */
$union = $fieldType;

$relationNames = (isset($union->config['relationName']) && \is_callable($union->config['relationName']))

Check failure on line 561 in src/Support/SelectFields.php

View workflow job for this annotation

GitHub Actions / Static Analysis

Result of && is always false.

Check failure on line 561 in src/Support/SelectFields.php

View workflow job for this annotation

GitHub Actions / Static Analysis

Offset 'relationName' on array{name?: string|null, description?: string|null, types: (callable(): iterable<callable(): GraphQL\Type\Definition\ObjectType|GraphQL\Type\Definition\ObjectType>)|iterable<(callable(): GraphQL\Type\Definition\ObjectType)|GraphQL\Type\Definition\ObjectType>, resolveType?: (callable(mixed, mixed, GraphQL\Type\Definition\ResolveInfo): (callable(): (GraphQL\Type\Definition\ObjectType|string|null)|GraphQL\Deferred|GraphQL\Type\Definition\ObjectType|string|null))|null, resolveValue?: (callable(mixed, mixed, GraphQL\Type\Definition\ResolveInfo): mixed)|null, astNode?: GraphQL\Language\AST\UnionTypeDefinitionNode|null, extensionASTNodes?: array<GraphQL\Language\AST\UnionTypeExtensionNode>|null} in isset() does not exist.
? $union->config['relationName']()
: null;
$with[$relationsKey] = function (MorphTo $relation) use ($queryArgs, $field, $union, $relationNames, $customQuery, $ctx): void {
$morphRelation = [];

foreach ($union->getTypes() as $unionType) {
// Get the model class name for the morph type
if (isset($unionType->config['model'])) {

Check failure on line 569 in src/Support/SelectFields.php

View workflow job for this annotation

GitHub Actions / Static Analysis

Offset 'model' on array{name?: string|null, description?: string|null, resolveField?: (callable(mixed, array<string, mixed>, mixed, GraphQL\Type\Definition\ResolveInfo): mixed)|null, argsMapper?: (callable(array<string, mixed>, GraphQL\Type\Definition\FieldDefinition, GraphQL\Language\AST\FieldNode, mixed): mixed)|null, fields: (callable(): iterable)|iterable, interfaces?: (callable(): iterable<callable(): GraphQL\Type\Definition\InterfaceType|GraphQL\Type\Definition\InterfaceType>)|iterable<(callable(): GraphQL\Type\Definition\InterfaceType)|GraphQL\Type\Definition\InterfaceType>, isTypeOf?: (callable(mixed, mixed, GraphQL\Type\Definition\ResolveInfo): (bool|GraphQL\Deferred|null))|null, astNode?: GraphQL\Language\AST\ObjectTypeDefinitionNode|null, ...} in isset() does not exist.
$modelClass = $unionType->config['model'];
} else {
// Fallback to type name if no model is configured
$modelClass = $relationNames[$unionType->name()] ?? $unionType->name();

Check failure on line 573 in src/Support/SelectFields.php

View workflow job for this annotation

GitHub Actions / Static Analysis

Offset string on null on left side of ?? does not exist.
}

/** @var callable $callable */
$callable = static::getSelectableFieldsAndRelations(
$queryArgs,
$field,
$unionType,
$customQuery,
false,
$ctx
);

$morphRelation[$modelClass] = $callable;
}

if (!empty($morphRelation)) {
$relation->constrain($morphRelation);
}
};
}

public function getSelect(): array
{
return $this->select;
Expand Down
4 changes: 4 additions & 0 deletions src/Support/UnionType.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ public function getAttributes(): array
$attributes['resolveType'] = [$this, 'resolveType'];
}

if (method_exists($this, 'relationName')) {
$attributes['relationName'] = [$this, 'relationName'];
}

return $attributes;
}

Expand Down
38 changes: 38 additions & 0 deletions tests/Database/SelectFields/UnionMorphTests/CommentType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

declare(strict_types = 1);
namespace Rebing\GraphQL\Tests\Database\SelectFields\UnionMorphTests;

use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Facades\GraphQL;
use Rebing\GraphQL\Support\Type as GraphQLType;
use Rebing\GraphQL\Tests\Support\Models\Comment;

class CommentType extends GraphQLType
{
protected $attributes = [
'name' => 'Comment',
'model' => Comment::class,
];

public function fields(): array
{
return [
'id' => [
'type' => Type::nonNull(Type::id()),
],
'title' => [
'type' => Type::nonNull(Type::string()),
],
'body' => [
'type' => Type::string(),
],
'file' => [
'type' => GraphQL::type('File'),
],
'commentable' => [
'type' => GraphQL::type('CommentableUnion'),
],
];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types = 1);
namespace Rebing\GraphQL\Tests\Database\SelectFields\UnionMorphTests;

use GraphQL\Type\Definition\Type as GraphqlType;
use Rebing\GraphQL\Support\Facades\GraphQL;
use Rebing\GraphQL\Support\UnionType;
use Rebing\GraphQL\Tests\Support\Models\Post;
use Rebing\GraphQL\Tests\Support\Models\Product;

class CommentableUnionType extends UnionType
{
protected $attributes = [
'name' => 'CommentableUnion',
];

public function types(): array
{
return [
GraphQL::type('Post'),
GraphQL::type('Product'),
];
}

public function relationName(): array

Check failure on line 26 in tests/Database/SelectFields/UnionMorphTests/CommentableUnionType.php

View workflow job for this annotation

GitHub Actions / Static Analysis

Method Rebing\GraphQL\Tests\Database\SelectFields\UnionMorphTests\CommentableUnionType::relationName() return type has no value type specified in iterable type array.
{
return [
Post::class => 'post',
Product::class => 'product',
];
}

/**
* @param object $value
*/
public function resolveType($value): ?GraphqlType
{
if ($value instanceof Post) {
return GraphQL::type('Post');
}

if ($value instanceof Product) {
return GraphQL::type('Product');
}

return null;
}
}
38 changes: 38 additions & 0 deletions tests/Database/SelectFields/UnionMorphTests/CommentsQuery.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

declare(strict_types = 1);
namespace Rebing\GraphQL\Tests\Database\SelectFields\UnionMorphTests;

use Closure;
use GraphQL\Type\Definition\ResolveInfo;
use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Facades\GraphQL;
use Rebing\GraphQL\Support\Query;
use Rebing\GraphQL\Support\SelectFields;
use Rebing\GraphQL\Tests\Support\Models\Comment;

class CommentsQuery extends Query
{
protected $attributes = [
'name' => 'comments',
];

public function type(): Type
{
return Type::listOf(GraphQL::type('Comment'));
}

public function resolve($root, $args, $context, ResolveInfo $info, Closure $getSelectFields)

Check failure on line 25 in tests/Database/SelectFields/UnionMorphTests/CommentsQuery.php

View workflow job for this annotation

GitHub Actions / Static Analysis

Method Rebing\GraphQL\Tests\Database\SelectFields\UnionMorphTests\CommentsQuery::resolve() has no return type specified.
{
/** @var SelectFields $selectFields */
$selectFields = $getSelectFields();

/** @var Comment[] $comments */
$comments = Comment::query()
->select($selectFields->getSelect())
->with($selectFields->getRelations())
->get();

return $comments;
}
}
35 changes: 35 additions & 0 deletions tests/Database/SelectFields/UnionMorphTests/FileType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types = 1);
namespace Rebing\GraphQL\Tests\Database\SelectFields\UnionMorphTests;

use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Facades\GraphQL;
use Rebing\GraphQL\Support\Type as GraphQLType;
use Rebing\GraphQL\Tests\Support\Models\File;

class FileType extends GraphQLType
{
protected $attributes = [
'name' => 'File',
'model' => File::class,
];

public function fields(): array
{
return [
'id' => [
'type' => Type::nonNull(Type::id()),
],
'name' => [
'type' => Type::string(),
],
'path' => [
'type' => Type::string(),
],
'folder' => [
'type' => GraphQL::type('Folder'),
],
];
}
}
28 changes: 28 additions & 0 deletions tests/Database/SelectFields/UnionMorphTests/FolderType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types = 1);
namespace Rebing\GraphQL\Tests\Database\SelectFields\UnionMorphTests;

use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Type as GraphQLType;
use Rebing\GraphQL\Tests\Support\Models\Folder;

class FolderType extends GraphQLType
{
protected $attributes = [
'name' => 'Folder',
'model' => Folder::class,
];

public function fields(): array
{
return [
'id' => [
'type' => Type::nonNull(Type::id()),
],
'name' => [
'type' => Type::string(),
],
];
}
}
32 changes: 32 additions & 0 deletions tests/Database/SelectFields/UnionMorphTests/PostType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types = 1);
namespace Rebing\GraphQL\Tests\Database\SelectFields\UnionMorphTests;

use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Facades\GraphQL;
use Rebing\GraphQL\Support\Type as GraphQLType;
use Rebing\GraphQL\Tests\Support\Models\Post;

class PostType extends GraphQLType
{
protected $attributes = [
'name' => 'Post',
'model' => Post::class,
];

public function fields(): array
{
return [
'id' => [
'type' => Type::nonNull(Type::id()),
],
'title' => [
'type' => Type::string(),
],
'file' => [
'type' => GraphQL::type('File'),
],
];
}
}
35 changes: 35 additions & 0 deletions tests/Database/SelectFields/UnionMorphTests/ProductType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types = 1);
namespace Rebing\GraphQL\Tests\Database\SelectFields\UnionMorphTests;

use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Facades\GraphQL;
use Rebing\GraphQL\Support\Type as GraphQLType;
use Rebing\GraphQL\Tests\Support\Models\Product;

class ProductType extends GraphQLType
{
protected $attributes = [
'name' => 'Product',
'model' => Product::class,
];

public function fields(): array
{
return [
'id' => [
'type' => Type::nonNull(Type::id()),
],
'name' => [
'type' => Type::string(),
],
'price' => [
'type' => Type::float(),
],
'file' => [
'type' => GraphQL::type('File'),
],
];
}
}
Loading
Loading