DEV Community

Adamo Crespi for Serendipity HQ

Posted on • Originally published at io.serendipityhq.com on

Value Objects, Immutable objects and Doctrine Embeddables

I was thinking about some entities I need, when I came across a very interesting concept: Immutable Objects.

The Immutable Objects are very handy to manage the so called Value Objects.

In the Domain Driven Design (DDD) properties of an Entity can have two different values: other Entities (Order->getProduct() – here Product is an Entity and its properties can change) or simple values (Product->getPrice()).

Price, in our example, is a simple value, not conceptually an Entity. Until now, it probably is a simple property in your Entities (as it was in mine!).

But, in this second case, the Value Objects play their parts: they represent those values in an immutable state.

In fact, if you reflect about the data Price , you realize that a Price is something like “100 Eur”. If you put your attention on the value, you can recognize more than one smaller parts in it: a numeric value – 100 – and a string value – Eur.

A Price is a Price only if we indicate both the numeric part of it (100) and the string part of it (Eur): If we indicate only one of the two, it is not a Price because we don’t know how much money does it represents or in which currency the price is expressed.

So we need both the “amount” and the “currency” to have a real value. Think it as a “composite value”.

And the important thing to consider to understand what Immutable stands for: if in the Price we change the amount, we have a different price. If in the Price we change the currency, we have, again, a different price.

But if in a Product we change the Price, we don’t have a different Product but the same one with only a different Price.

What an Immutable Object is?

Using some words written by others:

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).

So, if a Product with a different Price is ever the same Product (read: THE SAME Entity Object, only with a different Price. PHP will recognize the different Price as a modification of the original Product PHP Object), then a different Price is something completely different from the previous Price (read: it is A DIFFERENT Value Object and for PHP the two Prices are two different and separate objects).

Those behaviors are obtained writing the code of the two kind of classes (Value Object or Entity Object) in different ways and implementing methods with different behaviors when we interact with the Objects.

So, knowing the conceptual differences between a pure Entity Object class and a Value Object class permits us to write more solid code and better organize our business logic.

A simple example of an Immutable Object

So, as you can see from the example, this small class respect all the constraints of the definition of “Immutable Object”:

  1. Represents a value which has no identity separate from its properties;
  2. Its values can be passed only through the __construct() and so it hasn’t setter methods ($this->__set() is even overridden and with no body to prevent accidental modification to the properties);
  3. It returns a brand new instance of Email if a change is required.

And it is also really small as class!

How to manage Value Objects using Doctrine

Starting since the version 2.5, Doctrine supports the use of Value Objects, calling them Embeddables.

Embeddables are classes which are not entities themself, but are embedded in entities and can also be queried in DQL. You’ll mostly want to use them to reduce duplication or separating concerns. Value objects such as date range or address are the primary use case for this feature. Embeddables can only contain properties with basic @Column mapping.

This is a simple example of an AddressEmbeddable implemented in a dummy User Entity:

<?php 

/** @Entity */
class User
{
    /** @Embedded(class = "Address") */
    private $address;
}

/** @Embeddable */
class Address
{
    /** @Column(type = "string") */
    private $street;

    /** @Column(type = "string") */
    private $postalCode;

    /** @Column(type = "string") */
    private $city;

    /** @Column(type = "string") */
    private $country;
}
Enter fullscreen mode Exit fullscreen mode

The advantages

Before Embeddable, we could only do two things to manage a Value Object (as the AddressEmbeddable is):

  1. Create an Entity Address and use the relation OneToOne or ManyToOne/OneToMany (One Address for one Entity or, alternatively, one Entity with many Addresses) to associate the two values;
  2. Create the required fields directly as property of the Entity.

No other ways. But those two ones have some drawbacks:

The first alternative, create a new Entity, means a new table is created in the database (to contain Addresses), so the resulting schema is something like this:

|---------------------| |--------------------------------------------------|
| TABLE USERS | | TABLE ADDRESSES |
|---------------------| |--------------------------------------------------|
| id | name | Address | | id | street | postal_code | city | country |
|---------------------| |--------------------------------------------------|
| 1 | John | 1 | | 1 | Via di Qui | 12345 | Naples | Italy |
|---------------------| |--------------------------------------------------|

Enter fullscreen mode Exit fullscreen mode

Two separate tables linked each other by a foreign key. Each query needs a JOIN to get in the same resultset both the User Entity’s data and the email.

The second alternative, create the required fields in each Entity, on the other hand, is a solution that doesn’t permit to perform some checks, for example about the validity of passed data (see the example above of the Email: when instantiated, the Email (Value) Object checks that the passed data are really an e-mail).

