Aug 18, 2014
Table of contents:
Over the last couple of week’s we’ve looked quite extensively into integrating Doctrine 2 into a Laravel project as well as the unique characteristics and functionality Doctrine 2 offers us as the ORM layer to our applications.
Doctrine 2 is an implementation of The Data Mapper pattern. The Data Mapper pattern promotes the separation of your application’s business rules from how the data is persisted to the database. This is in contrast to the Active Record pattern (What’s the difference between Active Record and Data Mapper?), where the two are coupled together.
So far in this little exploration of Doctrine 2 we’ve covered:
Whilst getting a grasp of how Doctrine works and how it is different to Eloquent is important, we haven’t really touched upon the main reason why you would want to choose Doctrine 2 in the first place.
That reason is how you encapsulate the business rules of your application.
And so that will be the focus of today’s article.
The business rules of an application are essentially what makes that application unique.
If you were developing an application for an existing company, the company is likely going to already have business rules that define how the company operates.
For example, if you were developing an application to manage the internal company projects, you might have to adhere to the following business rules:
Each one of these business rules are extremely important to adhere to because they are critical to how the business operates.
Each different application will have a unique set of business rules. Typically applications that are built to streamline existing processes will already have strict business rules in place. But even for greenfield projects, the application will typically have a number of business rules that define how it should operate.
Having a good idea of the business rules of a proposed application will be a good starting point to developing a new application. Getting to that point is out of the scope of this article, but I’ll cover it in a future post.
As I’ve mentioned in a couple of previous posts, knowing where to define the business rules of an application can be tricky to get your head around.
For many types of application, defining business rules in the Active Record model is fine.
I’d even go as far as saying for certain types of simple web application, defining certain business rules in the controller is probably fine too.
However for bigger or more complex applications you should be defining your business rules within your project’s domain.
It is the domain of your application that makes it unique. Business rules should be encapsulated in entity and value objects that have no dependency or knowledge of the outside world.
Domain and Model are pretty loaded terms in the world of computer programming. Domain in this case is the rules around how the business operates, whereas Model is the code that you write to provide a solution to the client.
This is kind of an abstract topic unless I really get into what each of these concepts mean and how they work together in a cohesive application. If you are little bit fuzzy on what this all means, don’t worry! I’ll be covering each of these topics on Culttt in the coming weeks.
This building Cribbb series of tutorials is a hopefully a learning experience for both you and I. By documenting each step in the process hopefully you will pick up a lot of the tools, techniques and experience that is required to build and launch an application.
With that being said, the project so far has been pretty unstructured. There have been a number of times when I’ve advocated one approach and then just a couple of weeks later I’ve ripped it out and implemented a different approach.
There is no plan with this series and so I’m just making it up as I go along. This is probably annoying for you, the reader, but hopefully you will see it as a learning experience. Rather than you building your own cookie cutter version of Cribbb, you will learn how to build your own web applications.
Today’s tutorial marks another shift in direction for this series. From now on I’m going to be exploring a much deeper Domain Driven Design approach to developing Cribbb. This means that a lot of the code up until this point can just be deleted.
With this new direction I’ve also changed the directory structure of the application. I’d advise that you take a browse through the Git repository to see what’s changed.
The biggest change I’ve made is to move the Cribbb
folder from the app
directory, and into a src
directory. Now all my Cribbb specific code will be kept separate from the Laravel specific code.
Within the src/Cribbb
directory I’ve created two directories for Domain
and Infrastructure
.
The Domain
directory will be house my domain related code such as the User
entity or the UserRepository
interface. These files will be stored under a further directory of Model
.
The Infrastructure
folder will house the code that will implement Cribbb, but is not directly a concern of the application. For example, I might use a UserDoctrineRepository
or a SendGridMailer
class.
Under the Model
directory I will further split my application into further sections of related code. For example, the code in this tutorial will sit under a Users
directory.
If you are unsure about the reasoning why I’ve set up the project like this, don’t worry. I will be exploring the reasoning behind these decisions in the coming weeks.
The first aspect of Cribbb’s business rules that I’m going to tackle is the logic around users of the system. At the minute I’m only really thinking about the foundational aspects of being a “user” of Cribbb. The rules and logic about posting or joining a Cribbb can wait until another day.
So the rules around being a user of Cribbb are:
There are many different ways in which you could enforce the business rules I’ve outlined above.
However when using an Object Oriented approach, it makes the most sense to use Object Oriented methods.
An Email, Username and a Password could all be considered Value Objects within our application (What is the difference between Entities and Value Objects?). Two emails addresses are conceptually the same when you analyse them in isolation.
By creating Value Objects out of each of these user requirements we can encapsulate the business rules around each item within the confides of a dedicated PHP object that has the sole responsibility of being an instance of that thing.
This means whenever we need an instance of an email address, we can create a new Email
object like this:
$email = new Email("name@domain.com");
The Email
object has the responsibility to ensure that the email address is valid. This means we encapsulate the business rules of our application within the Email
class.
Creating an Email
class allows us to create Email
objects where we are confident that the object is valid.
When you do something like this:
$email = "name@domain.com";
The $email
is just a dumb string, so you can’t be sure that it is a valid email address without running it through some kind of validation.
By creating a Email
object we can encapsulate the rules of a “valid” email address within the object. The rules around what is valid and not valid are kept internal to the class, so the outside world never needs to be concerned.
So the first thing I’m going to do is to write some tests to define how I want my Email
object to behave.
Create a new file called EmailTest
under test/Cribbb/Domain/Model/Users
and copy the following code:
<?php namespace Cribbb\Domain\Model\Users;
class EmailTest extends \PHPUnit_Framework_TestCase
{
}
You will notice that I’m not extending the usual TestCase
class that you normally see in Laravel based projects. None of my domain related code will have anything to do with Laravel so we don’t need to load the framework for these tests.
The first test should ensure that an Email
object should require an email address to be passed in through the constructor. This is easy enough to implement because we can just define the email address as a dependency of the constructor method and PHP will deal with throwing an exception if it is not satisfied. Here is the test:
/** @test */
public function should_require_email()
{
$this->setExpectedException('Exception');
$email = new Email;
}
You will notice that I’ve diverged from the usually naming convention of PHPUnit tests. Normally PHPUnit requires that your test names are in the form of testShouldRequireEmail
. However I’ve picked this alternative convention from Mathias Verraes. This is totally optional and comes down to your personal preference, but in my opinion the naming convention I’ve used above is more readable.
Next I want to ensure that the Email
object will only accept valid email addresses. Here is the test:
/** @test */
public function should_require_valid_email()
{
$this->setExpectedException('Assert\AssertionFailedException');
$email = new Email('this_is_not_a_valid_email');
}
You will notice that in this test I’m expecting a AssertionFailedException
. I’ll explain what kind of Exception this is when we come to implement the code.
And lastly I will write a test to simply validate that everything works as expected by passing in an email address that is valid and asserting that the Email
object is instantiated correctly:
/** @test */
public function should_accept_valid_email()
{
$email = new Email('name@domain.com');
$this->assertInstanceOf('Cribbb\Domain\Model\Users\Email', $email);
}
Now that I’ve got the tests in place I can implement the code to make them pass.
Create a new file called Email.php
under the Users
directory under src/Cribbb/Domain/Model
and copy the following code:
<?php namespace Cribbb\Domain\Model\Users;
use Assert\Assertion;
class Email
{
}
You will notice that I intend to use Assert\Assertion
. This is a PHP package that can be used to “assert” that a value is of a specific type, you can find it on GitHub.
This means instead of having the following code to assert that an email address is a valid email:
if (filter_var($value, FILTER_VALIDATE_EMAIL) !== false) {
$this->value = $value;
}
We can simply write:
Assertion::email($value);
The Assert package is used to prevent you from having to litter your code with these if
blocks. It is specifically design for libraries and application low-level code and so it has no dependencies.
Now you could argue that there should be no third-party code in your Domain related code. I agree with this statement, but I also tend to err on the side of pragmatism. If PHP had a native Assert
class I would use it, so I think using this third-party package in this instance is fine. Personally I would rather have a simple one line assertion than have if
statements all over the place.
The Email
is going to be really simple for the time being as the only responsibility it has will be to ensure that the email address it is created with is valid.
First define a property on the class to hold the $value
that is passed through the constructor:
/**
* @var string
*/
private $value;
I will probably also want to cast this object as a string, so we can implement the __toString()
magic method (What are PHP Magic Methods?):
/**
* Return the object as a string
*
* @return string
*/
public function __toString()
{
return $this->value;
}
Finally we can implement the __construct()
method to accept the $value
and validate it:
/**
* Create a new Email
*
* @param string $value
* @return void
*/
public function __construct($value)
{
Assertion::email($value);
$this->value = $value;
}
If the $value
is not a valid email address, the Assertion
class will throw a AssertionFailedException
exception which will halt the application and jump to the surface (When should you use an Exception?).
If the email address is valid we can simply set it as a property of the class.
Now if you run the tests you should see them all pass.
In this tutorial we’ve looked at encapsulating the business rules of an application inside Value Objects within the project’s domain. By utilising the inherent power of object oriented programming we can write code that is expressive, easy to work with and satisfies our requirements.
You will have noticed that I’ve not walked through implementing the Username
and Password
objects in this tutorial. The principle behind those two Value Objects is the same as the Email
Value Object and so I will leave that as something you can think about. If you get stuck you can always take a peak at the Git repository.
The theory and the implementation that I’ve covered in this tutorial is heavily inspired by a fantastic talk by Mathias Verraes called Unbreakable Domain Models. If you need clarification on anything that I’ve wrote about today I would highly recommend taking an hour to watch that talk. I guarantee you will walk away more knowledgable than when you started.
You will also notice that I’ve not covered ensuring that email addresses and usernames are unique within the context of the application. The implementation of ensuring uniqueness is slightly different from what we’ve covered today, so I’ll leave that as something to cover next week.
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.