Overriding inversedBy mapping in Doctrine 2 inheritance

Unidirectional / bidirectional

Doctrine 2 uses the concept of unidirectional associations and bidirectional associations.

When defining a unidirectional association you have to omit the inversedBy parameter, because the association isn't inversed.

When defining a bidirectional association you have to use the inversedBy parameter on the owning side (that's the side that actually contains all metadata for Doctrine to properly map the association), and you have to use the mappedBy parameter on the inversed side (so that Doctrine knows where to look for the actual mapping metadata for the association).

So you either use both inversedBy and mappedBy (bidirectional) or you don't use them at all (unidirectional).

Principle of inheritance

But it is cumbersome and goes against the principle of inheritance.

I think that depends on how you look at it:

If you only look at the code (not the mapping), you are correct. Both concrete implementations of OrderTime share a property $restaurant (and probably getters, setters, and maybe other logic), so the principle dictates that you define that in OrderTime.

But when you look at the mapping, you have 2 different associations: One that ties Restaurant::$collectionTimes and CollectionTime::$restaurant together, and one that ties Restaurant::$deliveryTimes and DeliveryTime::$restaurant together.

Because these are 2 different associations, it's only fair that Doctrine wants you to properly define them both.

You can still stick to principle of inheritance in the following way: Define all shared logic you need in OrderTime, even the property $restaurant, just don't add the mapping metadata. In the concrete implementations you can redeclare the property $restaurant with the proper mapping metadata.

The only reason you have to redeclare the property $restaurant in those concretes is that you're using Annotations for mapping metadata. When using Yaml or XML, you don't have to redeclare the property because the mapping metadata will be in separate files.

So in fact it's not code/logic you're defining in those concrete implementations, it's the mapping metadata.

Value Object

Those OrderTime classes look more like Value Objects to me (not Entities): A small simple object, like money or a date range, whose equality isn't based on identity.

Doctrine will support Value Objects starting with version 2.5 (see here).


You can override inversedBy since Doctrine 2.6. That would look like that:

/**
 * @Entity
 * @ORM\AssociationOverrides({
 *     @ORM\AssociationOverride(name="restaurant", inversedBy="collectionTimes")
 * })
 */
class CollectionTime extends OrderTime
{
}

/**
 * @Entity
 * @ORM\AssociationOverrides({
 *     @ORM\AssociationOverride(name="restaurant", inversedBy="deliveryTimes")
 * })
 */
class DeliveryTime extends OrderTime
{
}

Tags:

Doctrine Orm