2
\$\begingroup\$

I'm trying to implement some domain driven design architecture, such as a repository to talk to the database, and a service that talks to the repository.

I have an action where I want to see if a User exists, and if he does, update his data, if he doesn't, create it and then perform a task (this could be done using event listeners but I'm not there yet).

  • Now I'm wondering if my service method can do all these things? Is there another actor that should be responsible for this?
  • This method is not very testable, since it's performing multiple actions? How would I test a method like this?
public function updateOrCreate($data)
{
    $userData = static::getUserDataFromAccessToken($data);

    // Find the user
    $user = $this->userRepository->find($userData['id']);

    // If we found the user, update and return
    if ($user) {
        $this->userRepository->update($userData);

        // Return the updated user
        return $this->userRepository->find($userData['id']);
    }

    // Else create
    $created = $this->userRepository->create($userData);

    if ($created) {

        // Get the newly created user
        $user = $this->userRepository->find($userData['id']);

        // Get the activities
        $this->activityTask->perform($user);

        return $user;
    }
}

public static function getUserDataFromAccessToken($token): array
{
    return [
        'id' => $token->getValues()['athlete']['id'],
        'username' => $token->getValues()['athlete']['username'],
        'photo' => $token->getValues()['athlete']['profile'],
        'access_token' => $token->getToken(),
        'refresh_token' => $token->getRefreshToken(),
    ];
}
\$\endgroup\$
  • 1
    \$\begingroup\$ Please cache $token->getValues() as a variable and use it multiple times instead of calling the method three times to populate the return array. We must never ask the system to fetch the same unchanged data more than once. Or (I don't know what else is in the athlete column), you might merge the return value of array_column($token->getValues(), 'athlete'). \$\endgroup\$ – mickmackusa Aug 31 at 22:13
  • \$\begingroup\$ Thanks @mickmackusa good advice. \$\endgroup\$ – Miguel Stevens Sep 1 at 6:38
  • 1
    \$\begingroup\$ @MiguelStevens since you are following DDD it might be of benefit to create a DTO or a Value Object for the user data hence remove a need for getUserDataFromAccessToken. It's easier to deal with models than it is with repositories, since that removes a need for re fetch of data after you perform and update. Also, why would user creation fail? \$\endgroup\$ – user3402600 Sep 3 at 19:22
  • 1
    \$\begingroup\$ @MiguelStevens you would want one action class for user creation and another action class for user update. this updateOrCreate is a different service file and to test it you just need to check that correct class is called depending on data you send into the method. \$\endgroup\$ – user3402600 Sep 3 at 19:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.