api-platform / api-platform

🕸️ Create REST and GraphQL APIs, scaffold Jamstack webapps, stream changes in real-time.
https://api-platform.com
MIT License
8.43k stars 953 forks source link

Trait injected ApiProperty Attribute gets ignored in STI Entity extending Classes #2043

Open mmaedler opened 2 years ago

mmaedler commented 2 years ago

API Platform version(s) affected: 2.6.5 (api-platform/core)

Description
To reflect different kinds of people types in my application I have decided to go with doctrines single table inheritance (STI) feature to build my entities. These entities all share the fact that they are timestampable via a trait that gets injected in the parent class Person. I have this class structure (simplified) for my entities:


trait Timestampable
{
    #[ORM\Column(type: 'datetime_immutable')]
    #[ApiProperty(writable: false)]
    private ?DateTimeImmutable $createdAt = null;

    #[ORM\Column(type: 'datetime', nullable: true)]
    #[ApiProperty(writable: false)]
    private ?DateTime $updatedAt = null;

    // Setters, getters and Lifecycle callbacks
    // ..
}

abstract class Person 
{
    use Timestampable;

    // further shared properties
}

#[ApiRessource]
final class Giver extends Person
{
    // further properties
}

#[ApiRessource]
final class Donnee extends Person
{
    // further properties
}

#[ApiRessource]
final class Item
{
    use Timestampable;

    // further shared properties
}

As you can see I have set the two properties $createdAt and $updatedAt as non-writable since it wouldn't make any sense to update them via API call. This is working fine when writing Item ressource entries, but for both Giver and Donnee ressources createdAt could be set via API.

If I move the trait injection from the parent class Person into the two subclasses it works as expected (but again won't make too much sense).

So not sure if this is really a bug or just a misunderstanding of concepts on my end. Therefore, any hint would be appreciated.

Thank you!

ES-Six commented 2 years ago

I'm using traits to do a Timestampabletrait on a project with the #[ApiProperty(...)] attribute in the traits and it's working well.

The only difference is I'm not using the writable: false property.

You can try to clear symfony cache with the php bin/console cache:clear command and ensure the getter and setter are named properly as ApiPlatform need them :

If it doesn't work, perhaps the problem is located on the ApiPlatform side especifically when using the writable property.

mmaedler commented 2 years ago

Thanks for your reply. In my example for Entity Item it filtering the writeable works just fine using the trait. However for the Entites that extend a parent entity it doesn't. Prove for the correct implementation is that the doctrine part (setting timestamps onCreate/onUpdate) works for all of them. Therefore my assumption was, that there might be an issue with serialization process within ApiPlatform.

ES-Six commented 2 years ago

It seem's API Platform doesn't officially support entity inheritance, see issues :

https://github.com/api-platform/api-platform/issues/593

https://github.com/api-platform/api-platform/issues/372

https://github.com/api-platform/api-platform/issues/266

https://github.com/api-platform/api-platform/issues/277

There is a lot more issues related to inheritance. I recommend using trait inside entities instead when it's possible.

Pros :

Cons : But traits can have sometime have some caveheat when :