Jul 23, 2014
Table of contents:
Models are one of the most important aspects of implementing the Active Record pattern. Models in the Active Record pattern inherit the ability to read, create, update and delete from the persistence storage and they also give you access to the properties and relationships of the record you are working with.
Models in the Active Record pattern tend to be pretty heavy objects because they end up having to coordinate a lot of what is going on in the code. You’ll often hear this being described as “fat model”.
In today’s article I’m going to be taking the first steps towards building out the models of this PHP SDK package.
Before I jump into the code, first I’ll explain what I mean when I use the term model.
A model in the Active Record pattern gives you access to a particular resource of the persistence storage.
For example, you might have a users
resource and a User
model.
Using the model you can find()
a particular user:
$user = User::find(1);
The $user
object is an instance of the User
model so we can now use it to set properties and save straight to the database:
$user->name = "Philip Brown";
$user->save();
The User
model maps a single database record to a PHP object you can work with in your code. All of the data persistence methods such as find()
, save()
, update()
and delete()
are inherited from a base Model
instance.
Models are important in the Active Record pattern because they provide the public interface for working with entities and the storage layer of our application.
When working with a model instance you can very easily get and set the properties of that record:
echo $user->name; // 'Philip Brown'
$user->email = "name@domain.com";
You can also create, update or retrieve entities from the database using an instance of the model:
$user = User::create(["name" => "Philip"]);
$user->email = "name@domain.com";
$user->save();
$user = User::find(1);
$user->update(["name" => "Philip Brown"]);
And you also have access to the entity’s related records:
$user = User::find(1);
foreach ($user->posts as $post) {
//
}
The models of the Active Record pattern hold a lot of power and a lot of responsibility. They provide a public interface to the objects and storage and allow you to work with and manipulate the data of your application.
Arguably, models in the Active Record pattern have too much responsibility, but we’ll not worry about that for this series of articles.
If you’ve been following a long with the Building Cribbb series you will probably be already familiar with Eloquent and the Active Record pattern.
However you might not know how the models of Eloquent are technically working behind the scenes.
Before I start implementing the models of the package we’re building, first I’ll talk about the structure of a model object.
First we need to inject the Connection
dependency from last week. Whilst the Active Record pattern is coupled to the persistence layer, we still need to inject the Connection
so that we can test in isolation.
Each of the models of the package will extend an abstract model. With the model objects having a lot of the responsibility and power we need we can abstract a lot of that functionality to an abstract class to allow all child classes to inherit and keep our code dry.
Each individual model class will have their own configuration properties, methods and relationship definitions. If you’ve ever worked with Laravel’s Eloquent, this will work in exactly the same way as that.
So the first thing to do is to create the abstract Model
class that will hold a lot of the abstracted functionality of the models.
First I will create the test file:
use PhilipBrown\CapsuleCRM\Connection;
class ModelTest extends PHPUnit_Framework_TestCase
{
}
At the bottom of this file I’ll also write a ModelStub
class to test this abstract class:
class ModelStub extends PhilipBrown\CapsuleCRM\Model
{
}
And finally I’ll create the actual Model
class:
<?php namespace PhilipBrown\CapsuleCRM;
abstract class Model
{
}
Each model instance will require an instance of the Connection
object. Without the HTTP connection this package isn’t going to be of much use.
To ensure that the Connection
object is required as a dependency we can inject it through the __construct()
method.
With each model object having an HTTP connection, we can work with the API using the Active Record pattern.
First we’ll write a failing test. I want to be able to inject the Connection
instance and then get access to it via a public connection()
method.
First I’ll create a new instance of the ModelStub
object in the setUp()
method:
public function setUp()
{
$this->model = new ModelStub(new Connection(", "));
}
The setUp()
will be automatically run before each test. This means we don’t have to repeat the code to create a new ModelStub
instance in each test.
Next I will write the failing test:
public function testConnectionMethodHasConnection()
{
$this->assertInstanceOf('PhilipBrown\CapsuleCRM\Connection', $this->model->connection());
}
Run phpunit
and watch the test fail.
Next we can write the code to make the test pass:
<?php namespace PhilipBrown\CapsuleCRM;
abstract class Model
{
/**
* The HTTP connection
*
* @var PhilipBrown\CapsuleCRM\Connection
*/
protected $connection;
/**
* Inject the Connection dependency
*
* @param PhilipBrown\CapsuleCRM\Connection $connection
* @return void
*/
public function __construct(Connection $connection)
{
$this->connection = $connection;
}
/**
* Get the connection instance
*
* @return PhilipBrown\CapsuleCRM\Connection
*/
public function connection()
{
return $this->connection;
}
}
Next inject the Connection
into the ModelStub
and pass it to the parent::__construct()
method:
class ModelStub extends PhilipBrown\CapsuleCRM\Model
{
public function __construct(Connection $connection)
{
parent::__construct($connection);
}
}
Now if you run phpunit
again your test should pass!
The Models of an Active Record are extremely important and so there is a lot to cover in order to implement them correctly. In today’s tutorial we’ve looked at the reasons why models are so important and we’ve set up the initial foundation abstract class that will hold a lot of the responsibility of each model instance.
In next week’s tutorial we will continue to look at building out the abstract model class step-by-step.