I have been implementing value objects as custom DBAL types in Doctrine 2 and it's been working OK. However I have been wondering if this is the best way. I've thought about using the Post Load listener to instantiate the Value Objects. Also instantiating them through Entity accessors when requested, the advantage with the latter would be that I would not instantiate more objects than I need.
My question is: which method is best? Or is there a better way to do it? Are there any gotchas or unreasonable performance hits with the above?
IMHO, both approaches are equally valuable, while waiting for native support for value objects.
I personally favor the second approach (instantiating them through accessors when requested) for two reasons:
- As you mentioned, it offers better performance as the conversion is only done when needed;
- It decouples your application from Doctrine dependency: you're writing less code that is Doctrine-specific.
An example of this approach:
class User
{
protected $street;
protected $city;
protected $country;
public function setAddress(Address $address)
{
$this->street = $address->getStreet();
$this->city = $address->getCity();
$this->country = $address->getCountry();
}
public function getAddress()
{
return new Address(
$this->street,
$this->city,
$this->country
);
}
}
This code will be fairly easy to refactor when Doctrine will offer native VO support.
About custom mapping types, I do use them as well, for single-field VO (Decimal
, Point
, Polygon
, ...) but would tend to reserve them for general-purpose, reusable types that can be used across multiple projects, not for project-specific single-field VO where I would favor the approach above.