Feb 23, 2015
Table of contents:
Last week we drew a line under writing the Domain Layer of the application and turned our attention to building out the Application Layer.
The Application Layer acts as the “public API” to the inner core. This boundary layer should accept requests and return responses, but it should also be agnostic to where those requests come from and where the responses are sent to.
Over the next couple of weeks we’re going to be looking at building out the Application Services for each of the main components of the application.
This week we’ll be looking at the User Registration process and how what we’ve built so far fits into the on-boarding flow for new users.
It’s been a while since we looked at the user registration functionality of Cribbb, so I think a good place to start would be quick recap of how things stand right now.
A couple of weeks ago we built the user registration Domain Service in the article Creating a User Registration Domain Service.
I decided to wrap this specific bit of functionality as a Domain Service because it is very important to the application.
This particular Domain Service basically enforces the Domain rules around user registration, it creates the new User
instance, and then it saves it to the database.
If any of the Domain rules are not satisfied, an Exception
is thrown.
As I wrote in When should you use an Exception? the decision as to when to use an Exception
over an alternate form of error response is quite nuanced.
In this case, I will have multiple layers of validation to ensure that the user has entered valid data and so if an Exception
is thrown during this Domain Service, we know something has seriously went wrong.
The Exception
in this example is a last line of protection against any funny business from the new user.
So if the Domain Service is doing the heavy lifting of actually registering the new user, what is the role of the Application Service?
The Application Service actually has a very important role within the request lifecycle of registering a new user.
First, when the user is entering their email address and choosing a username we need to give immediate feedback as to whether the email and username have already been registered. It will be the Application Service that performs this check on the server side.
Secondly, when the user submits the registration form, the Application Service will act as a first line of defence to ensure that the correct data has been submitted.
Thirdly, when the User
object is returned from the Domain Service it will be loaded with Domain Events that are ready to be dispatched. It is the Application Service’s job to dispatch those events. I’ve written previously on Domain Events in the article Implementing Domain Events.
And finally, the response from the application should be in a generic format. It will be the Application Service’s responsibility to return the response so that it is agnostic to the outside world.
So now that we are clear on what the responsibilities of the Application Service should be and how it should fit into the stack of the application, it’s now time to actually build it!
The first thing I’m going to do is to create a new Cribbb\Application\Identity
namespace under the app/Cribbb
directory.
Next I will define the basic class file:
<?php namespace Cribbb\Application\Identity;
class UserRegistration
{
}
I can also create the test file:
<?php namespace Cribbb\Tests\Application\Identity;
class UserRegistrationTest extends \TestCase
{
}
Next I can inject the Domain Service into the Application Service as a Dependency. This encapsulates the registration process and ensures that the Application Layer is dependent on the Domain Layer, and not the other way round:
/**
* @var RegisterUserService
*/
private $service;
/**
* @var RegisterUserService $service
* @return void
*/
public function __construct(RegisterUserService $service)
{
$this->service = $service;
}
In the test file we can implement the setUp()
method so we don’t have to repeat the same code for creating an instance of the UserRegistration
class for each test:
/** @var UserRegistration */
private $service;
/** @var UserRepository */
private $repository;
public function setUp()
{
parent::setUp();
$this->repository = m::mock('Cribbb\Domain\Model\Identity\UserRepository');
$this->service = new UserRegistration(
new RegisterUserService(
$this->repository,
new BcryptHashingService(new BcryptHasher)
)
);
}
We’re going to need to mock the UserRepository
implementation so instead of passing in a concrete class, we can instead pass in a mock object.
If the data that is passed to the UserRegistration
service is invalid we need to return a response that indicates the failure and provides a list of error messages.
We can do this by adding an instance of Laravel’s MessageBag
. To do that I will instantiate a new instance inside the __construct()
method:
/**
* @var MessageBag
*/
private $errors;
/**
* @var RegisterUserService $service
* @return void
*/
public function __construct(RegisterUserService $service)
{
$this->service = $service;
$this->errors = new MessageBag;
}
We can also provide an errors()
method that will return the MessageBag
instance:
/**
* Return the errors
*
* @return MessageBag
*/
public function errors()
{
return $this->errors;
}
When a user is entering their data into the registration form, I want to be able to make an Ajax request to an endpoint to determine whether the data they have entered is valid.
The rules for what is considered valid can be encapsulated as a private
property on the class:
/**
* @var array
*/
private $rules = [
'email' => 'email',
'username' => 'alpha_dash'
];
Currently I’m only checking to ensure that the email and username are in the correct format, however at a later stage I will also add in Laravel’s unique
rule to ensure that the email address or username have not already been registered.
Ideally I want to have a single endpoint for checking both the email address as well as the username. This endpoint should pass on the request details to the following method:
/**
* Validate the user's credentials
*
* @param array $data
* @return bool
*/
public function validate(array $data)
{
$data = array_only($data, ['email', 'username']);
$validator = Validator::make($data, $this->rules);
if ($validator->passes()) return true;
$this->errors = $validator->messages();
return false;
}
First we ensure that we only have the email
and username
keys of the array.
Next we create a new instance of Laravel’s Validator
class and pass it the stripped $data
and the $this->rules
class property.
Next we check to see if the validation passes and if so, we return true
. If the validation does not pass we can set the $this->errors
property and return false
.
We can ensure this functionality is working correctly with the following two tests:
/** @test */
public function should_only_accept_valid_email_addresses()
{
$this->assertFalse($this->service->validate(['email' => '...']));
$this->assertEquals(1, $this->service->errors()->count());
}
/** @test */
public function should_only_accept_valid_usernames()
{
$this->assertFalse($this->service->validate(['username' => '$_$']));
$this->assertEquals(1, $this->service->errors()->count());
}
In each of these tests I’m passing in data that I know should not pass a valid. I’m asserting that the correct response is returned and that the errors()
method returns a count
of 1
.
Finally we have the register()
method which should act as the main point of contact with the class:
/**
* Register a new user
*
* @param string $email
* @param string $username
* @param string $password
* @return User
*/
public function register($email, $username, $password)
{
if ($this->validate(compact('email', 'username'))) {
$user = $this->service->register($email, $username, $password);
/* Dispatch Domain Events */
return $user;
}
}
First we can reuse the validate()
method from earlier to ensure that the data that has been passed is in fact valid. I don’t mind this double check because we can’t rely on the Javascript Ajax request.
Next we can pass the $email
, $username
and $password
to the Domain Service. If everything goes smoothly, out should pop a new instance of User
.
As I mentioned earlier, the User
object will be loaded with Domain Events. At this point we can dispatch those Domain Events to notify the listeners that a new user has registered. I haven’t included that code yet as it’s something I’m going to come back to.
And finally we can return the instance of $user
.
The test for this method looks like this:
/** @test */
public function should_register_new_user()
{
$this->repository->shouldReceive('userOfEmail')->once()->andReturn(null);
$this->repository->shouldReceive('userOfUsername')->once()->andReturn(null);
$this->repository->shouldReceive('nextIdentity')->once()->andReturn(UserId::generate());
$this->repository->shouldReceive('add')->once();
$user = $this->service->register('name@domain.com', 'username', 'password');
$this->assertInstanceOf('Cribbb\Domain\Model\Identity\User', $user);
}
In this test I’m telling the mocked repository to expect certain method calls and then asserting that I’m returned an instance of User
.
I’m undecided as to where I want to transform the $user
object into a generic format (JSON). I can either do it inside this class, or inside of the Controller.
I like the idea of the Application returning a generic format, but I’m not sure if I want to give this class the extra responsibility.
I’ll sit on that decision for a while and implement that functionality in a later tutorial.
In today’s tutorial we took a proper first look at implementing an Application Service.
This Application Service serves two main purposes.
Firstly, it acts as an interface so we can make Ajax requests from the user registration sign up form. This allows us to check the server side validation stuff such as uniqueness (although I haven’t implemented that just yet).
Secondly, it also acts as at the “public API” endpoint for registering a new user. This Application Service can now be injected into a Controller or a Command Line tool to be used for registering new users into the application.
Next week we will continue to build out the Application Services layer of Cribbb.
This is a series of posts on building an entire Open Source application called Cribbb. All of the tutorials will be free to web, and all of the code is available on GitHub.