0

I have modeled my application using multiple 'user' domain objects.

  • Candidate
  • Recruiter
  • Administrator

Each entity extends from an AbstractUser implementing UserInterface.

interface UserInterface
{
    public function getEmail();
    public function setEmail($email);
    public function getPassword();
    public function setPassword($password);
}

They all have their own a services CandidateService, AdminService etc implementing UserServiceInterface

interface UserServiceInterface
{
   public function getUserByEmail();
}

My problem arises when I need to fetch a user by their email address (say PasswordResetService) I am unable to determine which service I should be calling as the email could be either of them. I am also using mongoDB so I cannot simply run a native query joining the 'tables'.

My current thought is that I have to inject each service into the PasswordResetService and call getUserByEmail() on each of them until I get my desired user.

class PasswordResetService
{
   public function getUserByEmail($email) 
   {
       $user = $this->userService->getUserByEmail($email);
       if ($user) return $user;

       $user = $this->recruiterService->getUserByEmail($email);
       if ($user) return $user;

       // etc ...
   } 
}

From a design perspective the above seems to me like a poor approach as should I add a new user 'type' I would need to update the password service also.

Is there a better way of achieving this?

3
  • Do the services need to have different names? Commented Nov 21, 2014 at 12:09
  • @JamesMcLeod I assume you mean within the context of PasswordResetService? So rather than $this->userService perhaps an array of user services? If this is what you mean, then no, they don't need different names as I would only ever be calling methods that are within the UserServiceInterface.
    – AlexP
    Commented Nov 21, 2014 at 12:37
  • 1
    If the invoking functionality needs to be able to distinguish between the three types of actor, than you need to provide a mechanism allowing it. If it does not need to know (because you could call getUserByEmail directly for each, and similarly for every other service invoked), then you don't. I don't think there are any other good design choices. Commented Nov 21, 2014 at 12:44

1 Answer 1

1

I would approach this by having a top level UserService that doesn't care what type of user it's dealing with.

If it gets a request for a user by email, it can look up on the database which type of user is correct and delegate the request to the correct service. This may sound a little inefficient, but used with an appropriate query caching later it's actually fine.

Other methods that are passed a user object could perhaps use double dispatch to forward the request to the correct service object., thus eliminating the need to hit the database for these operations.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.