Building a Data Access Layer for the Data Mapper Design Pattern

In this second part of a five-part series I go one step further in the implementation of the Data Mapper design pattern in PHP 5. Specifically, I build a simple MySQL abstraction class which performs a few common tasks. These include connecting to the database server and running hard-coded queries, fetching database rows and so forth.

Put in a simple way, the Data Mapper design pattern is an elegant solution that allows developers to keep all of the domain objects handled by an application separate from the underlying persistence layer. This characteristic is commonly known as persistence ignorance. As with many other patterns, the implementation of data mappers either in PHP 5 or any other programming language isn’t something that must be done all the time, as this depends heavily on the requirements of the application being developed.

What’s more, in many cases using domain objects that are aware of the data access layer is a suitable approach; the use of Active Record is a good example. However, as soon as the structure of those objects doesn’t match the database schema, the implementation of an intermediate layer that resolves this incompatibility internally is necessary. Here’s where data mappers come into play, although there are other patterns, such as Data Access Objects, that also address this issue in an effective manner.

In order to demonstrate the actual functionality of data mappers when using PHP, in the introductory installment of this series I started building a simple domain layer, which was comprised of an abstract class whose interfaced was used for modeling basic domain objects. Essentially, this class was a basic data container that implemented some magic PHP methods for adding and deleting object properties dynamically.

Based upon the interface and functionality encapsulated by this abstract class, it was possible to create concrete user objects easily via simple inheritance. With a domain layer already set, what’s the next step we must take in the implementation of data mappers? Well, as I said before, data mappers behave like "gluing elements" between domain objects and the data access layer. Thus, in this second tutorial I’m going to show you how to implement this layer. For the sake of brevity, it will be made up of a trivial MySQL abstraction class.

Want to learn the full details concerning the implementation of this sample data access layer? Then start reading now!

{mospagebreak title=Review: building a simple domain layer in PHP 5}

Before I begin building the data access layer mentioned in the introduction, I’d like to reintroduce the definitions of the classes developed in the previous article. These classes were the building blocks of a basic domain layer.

Having clarified that, here’s the source code corresponding to the first of these classes, which define the structure for generic domain objects. Take a look at it:

(DomainObjectAbstract.php)

 

 

 

<?php

 

 

 

abstract class DomainObjectAbstract

{

    protected $_data = array();

   

    public function __construct(array $data = NULL)

    {

        if ($data !== NULL)

        {

            // populate domain object with an array of data

            foreach ($data as $property => $value)

            {

                if (!empty($property))

                {

                   $this->$property = $value;

                }

            }

        }

    }

   

    // set domain object property

    public function __set($property, $value)

      {

        if (!array_key_exists($property, $this->_data))

        {

            throw new ModelObjectException(‘The specified property is not valid for this domain object.’); 

        }

        if (strtolower($property) === ‘id’ AND $this->_data['id'] !== NULL)

        {

            throw new DomainObjectException(‘ID for this domain object is immutable.’);

        }

        $this->_data[$property] = $value;

    }

   

    // get domain object property

    public function __get($property)

    {

        if (!array_key_exists($property, $this->_data))

        {

            throw new DomainObjectException(‘The property requested is not valid for this domain object.’);

        }

        return $this->_data[$property];

    } 

   

    // check if given domain object property has been set

    public function __isset($property)

    {

        return isset($this->_data[$property]);

    }

   

    // unset domain object property

    public function __unset($property)

    {

        if (isset($this->_data[$property]))

        {

            unset($this->_data[$property]);

        }

    }

}

 

 

 

 

 

 

(DomainObjectException.php)

 

 

 

<?php

 

 

 

class DomainObjectException extends Exception{}

As you can see, the above “DomainObjectAbstract” abstract class encapsulates all of the functionality required for building generic domain objects; it can aggregate and remove properties on the fly, thanks to the implementation of the “__set()” and “__get()” PHP magic methods. Since any concrete domain object inherited from this base class will be a plain data container, testing the object is reduced to performing some basic assertions on it. 

The “User” class below shows how to create a concrete user domain object by way of simple inheritance:

(User.php)

 

 

 

<?php

 

 

 

class User extends DomainObjectAbstract

{

    protected $_data = array(‘id’ => NULL, ‘fname’ => ”, ‘lname’ => ”, ‘email’ => ”);

}

 

 

 

$user = new User();

$user->fname = ‘Susan';

$user->lname = ‘Norton';

$user->email = ‘susan@domain.com';

Well, obviously spawning a new user object and assigning a few new properties to it is a simple process that doesn’t bear any further discussion, right? However, there are a few neat advantages to defining domain objects like this. First, they’re easy to test and maintain, and second, they’re completely ignorant of the storage mechanism implemented by the application that uses them.

While this strategy allows you to decouple the domain layer from the data access layer, this benefit comes with a fixed cost: there must exist an intermediate element that bridges the layers. That’s the role that a data mapper plays. However, before I start showing a concrete implementation of that mapper, it’s necessary to code, at least for the demonstration purposes, the aforementioned data access layer, so you can see how each element fits into this schema.

With that idea in mind, in the following section I’m going to define a basic data access layer. In this case, it will be comprised of a single MySQL abstraction class. Thus, to see how this whole new class will be developed, click on the link below and read the lines to come.

{mospagebreak title=Building a basic data access layer}

In most cases, the data access layer of an application is comprised of multiple classes that perform well-differentiated tasks. In this case, though, the layer that I plan to build here will be made up of only one class, which will abstract the access to MySQL. Doing this will let you grasp more quickly how a data mapper will work in a rather simple context.

That being said, please pay attention to the definition of the MySQL abstraction class, which is as follows:

(MySQLAdapter.php)

 

 

 

<?php

 

 

 

class MySQLAdapter

{

    private $_config = array();

    private static $_instance = NULL;

    private static $_connected = FALSE;

    private $_link = NULL;

    private $_result = NULL;

   

    // return Singleton instance of MySQLAdapter class

    public static function getInstance(array $config = array())

    {

        if (self::$_instance === NULL)

        {

            self::$_instance = new self($config);

        }

        return self::$_instance;

    }

   

    // private constructor

    private function __construct(array $config)

    {

        if (count($config) < 4)

        {

            throw new MySQLAdapterException(‘Invalid number of connection parameters’);  

        }

        $this->_config = $config;

    }

   

    // prevent cloning class instance

    private function __clone(){}

   

    // connect to MySQL

    private function connect()

    {

        // connect only once

        if (self::$_connected === FALSE)

        {

            list($host, $user, $password, $database) = $this->_config;

            if ((!$this->_link = mysqli_connect($host, $user, $password, $database)))

            {

                throw new MySQLAdapterException(‘Error connecting to MySQL : ‘ . mysqli_connect_error());

            }

            self::$_connected = TRUE;

            unset($host, $user, $password, $database);      

        }

    }

 

 

 

    // perform query

    public function query($query)

    {

        if (is_string($query) and !empty($query))

        {

            // lazy connect to MySQL

            $this->connect();

            if ((!$this->_result = mysqli_query($this->_link, $query)))

            {

                throw new MySQLAdapterException(‘Error performing query ‘ . $query . ‘ Error : ‘ . mysqli_error($this->_link));

            }

        }

    }

   

    // fetch row from result set

    public function fetch()

    {

        if ((!$row = mysqli_fetch_object($this->_result)))

        {

            mysqli_free_result($this->_result);

            return FALSE;

        }

        return $row;

    }

 

 

 

    // get insertion ID

    public function getInsertID()

    {

        if ($this->_link !== NUlL)

        {

            return mysqli_insert_id($this->_link); 

        }

        return NULL;  

    }

   

    // count rows in result set

    public function countRows()

    {

        if ($this->_result !== NULL)

        {

           return mysqli_num_rows($this->_result);

        }

        return 0;

    }

   

    // close the database connection

    function __destruct()

    {

        is_resource($this->_link) AND mysqli_close($this->_link);

    }

}

 

 

 

 

 

 

(MySQLAdapterException.php)

 

 

 

<?php

 

 

 

class MySQLAdapterException extends Exception{}

As seen before, the “MySQLAdapter” class is merely a Singleton that performs some typical operations on MySQL, such as connecting to the database server, executing hard-coded SQL statements and fetching database rows. Its inner working is that simple, really.

At this time, coding a class like this seems to be a pointless task, since it doesn’t shed any light on how to build a data mapper class. But this is a misconception, believe me. When I show you the definition of the data mapper, you’ll realize that the existence of a MySQL adapter makes a lot of sense.

Assuming that you understand the logic behind the “MySQLAdapter” class, it’s time to see how it works. So, in the following section I’m going to code a short script that will put it in action.

Now, go ahead and read the next segment. It’s only one click away.

{mospagebreak title=Putting the MySQL abstraction class to work}

If you’re like me, then you want to see how to use the MySQL abstraction class defined in the previous segment. Below I wrote a short example that shows how to utilize the class’s interface to pull out data from a fictional “users” database table and display this information on screen. Here’s the corresponding script:

<?php

 

 

 

require_once ‘MySQLAdapter.php';

 

 

 

$db = MySQLAdapter::getInstance(array(‘host’, ‘user’, ‘password’, ‘database’));

$db->query(‘SELECT * FROM users’);

while ($user = $db->fetch())

{

    echo ‘First Name: ‘ . $user->fname . ‘ Last Name: ‘ . $user->lname . ‘ Email: ‘ . $user->email . ‘<br />';

}

As depicted above, putting the “MySQLAdapter” class to work is a fairly straightforward process, meaning that you shouldn’t have any problems enhancing its current functionality. Naturally, the point in building this sample class is to set a basic data access layer that allows you to “justify” the implementation of a data mapper. 

Now, think carefully about the hypothetical scenario that has been created so far: on one hand there’s a domain layer where plain user objects live happily, completely ignorant of the existence of the persistence storage mechanism (read: a single MySQL table). On the other hand, there’s the “MySQLAdapter” class, which is the only building block of the layer that accesses the data stored on that table.

Still with me? Then, ask yourself the following question: how can a user object be saved to its associated table, even considering that its properties might not entirely match the table’s fields? That’s exactly where a data mapper comes in, as this element is responsible for internally solving this incompatibility. The bad news is that data mappers are complex creatures that often require the implementation of other data access design patterns, such as an Identity Map, or in large and heavily-loaded applications, a Unit of Work.

However, for the moment there’s no reason to feel intimidated by these potential issues. In the upcoming article I’m going to discuss how to build a basic data mapper class, so you’ll be able to quickly grasp its underlying logic. In the meantime, feel free to read the conclusions below.      

Final thoughts

In this second part of the series I went one step further into the implementation of the Data Mapper design pattern in PHP 5. I built a simple MySQL abstraction class which performed a few common tasks, such as connecting to the database server and running hard-coded queries, fetching database rows and so forth.

The purpose of coding a class like this is to recreate a scenario where an application is split into at least two different layers. The first one is the domain layer, where the domain objects (users, blog posts, etc) live, and the second one is the data access layer, which is built upon the previous MySQL accessing class. For the sake of brevity, the presentation layer will be omitted.

With that scenario already set, the next logical step is building the data mapper classes that will interconnect these two independent layers. However, this topic will be discussed in depth in the next tutorial, so don’t miss it!

[gp-comments width="770" linklove="off" ]

chat