Skip to content

Conversation

@alanpoulain
Copy link
Member

See #4613 (comment).

Supersedes #4930.

Fixes api-platform/api-platform#2296.

The principal issue was mainly because the root operation was used instead of the nested resource one.

This PR also improves how GraphQL handles a nested resource when the query operation does not exist.
Instead of having a fallback on the REST operation (and an exception if it does not exist), it creates a "dynamic" resource having the default operations.
This dynamic resource is created using a new DynamicExtractor with an addResource method, which can take an optional configuration array.

In the future, I think this could be useful to control how a nested resource is handled by GraphQL (for instance by using the ApiProperty attribute).

@alanpoulain alanpoulain force-pushed the fix/graphql-nested-resource-operation branch from 85e4479 to ee8fc86 Compare October 27, 2022 16:57
@alanpoulain alanpoulain merged commit 44337dd into api-platform:3.0 Nov 2, 2022
final class FieldsBuilder implements FieldsBuilderInterface
{
public function __construct(private readonly PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, private readonly PropertyMetadataFactoryInterface $propertyMetadataFactory, private readonly ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory, private readonly ResourceClassResolverInterface $resourceClassResolver, private readonly TypesContainerInterface $typesContainer, private readonly TypeBuilderInterface $typeBuilder, private readonly TypeConverterInterface $typeConverter, private readonly ResolverFactoryInterface $itemResolverFactory, private readonly ResolverFactoryInterface $collectionResolverFactory, private readonly ResolverFactoryInterface $itemMutationResolverFactory, private readonly ResolverFactoryInterface $itemSubscriptionResolverFactory, private readonly ContainerInterface $filterLocator, private readonly Pagination $pagination, private readonly ?NameConverterInterface $nameConverter, private readonly string $nestingSeparator)
public function __construct(private readonly PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, private readonly PropertyMetadataFactoryInterface $propertyMetadataFactory, private readonly ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory, private readonly DynamicResourceExtractorInterface $dynamicResourceExtractor, private readonly ResourceClassResolverInterface $resourceClassResolver, private readonly TypesContainerInterface $typesContainer, private readonly TypeBuilderInterface $typeBuilder, private readonly TypeConverterInterface $typeConverter, private readonly ResolverFactoryInterface $itemResolverFactory, private readonly ResolverFactoryInterface $collectionResolverFactory, private readonly ResolverFactoryInterface $itemMutationResolverFactory, private readonly ResolverFactoryInterface $itemSubscriptionResolverFactory, private readonly ContainerInterface $filterLocator, private readonly Pagination $pagination, private readonly ?NameConverterInterface $nameConverter, private readonly string $nestingSeparator)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

breaks BC layer

* {@inheritdoc}
*/
public function getResourcePaginatedCollectionType(GraphQLType $resourceType, string $resourceClass, Operation $operation): GraphQLType
public function getResourcePaginatedCollectionType(GraphQLType $resourceType, Operation $operation): GraphQLType
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BC layer is broken

* Gets the type of a paginated collection of the given resource type.
*/
public function getResourcePaginatedCollectionType(GraphQLType $resourceType, string $resourceClass, Operation $operation): GraphQLType;
public function getResourcePaginatedCollectionType(GraphQLType $resourceType, Operation $operation): GraphQLType;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't change an interface like this right?

$dynamicResourceName = $this->getDynamicResourceName($resourceClass);

$this->dynamicResources[$dynamicResourceName] = [
array_merge(['class' => $resourceClass], $config),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

array_merge is quite slow for this we could just add the class to the config right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it doesn't impact performance but we can.

*
* @author Alan Poulain <contact@alanpoulain.eu>
*/
interface DynamicResourceExtractorInterface extends ResourceExtractorInterface
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we really need to add a new interface? its wanted that a ResourceExtractorInterface doesn't have an addResource we're using a Factory to prepare resources inside it no?

Copy link
Member Author

@alanpoulain alanpoulain Nov 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need an interface since this method needs to be called from the fields builder.

public function isDynamic(): bool
{
return str_starts_with($this->resourceClass, self::DYNAMIC_RESOURCE_CLASS_PREFIX);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really don't like this graphql-specific code here, can you explain this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not GraphQL-specific. The aim is to create metadata for a resource which doesn't exist.


public function isDynamic(): bool
{
return str_starts_with($this->resourceClass, self::DYNAMIC_RESOURCE_CLASS_PREFIX);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imo resourceClass should be a class-string this breaks it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure but we need a way to distinguish a dynamic resource for a normal one.

soyuka added a commit that referenced this pull request Nov 3, 2022
soyuka added a commit that referenced this pull request Nov 4, 2022
soyuka added a commit that referenced this pull request Nov 4, 2022
* fix: update yaml extractor test file coding standard (#5068)

* fix(graphql): add clearer error message when TwigBundle is disabled but graphQL clients are enabled (#5064)

* fix(metadata): add class key in payload argument resolver (#5067)

* fix: add class key in payload argument resolver

* add null if everything else goes wrong

* fix: upgrade command remove ApiSubresource attribute  (#5049)

Fixes #5038

* fix(doctrine): use abitrary index instead of value (#5079)

* fix: uri template should respect rfc 6570 (#5080)

* fix: remove @internal annotation for Operations (#5089)

See #5084

* fix(metadata): define a name on a single operation (#5090)

fixes #5082

* fix(metadata): deprecate when user decorates in legacy mode (#5091)

fixes #5078

* fix(graphql): use right nested operation (#5102)

* Revert "fix(graphql): use right nested operation (#5102)" (#5111)

This reverts commit 44337dd.

* fix(graphql): always allow to query nested resources (#5112)

* fix(graphql): always allow to query nested resources

* review

Co-authored-by: Alan Poulain <contact@alanpoulain.eu>

* chore: php-cs-fixer update

* fix: only alias if exists for opcache preload

Fixes api-platform/api-platform#2284 (#5110)

Co-authored-by: Liviu Mirea <liviu.mirea@wecodepixels.com>

* chore: php-cs-fixer update (#5118)

* chore: php-cs-fixer update

* chore: php-cs-fixer update

* fix(metadata): upgrade script keep operation name (#5109)

origin: #5105

Co-authored-by: WilliamPeralta <william.peralta18@gmail.com>

* chore: v2.7.3 changelog

* chore: v3.0.3 changelog

Co-authored-by: helyakin <CourcierMarvin@gmail.com>
Co-authored-by: ArnoudThibaut <thibaut.arnoud@gmail.com>
Co-authored-by: davy-beauzil <38990335+davy-beauzil@users.noreply.github.com>
Co-authored-by: Baptiste Leduc <baptiste.leduc@gmail.com>
Co-authored-by: Xavier Laviron <norival@users.noreply.github.com>
Co-authored-by: Alan Poulain <contact@alanpoulain.eu>
Co-authored-by: Liviu Cristian Mirea-Ghiban <contact@liviucmg.com>
Co-authored-by: Liviu Mirea <liviu.mirea@wecodepixels.com>
Co-authored-by: WilliamPeralta <william.peralta18@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants