Decoupling models from the database: Data Access Object pattern in PHP

Tags:

Nowadays it’s a quite common approach to have models that essentially just represent database tables, and may support saving the model instance right to the database. While the ActiveRecord pattern and things like Doctrine are useful, you may sometimes want to decouple the actual storage mechanism from the rest of the code.

This is where the Data Access Object pattern comes in. It’s a pattern which abstracts the details of the storage mechanism – be it a relational database, OO database, an XML file or whatever. The advantage of this is that you can easily implement different methods to persist objects without having to rewrite parts of your code.

I’m again going to use the programming language quiz game I wrote as an example. Since I initially wrote it to use Doctrine ORM directly, and both the old and new code are available, you can easily see how the code was improved.

A look at the pattern


The basic idea is that you have a Data Access Object (DAO), which abstracts the storage mechanism. It should implement an interface, so if you want to add another way of accessing data, you simply write a new set of DAO’s that implement the interface.

While you could use the pattern alone, it’s probably best to use it together with the factory pattern. That way, we have a single class which handles the creation of the DAO’s – the DAO factory. We could even have multiple factories to handle creation of different kinds of DAO’s, and use the abstract factory pattern to hide the implementation details.

The image on the right displays how the abstract factory version of this could work. Basically, you have an interface HelloDao, which is then implemented by your concrete DAO objects. You also have an interface for the factory, and the concrete factory/factories implement it.

The example later in this post, however, uses just a single factory, as we only implement a single set of DAO’s.

The models

The models in the quiz are relatively simple. We have Question, Answer and QuestionAnswer. At first, these were just Doctrine’s models. However, for implementing the DAO stuff, we’ll create some new model classes of our own.

Here’s the Quiz_Question model class:

<?php
class Quiz_Question
{
	private $_id;
	private $_question;
 
	public function getId()
	{
		return $this->_id;
	}
 
	public function setId($id)
	{
		if(!is_numeric($id))
			throw new InvalidArgumentException('ID can not be non-numeric');
 
		$this->_id = $id;
	}
 
	public function getQuestion()
	{
		return $this->_question;
	}
 
	public function setQuestion($question)
	{
		if(empty($question))
			throw new InvalidArgumentException('Question can not be empty');
 
		$this->_question = $question;
	}
}

Quite simple. It just stores an ID and the question’s text, and provides getters and setters. The setters contain a bit of validation logic that throws an exception if the data is bad. There is absolutely no persistence-related logic here.

The other model classes follow this same approach.

Creating a DAO for the question model

Here’s an interface for the DAO that will be used to deal with Questions:

<?php
interface App_Dao_Question_Interface
{
	public function insertQuestion(Quiz_Question $question);
	public function findQuestion($id);
	public function fetchRandomQuestionNotIn($questionIdList);
	public function findQuestionByQuestion($question);
}

You can probably see the basic idea there: The interface provides methods for accessing the data, as the name Data Access Object says.

Since I still want to use Doctrine, I’m going to create a DAO which uses Doctrine’s methods to implement the above interface:

<?php
class App_Dao_Doctrine_Question implements App_Dao_Question_Interface
{
	/**
	 * Insert a question into the database
	 * @param Quiz_Question $question
	 */
	public function insertQuestion(Quiz_Question $question)
	{
		//Create a Doctrine model for storing the Quiz_Question model
		$q = new Question();
		$q->question = $question->getQuestion();
 
		try
		{
			$q->save();
			$question->setId($q->id);
		}
		catch(Doctrine_Exception $e)
		{
			throw new App_Dao_Exception('Error inserting question', $e);
		}
	}
 
	/**
	 * Find a question by ID
	 * @param int $id
	 * @return Quiz_Question
	 */
	public function findQuestion($id)
	{
		try
		{
			$data = Doctrine::getTable('Question')->find($id);
		}
		catch(Doctrine_Exception $e) 
		{
			throw new App_Dao_Exception('Error querying the database', $e);
		}
 
		if(!$data)
			return null;
 
		$question = new Quiz_Question();
		$question->setId($data->id);
		$question->setQuestion($data->question);
 
		return $question;
	}
 
	/* Rest omitted to save space */
}

Here are two methods from the interface implemented in the DAO. You can see how the methods basically hide away the fact that it’s Doctrine behind the scenes. Particularily, note the try-catch blocks – they are used to catch any implementation-specific exceptions from Doctrine, which get wrapped into App_Dao_Exceptions. This way you can easily catch exceptions from the DAO’s, without knowing what it’s doing behind the scenes.

Creating the factory

Now we have some models, and DAOs that interact with the storage (the database in this case). Next, we need the DaoFactory.

Strictly speaking, this class isn’t absolutely necessary. We could create new DAO’s in our code without the factory, but it might not be a very good idea. If some DAO’s need more initialization, for example passing in a database connection or something, it would be problematic.

Also, if we wanted to change the DAOs, we would need to go around our code and modify it to create other kinds of instances. With the factory, we could simply modify (or even replace) the factory and all code will follow.

class App_DaoFactory
{
	private static $_instance;
 
	public function __construct()
	{
	}
 
	/**
	 * Set the factory instance
	 * @param App_DaoFactory $f
	 */
	public static function setFactory(App_DaoFactory $f)
	{
		self::$_instance = $f;
	}
 
	/**
	 * Get a factory instance. 
	 * @return App_DaoFactory
	 */
	public static function getFactory()
	{
		if(!self::$_instance)
			self::$_instance = new self;
 
		return self::$_instance;
	}
 
	/**
	 * Get a Question DAO
	 * @return App_Dao_Question_Interface
	 */
	public function getQuestionDao()
	{
		return new App_Dao_Doctrine_Question();
	}
}

The factory is set up a bit similar to the singleton: it has a static method for getting an instance of the factory. This is so we can easily obtain a factory instance in our code, but we also provide a setter method, so if needed, we can replace the factory with something else – for example a mock factory for testing code, as can be seen in the new unit tests for App_QuizHandler (scroll down in the code).

This could be easily changed into an abstract factory too. The getFactory method could return PdoDaoFactories, DoctrineDaoFactories or something else – perhaps based on a parameter that’s passed in, or a configuration value or something. But since the abstract factory isn’t necessary (we could just change the get*Dao methods), I have left it out.

DAO in action

With all the classes done, we can now move to actually using them in code. Here’s a very simple example:

$questionDao = App_DaoFactory::getFactory()->getQuestionDao();
 
$question = $questionDao->findQuestion(10);

Relatively simple, no?

Let’s check out a few examples from the quiz on how the code was changed. For example, if we look at the App_Questioner class, methods getRandomQuestion or getBestAnswer, we can see that there’s a bunch of Doctrine-related code there. Looking at the refactored App_Questioner, we see it’s mostly replaced by calls to the DAO’s. Also, if you check out the DAO’s code, you can see the code was basically just moved to the DAO method with minor changes.

Summing it up

While going straight Doctrine models may be quick, DAO’s provide flexibility where it’s needed, and you could easily write some tools to generate the DAO classes for you. Of course, it’s a layer of complexity, but it’s good to know different ways of solving problems.

What comes to the model class shown, and the fact that there is no database related logic… It could contain some additional methods, for example getAnswers, which could return relevant answers. If we provided a such method, it should use the DAO for the answers to fetch them.

The approach with DAO’s is a bit similar to what Matthew Weier O’Phinney shows in his model infrastructure blogpost. I recommend checking it out, as it also contains some more in-depth things about models themselves.

The Core J2EE patterns: Data Access Object is also a good read on the topic.

The source code for the quiz can be found in SVN, as follows:
Version 1.0 of the quiz
Version 1.1 of the quiz (with DAO’s and some other refactoring)

Further reading:
Another idea for using models with forms
The problems faced by a common model interface in frameworks
Food for thought: utilizing models in MVC