As the heading suggests I am having some small problems while implementing the 3 structure Model (Domain object, data mapper and service).
In the past when someone was registering on my site I would simply do
$user->register($firstName, $lastName, $emailAddress, $username...);
and that method would run in steps like this
1. Check if the form sent was valid.
2. Check if all the required fields were filled.
3. Check the if the lengths of strings were valid and the range of integers etc.
4. Check if the input is in the correct format (regex).
5. Check if the username is already taken and if the email address already exists
in the database
6. etc. etc.
All that works fine but I'm trying to get away from doing it that way because I want my code to be more reusable and testable.
Now, with this 3 structure Model the Domain Object and the Data Mapper are supposed to communicate through a Service to keep them isolated from one another so here's my idea of a User service
class UserService {
public function register($firstName, $lastName, $email...) {
$userDO= $this->domainObjectFactory->build('User');
$mapper = $this->dataMapperFactory->build('User');
// Is this where I start doing my validation like in the steps above???
// And if this is where I start doing my checks, when I get to the part
// where I have to check if the username they want is already taken how
// how do I do that check?
}
}
And then to actually run that I would do it from my controller like so
$userService = $this->serviceFactory->get('user');
$result = $userService->register($_POST['firstName']....);
The logic (if's and else's) must go in the register()
method in my UserService
class right? Because if they go in the Domain Object when I reach the stage of needing the database to do some checks like if the username already exists how would I access the database? I really don't know since the domain object is not supposed to know anything about a data source.
There has got to be a way to access the database for small queries like checking if a username or email address already exist and loads of other little queries that need to be done.
I have lots of entities/domain objects that need to do loads of little queries and in the past my model had access to the database from within any method and could do those queries but that doesn't seem to be permitted with this 3 structure model and I'm dying to find out what is the correct way to do it because there has to be a way.
I was flying it until I found out a Model is a layer which is broken into 3 structures.
Any help or push in the right direction would be greatly appreciated, especially good real life examples. The internet seems to be lacking those for my specific problem.
Thanks.
This is an interesting question. I suppose your user Data Mapper has methods for finding & loading users based on some criteria (like username). Therefore, in this case I would do the check inside UserService::register by trying to find a user having the provided username (if it exists):
By the way, I don't know if you read this, but a very good guide is Martin's Fowler book - Patterns of Enterprise Application Architecture. You will find good answers for many of your questions.
I am going through the same thing you are right now (funny enough, for this exact problem - user registration/authorization).
One piece of advice that I have is that you should not restrict your model to just 3 layers (in this case, 3 classes). A model should be as many classes as needed in order to get the job done while maintaining SRP (single responsibility principle) integrity.
For example, you might also want to use a UserTableGateway class to compliment the UserDataMapper, and a UserCollection class to allow for potential pagination functionality or general lists of users. All of those things could be part of your model and UserService layer.
To answer your question about the logic specific to the registration process, yes, the most appropriate place for it is in the register methods of the UserService class.
All that said, you might want to think about your domain structure here. Is a UserService the most appropriate place for registration (and by extension, login, recover password, change password etc)?
Perhaps those things could be part of a totally different model related to Accounts. A service class could be something like this:
Given there are potentially dozens of other things a UserService could be responsible for, it makes sense for you to keep everything related to the user's account in its own service class.
Conceptually, an account is different from a user anyway, and if it's conceptually different, it deserves its own class.
Now, as far as getting the Account service class the dependencies it needs, that's beyond me at this stage in my understanding of complex system design.