-
-
Notifications
You must be signed in to change notification settings - Fork 893
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[GraphQl] Support for unions and interfaces for search functionality #2927
Labels
Comments
samzijlmans
changed the title
GraphQl: Support for unions and interfaces for search functionality
[GraphQl] Support for unions and interfaces for search functionality
Jul 11, 2019
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.
// 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
}
}
}
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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!
The text was updated successfully, but these errors were encountered: