Creating focused domain applications. A Symfony approach (Saving the entity)

icolomina

Nacho Colomina Torregrosa

Posted on November 15, 2024

Creating focused domain applications. A Symfony approach (Saving the entity)

Introduction

In this third post of this series, we are going to create an entity ready to be persisted to the database from the DTO we created in the first article of the series.

Transforming the UserInputDTO into an entity

To start with this section, let's assume we are using doctrine to communicate with the database and our User entity looks like this:

#[ORM\Entity(repositoryClass: UserRepository::class)]
class User
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 150)]
    private string $firstname;

    #[ORM\Column(length: 255)]
    private string $lastname;

    #[ORM\Column(length: 25)]
    private string $dob;

    #[ORM\Column]
    private \DateTimeImmutable $createdAt;

    #[ORM\Column]
    private string $token;

    // getters and setters
}
Enter fullscreen mode Exit fullscreen mode

The fields email, firstname, lastname and dob will be filled with the UserInputDTO values and the createdAt and token fields will be filled following the next rules:

  • The createdAt field will hold the current date.
  • The token field will hold a string of 50 alphanumeric characters.

As we have decided how we are going to fill the entity fields, this part of the code will belong to the domain since it contains domain business rules. So, we need a service domain to do the stuff. Let's code it.

class UserEntityBuilder {

    public function buildEntity(UserInputDTO $userInputDto): User
    {
        $user = new User();
        $user->setEmail($userInputDto->email);
        $user->setFirstname($userInputDto->firstname);
        $user->setLastname($userInputDto->lastname);
        $user->setDob($userInputDto->dob);
        $user->setToken(bin2hex(random_bytes(50)));
        $user->setCreatedAt(new \DateTimeImmutable());

        return $user;
    }
}
Enter fullscreen mode Exit fullscreen mode

As you can see, the UserEntityBuilder buildEntity method creates the User entity following the pre-established rules and returns the entity.

An application service to create and save the entity

Now, we need a service which will be in charge of coordinating the processes involved in saving the entity:

  • Creating the User entity by using our recently created UserEntityBuilder domain service.
  • Using the doctrine EntityManager service to persist the entity on the database. The EntityManager service should be considered as an infrastructure service since it is provided by the Symfony framework through its symfony/orm-pack component.

Let's code it.

class UserCreator {

    public function __construct(
        private readonly UserEntityBuilder $userEntityBuilder,
        private readonly EntityManagerInterface $em,
    ){}

    public function createUser(UserInputDTO $userInputDto): object
    {
        $user = $this->userEntityBuilder->buildEntity($userInputDto);
        $this->em->persist($user);
        $this->em->flush();

        return '.....'; // Return a DTO ready to be used by the presentation layer
    }
}
Enter fullscreen mode Exit fullscreen mode

As you can see in the code above, the UserCreator application layer service uses first the UserEntityBuilder to create the entity and then uses the Doctrine entity manager to save it to the database.

You may have noticed that the "return" line is not complete. ¿ What should we return here?. We will see it in the next and last article of this series :)

What about the entities. Do they belong to the domain ?

This is a good question. In my opinion, they would belong to our domain since, although they represent a mapping of database tables to objects in our application, they encapsulate our decisions regarding the project's data model.
Now, the fact that they can belong to our domain does not mean that they can be used as DTO's. They should be isolated and only be used for saving data to the database and receiving data from there.

Conclusion

In this third article, we have created a domain service to create a User entity ready to be persisted to the database and also have created an application service which saves the entity to the database by using the domain service to create the user and the doctrine entity manager to save it.
In the next and last article, we will learn hot to create an output DTO with the saved user information ready to be returned to the presentation layer.

If you like my content and enjoy reading it and you are interested in learning more about PHP, you can read my ebook about how to create an operation-oriented API using PHP and the Symfony Framework. You can find it here: Building an Operation-Oriented Api using PHP and the Symfony Framework: A step-by-step guide

💖 💪 🙅 🚩
icolomina
Nacho Colomina Torregrosa

Posted on November 15, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related