Blog Archive

Thursday, 14 November 2013

Entities vs Value Objects and Doctrine 2

Update (4th June 2014): Value Objects can now be used in Doctrine 2.5 (currently still in Beta), using the new 'Embeddables' feature: http://doctrine-orm.readthedocs.org/en/latest/tutorials/embeddables.html. An example is given at the end of this post.

An aspect of Domain Driven Design (DDD) that I find quite appealing is the differentiation between entities and value objects. I don't think you even need to embrace DDD as a whole to benefit from this distinction (I'm not saying you shouldn't embrace DDD, just that this aspect of it stands on its own). If you are using Doctrine 2 though, there is no native support for value objects (not yet anyway), which leaves you with the problem of mapping them yourself. In this post I will talk a bit about the difference between entities and value objects and give one suggestion of how to handle value objects when using Doctrine 2.

What is an entity?

An entity is a class that represents something which has an identity independent of its properties. In other words, even if some of its properties change, its identity remains the same. Entities normally represent the fundamental building blocks of your application.

For example, a Customer would be an entity. A customer record might have various properties like name, address, email address, order list, etc., but even if you change one of those values (eg. if the customer moves house), it is still the same customer.

What is a value object?

A value object is a class (usually small, with just a few properties, and frequently used), that represents a value which has no identity separate from its properties. If any one of its properties change, it is no longer the same value.

An example of a value object is an address. If you change any part of an address, it becomes a different address. Another example would be a price - it might have properties for currency, amount, and payment frequency, but changing any of those would yield a new price.

As such, value objects are immutable - their properties cannot change (it is normal to use getters but not setters for the properties of value objects). If two value objects have exactly the same properties, they can be regarded as equal.

Value objects can have methods, but the behaviour of a method doesn't ever change the object's state. If a method needs to change a property, it will return a brand new instance of the value object instead of modifying the existing one. Methods on a value object can also return other types of value of course (eg. a boolean return value would be typical for a validate method).

Can a Value Object have an Entity as a property?

It doesn't happen very often, but there is nothing wrong with referencing an entity from a value object - having a reference to an entity does not force a value to become an entity. For example, an address value object would typically include a country property. Whilst this would normally be a string, your application might need to have a Country class which has mutable properties (such as whether the country is a member of the EU) and is therefore an entity. But you could still have a country property on your address value object, even if it refers to an entity (I will use this example in the sample code below).

Can an address/price/date range/etc. ever be an Entity?

Yes! Whether something is an entity or a value object depends on how you intend to use it. If you were writing an application for a postal service or a town planner, an address might be more than just a value - you might have the power to change properties of an address without changing its identity (eg. if you can assign house numbers or postcodes).

Why use value objects?

This is really two separate questions, one of which is a little easier to answer than the other...

Why use value objects instead of scalar values?

This is the easy one. You could have a Customer class with properties for address_line_1, address_line_2, etc. - each as a string. Or a phone number could be held as a string with the area code in brackets. By collecting these properties together into a single value object, or separating a string into constituent parts as separate properties of a value object, it is not hard to see that you will gain many OOP benefits. If there are several pieces of data that go together to make a single domain concept, they belong in an object. You can then perform computations on that discrete set of data, validate it, re-use it, and extend it. It also allows you to separate concerns - your entity does not have to worry about any domain logic relating to the value, leading to cleaner code.

Why use value objects instead of Entities?

Why not just give everything an ID and make it an entity? There's no technical reason why you couldn't have an address ID for example, and even allow the properties to be modified. However, although at first glance it might seem as though separating out entities and value objects makes things more complicated, it actually makes things simpler. Why give an address an ID if it doesn't need one? It unnecessarily complicates your model, and could also cause confusion as it is not clear how you intend the data to be used. If something is defined as a value object, we know what it is, that it will not change, and that another object of the same type with the same properties is considered equal to it. This gives us lots more information on how it is meant to be used - so the conceptual difference is valuable in making your code understandable and easy to maintain.

Having said that, if you are using an ORM which does not support value objects (such as Doctrine 2), there is indeed some additional complexity involved, as you need to provide some way of mapping custom value objects to database columns yourself. If you can do this in a way that will be easy to refactor later (when hopefully the next version of Doctrine will support value objects), it might still be worthwhile doing that extra legwork while defining your entities so that you can reap the rewards of improved code clarity and usability.

Using Value Objects with Doctrine 2

Let's take a simplified example. Here is a basic Customer class, including phpDoc annotations for Doctrine 2 (the BaseEntity class it derives from [not shown] contains magic methods __get and __set for accessing the protected properties, as Doctrine 2 doesn't like you to use public properties):

