Prerequisites:
I wonder if it's possible to override an inversedBy
attribute of a property association mapping that's taken from a trait.
An interface that I use as a concrete user entity placeholder:
ReusableBundle\ModelEntrantInterface.php
interface EntrantInterface
{
public function getEmail();
public function getFirstName();
public function getLastName();
}
User
entity that implements EntrantInterface
and all other entities that are derived from these abstract classes in AppBundle
):ReusableBundle\Entity\Entry.php
/**
* @ORM\MappedSuperclass
*/
abstract class Entry
{
/**
* @var EntrantInterface
*
* @ORM\ManyToOne(targetEntity="ReusableBundle\Model\EntrantInterface", inversedBy="entries")
* @ORM\JoinColumn(name="user_id")
*/
protected $user;
// getters/setters...
}
ReusableBundle\Entity\Timestamp.php
/**
* @ORM\MappedSuperclass
*/
abstract class Timestamp
{
/**
* @var EntrantInterface
*
* @ORM\ManyToOne(targetEntity="ReusableBundle\Model\EntrantInterface", inversedBy="timestamps")
* @ORM\JoinColumn(name="user_id")
*/
protected $user;
// getters/setters...
}
And couple more entities with similar structure that utilize EntranInterface
UserAwareTrait
to be reusable across several entities:ReusableBundle\Entity\Traits\UserAwareTrait.php
trait UserAwareTrait
{
/**
* @var EntrantInterface
*
* @ORM\ManyToOne(targetEntity="ReusableBundle\Model\EntrantInterface")
* @ORM\JoinColumn(name="user_id")
*/
protected $user;
// getter/setter...
}
In Doctrine 2.6 if I would use super class and wanted to override its property I'd do this:
/**
* @ORM\MappedSuperclass
* @ORM\AssociationOverrides({
* @ORM\AssociationOverride({name="property", inversedBy="entities"})
* })
*/
abstract class Entity extends SuperEntity
{
// code...
}
But if I want that Entity to use UserAwareTrait
and override association mapping of a property...
/**
* @ORM\MappedSuperclass
* @ORM\AssociationOverrides({
* @ORM\AssociationOverride({name="user", inversedBy="entries"})
* })
*/
abstract class Entry
{
use UserAwareTrait;
// code...
}
... and run php bin/console doctrine:schema:validate
I see this error in the console:
[Doctrine\ORM\Mapping\MappingException]
Invalid field override named 'user' for class 'ReusableBundle\Entity\Entry'.
Is there a workaround that I could follow to achieve the desired result?
Use trait to store shared properties
Override assotiation mapping or (possibly) attributes mapping in the class that uses that trait
TL;DR You should change the access modificator from protected
to private
. Don't forget that you will not be able to directly manipulate the private property in a subclass and will need a getter.
The exception appears due to the bug (I believe, or a quirk of the behavior) in the AnnotationDriver
.
foreach ($class->getProperties() as $property) {
if ($metadata->isMappedSuperclass && ! $property->isPrivate()
||
...) {
continue;
}
It skips all non-private properties for MappedSuperclass
letting them to compose metadata on the subclass parsing. But when it comes to overriding the driver tries to do it at a MappedSuperclass
level, it doesn't remember that the property was skipped, fails to find it in the metadata and raise an exception.
I made a detailed explanation at the issue. You can find there also the link to the unit tests that highlight the case.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With