Question

Let's say you have a username value object which has formatting rules e.g.,

class Username
{
    private $username; 

    public function __construct(string $username)
    {
        // thrown an exception if invalid regex ^[a-zA-Z0-9]+$
        // ...

        $this->username = $username;
    }
}

Like above, usually you would pass the raw string from "outside" to validate the username.

My question is, can value objects have "additional functionality" like generate its own value, like for example, generate a username? e.g.,

class Username
{
    private $username; 

    // original __constuct() remains here
    // ...

    public function generateUsername(UserRepository $userRepository): self
    {
        $username = $this->generateRandomUsername();

        if (!$userRepository->userExist($username))           
             return new self($username);
    }
}

The example is just a quick pseudocode of the idea but the idea is generateUsername() would take UserRepository to validate if the newly generated username from within the class does not exist yet in the database.

Can value objects have a functionally like this, or should they behave more like the first example, where they just accept and validate input from the "outside"?

Was it helpful?

Solution

Can Value Objects create their own value?

Yes, it's not unusual to do that, especially with compound values that need to be backwards compatible with earlier models.

public function generateUsername(UserRepository $userRepository): self
{
    $username = $this->generateRandomUsername();

    if (!$userRepository->userExist($username))           
         return new self($username);
}

That's a bit weird. Most notably because we don't normally pass repositories to the domain model, and because random numbers are usually an input (like time).

Furthermore, uniqueness is a specialized case of "set validation". In the case where your repository is backed by an relational database, you may be able to manage, but in the general case trying to enforce uniqueness other than of the key used to lookup the aggregate gets complicated.

Licensed under: CC-BY-SA with attribution
scroll top