Core: One-To-Many non-doctrine entities

Created on 17 Apr 2019  路  5Comments  路  Source: api-platform/core

Hello!
I think my question is common enough and was asked before, but I didnt find something similar.
So, if I have 2 not-doctrine entities:

/**
* ApiResource
*/
class Parent
{
/**
    /**
     * @ApiProperty(identifier=true)
     *
     * @var int
     */
    public $id;

    /**
     * @ApiSubresource()
     *
     * @var Child[]|null
     */
    public $childs = [];
}

/**
 * @ApiResource
 */
class Child
{  
    /**
     * @ApiProperty(identifier=true)
     *
     * @var int
     */
    public $id;
}

Then in GraphQl schema I see that both of these classes were recognized by SchemaBuilder, but Parent has no proper one-to-many link to Child - childs property has type Iterable instead of Child[].

What am I missing here?

Thanks.

GraphQL bug duplicate

Most helpful comment

Hello @Siregacvek,

we had some discussion about this issue in https://github.com/api-platform/core/issues/2687. You ca take a look there, I need to write a Behat test for this

All 5 comments

This is a known issue. I will fix it when I have some time.

@alanpoulain thanks for an answer. How do you think, this is only a Schema Builder issue or it's something what involves many different classes and subsystems of ApiP?
If it's only related to Schema Builder, I can try to investigate this myself and create PR.

Hello @Siregacvek,

we had some discussion about this issue in https://github.com/api-platform/core/issues/2687. You ca take a look there, I need to write a Behat test for this

@alanpoulain @Maxell92 looks like I solved my issue (not sure that this will work for @Maxell92 case). The issue is here https://github.com/api-platform/core/blob/be932e901402000adf54fa38e0b741f36474be79/src/GraphQl/Type/SchemaBuilder.php#L369-L386

In my case when field is a collection of not-doctrine objects, the $type->getBuiltinType() returns array type, and code falls to wrong case branch. I did the following:

  1. Added the method to determine that we are working with array of objects:
    private function isArrayOfObjects(Type $type): bool
    {
        return Type::BUILTIN_TYPE_ARRAY === $type->getBuiltinType() &&
            $type->getCollectionValueType() &&
            Type::BUILTIN_TYPE_OBJECT === $type->getCollectionValueType()->getBuiltinType();
    }
  1. Improved isCollection method:
    private function isCollection(Type $type): bool
    {
        return ($type->isCollection() && Type::BUILTIN_TYPE_OBJECT === $type->getBuiltinType()) || $this->isArrayOfObjects($type);
    }
  1. Slightly changed case branch for array (quite tricky, don't totally like my implementation but it works):
...
            case Type::BUILTIN_TYPE_ARRAY:
            case Type::BUILTIN_TYPE_ITERABLE:
                if (!$this->isArrayOfObjects($type)) {
                    $graphqlType = $this->graphqlTypes['Iterable'];
                    break;
                }
...

After these changes the schema works fine for me.

But the next problem was that my childs field is empty always. I explored the code and noticed, that there is a CollectionResolver class which handles my case:
https://github.com/api-platform/core/blob/be932e901402000adf54fa38e0b741f36474be79/src/GraphQl/Resolver/Factory/CollectionResolverFactory.php#L86-L89
It delegates fetching collection to src/Bridge/Doctrine/Orm/SubresourceDataProvider.php which of course can't find the items. So I was needed to create my custom implementation of SubresourceDataProviderInterface and it finally works for me.

@alanpoulain please, let me know if I solved the issue in a wrong way.

Was this page helpful?
0 / 5 - 0 ratings