Open samzijlmans opened 5 years ago
Is this something that is planned or any advice how to deal with it meanwhile? This rules out a big part of GraphQL capabilities.
would love to see this implemented. in a meantime I got fragments working for collection for my setup like this.
I have different types, not OneComment and AnotherComment. this is just for demonstration
// api/src/Entity/Comment.php
//...
#[ORM\InheritanceType('SINGLE_TABLE')]
#[ORM\DiscriminatorColumn(name: 'type', type: 'string')]
#[ORM\DiscriminatorMap([
'one' => OneComment::class,
'another' => AnotherComment::class,
])]
class Comment
{
//...
// api/src/Entity/OneComment.php
//...
class OneComment extends Comment
{
//...
// api/src/Entity/AnotherComment.php
//...
class AnotherComment extends Comment
{
//...
# api/config/services.yaml:
# ...
App\Type\TypeConverter:
decorates: api_platform.graphql.type_converter
App\Type\UnionCommentType:
tags:
- { name: api_platform.graphql.type }
ApiPlatform\GraphQl\Type\TypeBuild
// api/src/Type/TypeConverter.php
<?php
namespace App\Type;
use ApiPlatform\GraphQl\Type\TypeConverterInterface;
use ApiPlatform\Metadata\GraphQl\Operation;
use App\Entity\Comment;
use GraphQL\Type\Definition\Type as GraphQLType;
use Symfony\Component\PropertyInfo\Type;
final class TypeConverter implements TypeConverterInterface
{
public function __construct(
private TypeConverterInterface $defaultTypeConverter,
private UnionCommentType $unionCommentType,
) {
}
/**
* {@inheritdoc}
*/
public function convertType(
Type $type,
bool $input,
Operation $rootOperation,
string $resourceClass,
string $rootResource,
?string $property,
int $depth
): GraphQLType|string|null {
if ($type->isCollection() && $type->getCollectionValueTypes()[0]->getClassName() === Comment::class) {
return $this->unionCommentType;
}
return $this->defaultTypeConverter->convertType(
type: $type,
input: $input,
rootOperation: $rootOperation,
resourceClass: $resourceClass,
rootResource: $rootResource,
property: $property,
depth: $depth,
);
}
/**
* {@inheritdoc}
*/
public function resolveType(string $type): ?GraphQLType
{
return $this->defaultTypeConverter->resolveType($type);
}
}
// api/src/Type/UnionCommentType.php
<?php
namespace App\Type;
use ApiPlatform\GraphQl\Type\Definition\TypeInterface;
use ApiPlatform\GraphQl\Type\TypeBuilderEnumInterface;
use ApiPlatform\Metadata\GraphQl\QueryCollection;
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
use App\Entity\OneComment;
use App\Entity\AnotherComment;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\UnionType;
final class UnionCommentType extends UnionType implements TypeInterface
{
/**
* @var array<string, ObjectType>
*/
private array $commentTypes;
public function __construct(
private readonly TypeBuilderEnumInterface $typeBuilder,
private readonly ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory,
) {
$this->name = 'UnionComment';
$this->description = 'Union type for all Comment types';
$this->astNode = null;
$this->extensionASTNodes = [];
$this->commentTypes = [
OneComment::class => $this->getCommentType(OneComment::class),
AnotherComment::class => $this->getCommentType(AnotherComment::class),
];
$this->config = [
'name' => 'UnionComment',
'description' => 'Union type for all Comment types',
'types' => $this->commentTypes,
'resolveType' => fn ($objectValue) => $this->commentTypes[$objectValue['#itemResourceClass']],
'astNode' => null,
'extensionASTNodes' => [],
];
}
public function getName(): string
{
return 'UnionComment';
}
private function getCommentType(string $resourceClass): ObjectType
{
$resourceMetadataCollection = $this->resourceMetadataCollectionFactory->create($resourceClass);
$operationName = 'collection_query';
$operation = $resourceMetadataCollection->getOperation($operationName);
assert($operation instanceof QueryCollection);
$type = $this->typeBuilder->getResourceObjectType(
resourceClass: $resourceClass,
resourceMetadataCollection: $resourceMetadataCollection,
operation: $operation,
input: false,
wrapped: false,
depth: 0
);
assert($type instanceof ObjectType);
return $type;
}
}
query {
comments() {
collection {
id
... on OneComment {
id
body
}
... on AnotherComment {
id
body
}
}
}
}
I am trying to create a general search functionality in my app that can return multiple types of objects. For each type of object I want to retrieve different fields.
In the graphQl specification this is supported using interfaces and unions. See this example below:
See this guide for more details.
I tried making all my entities extend a 'base' entity and creating the search query on that entity, but that did not work.
Thanks in advance!