If you’d like to do this type of checks, you need to repeat the same code in more Entities, and, if you make a change, you have to update the code in more places (not speaking about unit tests!). Not so useful, not so practical, not so intelligent, not so easy.

Using an Embeddable object, instead, permits you to take advantage of only the benefits of the two methods.

Embedding the AddressEmbeddable in your Entities, will produce a table like this:

|-----------------------------------------------------------------------------------|
| TABLE USERS |
|-----------------------------------------------------------------------------------|
| id | name | address_street | address_postal_code | address_city | address_country |
|-----------------------------------------------------------------------------------|
| 1 | John | Via di Qui | 12345 | Naples | Italy |
|-----------------------------------------------------------------------------------|

Enter fullscreen mode Exit fullscreen mode

Very useful!

NOTE: The default behavior is to call the column [embeddale]_[property] ([address]_[street]), but you can change it.

The last essential question: Which is the best way to represent a domain: an Entity or an Embeddable/Value Object?

So, here we come to the very complex question: what kind of class should have I to choose when dealing with such a decision?

Also if the question seems complex, the answer is really simple: it depends 🙂

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 […]

So, an Address without the postal code has no sense, but a Company without an Address has.

A Price has no sense without a Currency, but a Product without a Price has.

So, use Value Objects/Embeddable each time you have to represent a value composed of more than one information and only the sum of these information has a sense and “creates” the meaning of the value. You can also use Embeddables in other Embeddables, for example you can use a PostalCodeEmbeddable inside the AddressEmbeddable (not tested, but I think it’ll work fine).

Each time you’ll find those kind of objects, you’ll know they cannot be modified in any way and that, if you edit them, you have a new different Object, not the same edited.

The problem: and if, for example, a Customer can have more than one Address (for example, one time it chose to ship to Italy and the second one it chose to ship to UK)?

The problem arises when the Embeddable is melted into the Entity table: only one Address is allowed.

The Real Astonishing Truth: Entities and Value Objects/Embeddable can be used together!

Yes, it is possible to use together Entities and Embeddables.

So, if a Customer can have more than one Address, and as you can use Embeddables/Value Objects together with Entities, you’ll have an AddressEmbeddable that represents the current state of the value and an AddressEntity that represents the collection of those values.

Something like this:

<?php 

namespace AppBundle\Entity;

/** @Entity */
class User
{
    /**
     * @ORM\OneToMany(targetEntity="Address", mappedBy="ofUser")
     */
    private $addresses;
}



<?php 

namespace AppBundle\Entity;

/** @Entity */
class Address
{
    /**
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="User", inversedBy="addresses")
     * @ORM\JoinColumn(name="of_user", referencedColumnName="id")
     */
    private $ofUser;

    /**
     * @Embedded(class = "AddressEmbeddable")
     */
   private $address;
} 


<?php 

namespace AppBundle\Embeddable;

/** @Embeddable */
class AddressEmbeddable
{
    /** @Column(type = "string") */
    private $street;

    /** @Column(type = "string") */
    private $postalCode;

    /** @Column(type = "string") */
    private $city;

    /** @Column(type = "string") */
    private $country;
}
Enter fullscreen mode Exit fullscreen mode

This way you’ll have again a table dedicated to addresses, but each Address Entity will return an Immutable Object, one that returns a new object if edited (IS UP TO YOU TO IMPLEMENT THE AddressEmbeddable->setNewAddress() method in such a way it returns a brand new copy of the AddressEmbeddable class. See the Email example above to better understand this).

Someone terms “Fake” this kind of Address Entity that embeds an EmbeddableObject because its unique purpose is to manage an Embeddable.

If seen only in the context of Doctrine, this could also be considered true, but, if considered in the bigger picture of the Domain Driven Design, this is the only correct way of doing things.

The real purpose of a Value Object is to represent an Immutable Value. The fact that Doctrine calls them Embeddables and treats them in some ways persisting them into the database is something that does not interfere with the real purpose.

So, the Entity is a container of values and a value formed by more values has to be a Value Object instead of a simple property.

Using Doctrine, those Value Objects are called Embeddables and are persisted creating columns directly in the table of the Entity that embeds.

But the concept of Immutability applied to Value Objects still is valid and has to be used, independently of how the ORMs manage their persisting in the databases.

Some links to go deeper

About Doctrine and Embeddable/Value Objects:

Remember to “Make. Ideas. Happen.”.

I wish you flocking users, see you soon!

L'articolo Value Objects, Immutable objects and Doctrine Embeddables proviene da ÐΞV Experiences by Serendipity HQ.

Top comments (0)