Skip to content
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

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

Open
mmaedler opened this issue Oct 12, 2021 · 3 comments

Comments

@mmaedler
Copy link

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
Copy link

ES-Six commented Oct 15, 2021

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 :

  • setCreatedAt
  • getCreatedAt
  • setUpdatedAt
  • getUpdatedAt

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

@mmaedler
Copy link
Author

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
Copy link

ES-Six commented Oct 22, 2021

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

#593

#372

#266

#277

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

Pros :

  • API Platform seem's to support traits.
  • An entity can use multiple traits at the same time.

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

  • Using attributes at class level. (not possible in traits)
  • It's more complex to handle normalizer compatibility based on traits used in a class (because sometime the normalizer support method can receive a doctrine Proxy class instead of the entity, this case must be handled manually).

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

No branches or pull requests

2 participants