DEV Community

Cover image for The Value of Value Objects in Symfony
Micah Breedlove (druid628)
Micah Breedlove (druid628)

Posted on

The Value of Value Objects in Symfony

Recently, I was working on an article - similar to this one - focused on Domain-Driven Design (DDD) in Symfony. To illustrate the concepts, I spun up a demo project and brought in one of my commonly used libraries, which includes a collection of data type objects.
That's when I had an epiphany: my primitive and composite data-type objects were essentially just Value Objects with a different name. This realization led me to shift the focus of my article to Value Objects - an essential but often overlooked concept outside of DDD.

What is a Value Object?
At its core, a Value Object is exactly what it sounds like - an object that encapsulates a value. But why use them? While there's no single reason that will blow your socks off, they offer clear advantages in making code more expressive, maintainable, and domain-focused.
That said, not every value in your entity needs to become a standalone Value Object. Overusing them can lead to unnecessary complexity - like the "array_map() Design Pattern." 😀

A Practical Example: Email as a Value Object
Consider an entity with a field that you frequently perform operations on - an email address, for example. Instead of keeping it as a simple string, we can define a dedicated Value Object that encapsulates its behavior and logic.

Step 1: Creating the Email Value Object
For simplicity, I created it in App\Entity\Embeddable:

Basic Email Value Object

If you want to create your Value Objects outside of App\Entity then you will need to make modifications to your Doctrine ORM mapping configuration inside config/packages/doctrine.yaml.

Step 2: Embedding it in the Contact Entity

Contact entity with embedded Value Object Email

By leveraging the Embedded attribute (Doctrine\ORM\Mapping\Embedded), we seamlessly integrate the Value Object within our entity.

Why is this useful?
Now that we've structured our Email as a Value Object, extracting specific parts - like the user, domain, or TLD - becomes much cleaner, as the logic is all contained within the Value Object:

Adds email specific logic to Email ValueObject

Now when dealing with your Contact object you can execute the following:

Example of contact entity getting the domain for an email via Value Object method

By encapsulating logic within a Value Object, we reduce duplication, improve code readability, and reinforce domain concepts within our applications.

How do you approach Value Objects in your projects? Do you find them useful, or do they add unnecessary complexity?

Top comments (0)