namespace Entities;
/**
* @Entity @Table(name="customer")
* @property int $id
* @property string $name
* @property \ValueObjects\Address $address
* @property string $email_address
* @property string $telephone
**/
class Customer extends BaseEntity
{
    /** @var integer @Id @GeneratedValue @Column(type="integer") */
    protected $id;
    /** @var string @Column(type="string") */
    protected $name = '';
    /** @var \ValueObjects\Address */
    protected $address;
    /** @var string @Column(type="string", length=150) **/
    protected $email_address = '';
    /** @var string @Column(type="string", length=40) **/
    protected $telephone = '';
}

Here we have an Address value object as one of our properties, but we can't map it directly to a column, because it is made up of several fields and Doctrine 2 currently won't resolve them for us. We could give Address an ID and make it an entity, and Doctrine 2 would then be able to map it, but if we want to use a value object, we have to do our own mapping, which I will come to in a minute. First, here is the Address class (the BaseValueObject it derives from has a magic getter but no setter, so the properties are read only):

namespace ValueObjects;
class Address extends BaseValueObject
{
    /** @var string **/
    protected $line_1 = "";
    /** @var string **/
    protected $line_2 = "";
    /** @var string **/
    protected $line_3 = "";
    /** @var string **/
    protected $town = "";
    /** @var string **/
    protected $state = "";
    /** @var string **/
    protected $postcode = "";
    /** @var \Entities\Country **/
    protected $country;

    public function __construct($line_1 = '', $line_2 = '', $line_3 = '',
                                $town = '', $state = '', $postcode = '',
                                \Entities\Country $country = null)
    {
        $this->line_1 = $line_1;
        $this->line_2 = $line_2;
        $this->line_3 = $line_3;
        $this->town = $town;
        $this->state = $state;
        $this->postcode = $postcode;
        $this->country = $country;
    }
}

As described above, the country property of the Address value object here refers to an entity (although it could very well refer to another value object, or just a scalar value).

Now, to enable Doctrine 2 to persist our Customer class, with its Address value object, we will need to tell it how to map to columns to hold each part of the address. We could use a custom mapping type for this, but there is another way which is probably simpler and a little more generic.

As Address is not an entity, and has no identifier (ie. no primary key), the address data cannot be held in a separate table - it will have to go in the same table as the Customer entity. We could therefore just add the fields to our Customer entity and map them to an accessor like this (note that here we do have a setter as well as a getter for the address, because the Customer entity is not immutable):

namespace Entities;
/**
* @Entity @Table(name="customer")
* @property int $id
* @property string $name
* @property \ValueObjects\Address $address
* @property string $email_address
* @property string $telephone
**/
class Customer extends BaseEntity
{
    /** @var integer @Id @GeneratedValue @Column(type="integer") */
    protected $id;
    /** @var string @Column(type="string") */
    protected $name = '';
    /** @var \ValueObjects\Address */
    protected $address;
    /** @var string @Column(type="string", length=150) **/
    protected $email_address = '';
    /** @var string @Column(type="string", length=40) **/
    protected $telephone = '';

    /** @var string @Column(type="string", length=100) **/
    private $address_line_1 = "";
    /** @var string @Column(type="string", length=100) **/
    private $address_line_2 = "";
    /** @var string @Column(type="string", length=100) **/
    private $address_line_3 = "";
    /** @var string @Column(type="string", length=100) **/
    private $address_town = "";
    /** @var string @Column(type="string", length=100) **/
    private $address_state = "";
    /** @var string @Column(type="string", length=100) **/
    private $address_postcode = "";
    /**
    * @ManyToOne(targetEntity="Country", fetch="EAGER")
    * @JoinColumn(name="address_country", referencedColumnName="code")
    * @var Country
    **/
    private $address_country;

    public function setAddress(\ValueObjects\Address $address)
    {
        $this->address = $address;
        $this->address_line_1 = $address->line_1;
        $this->address_line_2 = $address->line_2;
        $this->address_line_3 = $address->line_3;
        $this->address_town = $address->town;
        $this->address_state = $address->state;
        $this->address_postcode = $address->postcode;
        $this->address_country = $address->country;
    }

    /** @return \ValueObjects\Address **/
    public function getAddress()
    {
        if (!isset($this->address)) //Lazy load
        {
            $this->address = new ValueObject\Address(
                    $this->address_line_1,
                    $this->address_line_2,
                    $this->address_line_3,
                    $this->address_town,
                    $this->address_state,
                    $this->address_postcode,
                    $this->address_country);
        }
        return $this->address;
    }
}

Here we have private properties to map the individual parts of the address to database columns without exposing these to the outside world (the magic getter in the base class will not have access to them), but we have a public getter and setter for the address value object.

This will work, but it doesn't look very nice - our Customer class is now bloated with address mapping code. Also, we might have other entities that also need an address, and we don't want to have to copy and paste this all over the place. This is where traits come in handy! We can use a trait to keep the nasty mapping kludge out of our entity, and re-use it wherever an address is needed:
namespace Traits;
/**
* This trait allows us to map address value objects to database columns using Doctrine 2
*/
trait Address
{
    /** @var string @Column(type="string", length=100) **/
    private $address_line_1 = "";
    /** @var string @Column(type="string", length=100) **/
    private $address_line_2 = "";
    /** @var string @Column(type="string", length=100) **/
    private $address_line_3 = "";
    /** @var string @Column(type="string", length=100) **/
    private $address_town = "";
    /** @var string @Column(type="string", length=100) **/
    private $address_state = "";
    /** @var string @Column(type="string", length=100) **/
    private $address_postcode = "";
    /**
    * @ManyToOne(targetEntity="Country", fetch="EAGER")
    * @JoinColumn(name="address_country", referencedColumnName="code")
    * @var Country
    **/
    private $address_country;

    public function setAddress(\ValueObjects\Address $address)
    {
        $this->address = $address;
        $this->address_line_1 = $address->line_1;
        $this->address_line_2 = $address->line_2;
        $this->address_line_3 = $address->line_3;
        $this->address_town = $address->town;
        $this->address_state = $address->state;
        $this->address_postcode = $address->postcode;
        $this->address_country = $address->country;
    }

    /** @return \ValueObjects\Address **/
    public function getAddress()
    {
        if (!isset($this->address)) //Lazy load
        {
            $this->address = new ValueObject\Address(
                    $this->address_line_1,
                    $this->address_line_2,
                    $this->address_line_3,
                    $this->address_town,
                    $this->address_state,
                    $this->address_postcode,
                    $this->address_country);
        }
        return $this->address;
    }
}

Putting the ugly stuff there in the trait means that the only pollution in our entity class is a use statement:
namespace Entities;
/**
* @Entity @Table(name="customer")
* @property int $id
* @property string $name
* @property \ValueObjects\Address $address
* @property string $email_address
* @property string $telephone
**/
class Customer extends BaseEntity
{
    use \Traits\Address; //Allows Doctrine 2 to map the Address value object

    /** @var integer @Id @GeneratedValue @Column(type="integer") */
    protected $id;
    /** @var string @Column(type="string") */
    protected $name = '';
    /** @var \ValueObjects\Address */
    protected $address;
    /** @var string @Column(type="string", length=150) **/
    protected $email_address = '';
    /** @var string @Column(type="string", length=40) **/
    protected $telephone = '';
}

The fly in the ointment

Aside from the fact that manually mapping fields is a bit of a kludge in itself, there is another problem here. What about cases where an entity needs more than one address? Perhaps a billing address and shipping address for example? We can't include the trait twice (well, we could use aliasing, but both would refer to the same values and would require a monumental kludge to differentiate), so we would have to add more traits for the different address types. I still think that is better than putting it all directly in the entity class, but it does smell a bit iffy. What do you think? Is there a better way?

Update: Using Embeddables

If you can use Doctrine 2.5, this problem is easily solved using Embeddables. Here is how you would do the mapping for a customer address in Doctrine 2.5:

namespace ValueObjects;

/** @Embeddable **/
class Address extends BaseValueObject
{
    /** @var string **/
    protected $line_1 = "";
    /** @var string **/
    protected $line_2 = "";
    /** @var string **/
    protected $line_3 = "";
    /** @var string **/
    protected $town = "";
    /** @var string **/
    protected $state = "";
    /** @var string **/
    protected $postcode = "";
    /** @var \Entities\Country **/
    protected $country;
 
    public function __construct($line_1 = '', $line_2 = '', $line_3 = '',
                                $town = '', $state = '', $postcode = '',
                                \Entities\Country $country = null)
    {
        $this->line_1 = $line_1;
        $this->line_2 = $line_2;
        $this->line_3 = $line_3;
        $this->town = $town;
        $this->state = $state;
        $this->postcode = $postcode;
        $this->country = $country;
    }
}


namespace Entities;
/**
* @Entity @Table(name="customer")
* @property int $id
* @property string $name
* @property \ValueObjects\Address $address
* @property string $email_address
* @property string $telephone
**/
class Customer extends BaseEntity
{
    /** @var integer @Id @GeneratedValue @Column(type="integer") */
    protected $id;
    /** @var string @Column(type="string") */
    protected $name = '';
    /** @var \ValueObjects\Address @Embedded(class="\ValueObjects\Address") */
    protected $address;
    /** @var string @Column(type="string", length=150) **/
    protected $email_address = '';
    /** @var string @Column(type="string", length=40) **/
    protected $telephone = '';
}
Painless!

Sunday, 13 October 2013

Active Record vs Data Mapper for Persistence

These two design patterns are explained in Martin Fowler's book 'Patterns of Enterprise Application Architecture', and represent ways of handling data persistence in object oriented programming. Here are the basics:

Active Record Example

class Foo 
{
    protected $db;
    public $id;
    public $bar;
    
    public function __construct(PDO $db)
    {
        $this->db = $db;
    }

    public function do_something()
    {
        $this->bar .= uniqid();
    }

    public function save()
    {
        if ($this->id) {
            $sql = "UPDATE foo SET bar = :bar WHERE id = :id";
            $statement = $this->db->prepare($sql);
            $statement->bindParam("bar", $this->bar);
            $statement->bindParam("id", $this->id);
            $statement->execute();
        }
        else {
            $sql = "INSERT INTO foo (bar) VALUES (:bar)";
            $statement = $this->db->prepare($sql);
            $statement->bindParam("bar", $this->bar);
            $statement->execute();
            $this->id = $this->db->lastInsertId();
        }
    }
}

//Insert
$foo = new Foo($db);
$foo->bar = 'baz';
$foo->save();


In this simplified example, a database handle is injected into the constructor of Foo (using dependency injection here allows the object to be unit tested without using a real database), and Foo uses that to save its own data. The do_something method is just a placeholder for some business logic.

Active Record advantages

  • It is fairly quick and easy to write an active record object, particularly when the properties of the object correlate directly with columns in the database.
  • Everything is kept in one place, making it easier to see how the code works.

Active Record disadvantages

  • The Active Record pattern breakes SOLID design principles - in particular the Single Responsibility Principle (SRP - the 'S' of SOLID). According to the SRP, a domain object should only have a single responsibility, ie. its own business logic. By asking it to handle persistence as well, you are giving it an additional responsibility, and this increases the complexity of the object - making it more difficult to maintain and test.
  • The persistence implementation is closely coupled with the business logic, meaning that if you later wanted to use a different persistence layer (for example to store the data in an XML file instead of a database), you would need to refactor the code.

Data Mapper Example

class Foo 
{
    public $id;
    public $bar;

    public function do_something()
    {
        $this->bar .= uniqid();
    }
}

class FooMapper
{
    protected $db;

    public function __construct(PDO $db)
    {
        $this->db = $db;
    }
    public function saveFoo(Foo &$foo)
    {
        if ($foo->id) {
            $sql = "UPDATE foo SET bar = :bar WHERE id = :id";
            $statement = $this->db->prepare($sql);
            $statement->bindParam("bar", $foo->bar);
            $statement->bindParam("id", $foo->id);
            $statement->execute();
        }
        else {
            $sql = "INSERT INTO foo (bar) VALUES (:bar)";
            $statement = $this->db->prepare($sql);
            $statement->bindParam("bar", $foo->bar);
            $statement->execute();
            $foo->id = $this->db->lastInsertId();
        }
    }
}

//Insert
$foo = new Foo();
$foo->bar = 'baz';
$mapper = new FooMapper($db);
$mapper->saveFoo($foo);


Here the Foo class is a lot simpler and only has to worry about its own business logic. Not only does it not have to persist its own data, it doesn't even know or care whether its data is persisted at all. The FooMapper class doesn't contain any business logic, but it does handle the data persistence, and all of the SQL is tucked away in the mapper class.

Data Mapper advantages

  • Each object has a single responsibility, thus preserving the integrity of SOLID design principles, and keeping each object simple and to the point.
  • The business logic and persistence are loosely coupled - if you want to persist in an XML file or some other format, you can just write a new mapper and don't have to touch the domain object.

Data Mapper disadvantages

  • You have to think a bit harder before you type!
  • You end up with more objects to manage, which makes the calling code a little more complex and slightly harder to follow.

Service Objects

When using the data mapper pattern, the calling code has to choose a mapper object and a business object and put them together. If this calling code is in your controller, you could end up having your model layer leak into your controller, and this can cause more difficulties with maintenance and unit testing. This problem can be resolved by introducing a service object. The service object is the gateway between the controller and the model, and it handles marrying up domain objects with their mappers as necessary.

It should of course be remembered that the M in MVC, represents a model layer, not necessarily a model object. There could be several types of object in a single model (in the above example, you could have a service object, domain object, and data mapper object, all forming a single model). If you use the active record pattern on the other hand, your model could well be just a single object.

Which option to use

Active record objects have historically been very popular due to them being simpler, easier to understand and quicker to write, and many PHP frameworks and ORMs use the active record pattern by default. If you are confident that you will never need to swap out the persistence layer (perhaps when dealing with an object which represents an .ini file for example), or are dealing with very simple objects that don't have much (or even any) business logic, or just prefer to keep things contained in fewer classes, the active record pattern may make the most sense.

Using a data mapper though does lead to cleaner, easier to test, easier to maintain code, and allows for greater extensibility - at the cost of slightly increased complexity. If you haven't tried it before, give it a whirl - you might like it.