Building the Data Mapper Classes for the Data Mapper Design Pattern

In this third part of a five-part series on the data mapper design pattern, I start developing a basic user mapper class. This class allows you to map user domain objects to their associated database table in a fairly easy way.

The Data Mapper design pattern is a powerful and elegant solution that permits developers to isolate domain objects from the underlying persistence storage mechanism of an application. Its implementation, at least at a basic level, is a pretty straightforward process that can be tackled with minor hassles.

In the case of PHP, building data mapper classes can be a challenging task, especially for developers who are taking their first steps into the huge area of design patterns. Once the logic that drives data mappers has been properly digested, however, their implementation is indeed fairly simple.

Naturally, explaining how to create one or more data mapper classes requires the performance of some initialization tasks, such as defining a few domain objects that make up the domain layer and implementing a data access layer (DAL).

In keeping with this requirement, these two layers were developed in the preceding parts of this series. For demonstration purposes, the domain objects were created as simple data containers, capable of adding and removing properties dynamically, while the data access layer was comprised only of a single MySQL abstraction class.

The fact that these layers currently live isolated from each other sets a propitious scenario for taking advantage of the data mapper pattern’s functionality. The question that comes up here is: why should the pattern be implemented, anyway? Well, if the structure of the domain objects matches the structure of the database tables in a one-to-one relationship, the problem is far easier to solve, quite possibly by using an Active Record implementation.

Unfortunately, in most cases this match doesn’t occur. Consider, for instance, a basic domain layer comprised of blog post objects that also have an associated author object. In a case like this, storing blog posts will require working with two different tables, instead of only one. However, the good news is that this incompatibility can be resolved by means of a data mapper,  without making the domain objects aware of the persistence layer.

Having said that, in this third part of the series I’ll be discussing how to create some basic data mapper classes, which will bridge the pair of layers defined in the previous chapters. Now, to find out how this will be achieved, go ahead and start reading!

{mospagebreak title=Review: a quick look at some previous sample classes}

Just in case you haven’t read the two previous articles, where I explained in detail how to create two sample domain and data access layers, below I listed the definitions of the classes that compose the layers. This will allow you to take a close  look at them and quickly understand how they work.

First, here is the source code of the classes that comprise the domain layer, along with an example that shows how to use it for modeling some simple user objects. Here are the corresponding sample files:

(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 its name implies, the above “DomainObjectAbstract” class defines the behavior and structure of generic domain objects, whose properties can be added and removed on the fly, thanks to the implementation of the “__set()”, __get()” and “__unset()” PHP magic functions. With this class seated on top of the hierarchy, creating a sub class that spawns concrete user objects is reduced to doing something as simple as this: 

(User.php)

 

 

<?php

 

 

class User extends DomainObjectAbstract

{

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

}

That was easy to code and read, wasn’t it? Now, if you ever want to employ the previous “User” class to create a concrete user object, it could be done in a snap, in the following way:

$user = new User();

$user->fname = ‘Julie';

$user->lname = ‘Smith';

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

If you analyze the two earlier classes, you’ll realize that they’re the building blocks of a domain layer composed of objects that are nothing but basic data containers with a predictable behavior. This approach is very useful and efficient, as the objects are easy to test, and completely ignorant of the persistent storage mechanism.

With the domain layer already set, it’s time to show the structure of the data access layer. Disappointingly, it is made up of only a trivial MySQL abstraction class called “MySQLAdapter,” whose definition 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{}

Since all that the “MySQLAdapter” class does is perform some common database operations, such as connecting to the server, running hard-coded queries and fetching rows in result sets, I’m not going to spend more time explaining its driving logic. It’s valid to notice, though, that this class is the only element that comprises the data access layer.

Naturally, if you’re like me, at this point you want an answer to the following question: if an application needs to save a user object (or any other kind of domain object) to the database via the previous “MySQLAdapter” class, how can this be done without breaking the rules of the persistence ignorance paradigm?

Well, here’s where data mappers come in. Their mission is to keep those domain objects isolated from the data access layer. But this is theory that needs to be backed up with some functional code. Therefore, in the following segment I’m going to start coding a data mapper class, so you’ll be able to understand its underlying logic.

Now, click on the link below and read the section to come.         

{mospagebreak title=Building an abstract data mapper class}

In the section that you just read, I promised that you’d learn how to build a data mapper class from scratch. Well, in keeping with that, please look at the following code fragment. It defines the generic structure of an abstract mapper:  

(DataMapperAbstract.php)

 

 

<?php

 

 

abstract class DataMapperAbstract

{

    protected $_db = NULL;

    protected $_table = ”;

    protected $_identityMap = array();

   

    public function __construct(MySQLAdapter $db)

    {

        $this->_db = $db;   

    }

   

    // get domain object by ID (implemented by concrete domain object subclasses)

    abstract public function find($id);

   

    // insert/update domain object (implemented by concrete domain object subclasses)

    abstract public function save(DomainObjectAbstract $domainObject);

   

    // delete domain object (implemented by concrete domain object subclasses)

    abstract public function delete(DomainObjectAbstract $domainObject);

}

Definitely, the definition of the above “DataMapperAbstract” class brings some interesting things to the table that deserve a deeper analysis. As you can see, this class defines a clean, abstract interface, which via concrete implementations, will perform CRUD operations on domain objects by using an instance of the MySQL adapter.

The class not only uses a $_table property to map those operations to a specified database table, but defines another property called $_identityMap. As you’ll see in a moment, this latter will be used for building an identity map to keep track of what objects were fetched from the database.

If you’re interested in a fuller explanation of  the Identity Map and other design patterns, I suggest to you grab a copy of Martin Fowler’s book, Patterns of Enterprise Application Architecture, or visit Fowler’s Identity Map page.

So far, so good. Having defined an abstract mapper class, the next logical step is to create a concrete one that permits you to work directly with user domain objects. That will be the topic that I’m going to discuss in the next section.

{mospagebreak title=Mapping concrete user domain objects with a user mapper class}

Without a doubt, the best way to understand the logic that stands behind a data mapper is by subclassing the previous “DataMapperAbstract” class. In this case, the goal is to map user domain objects to a single MySQL table, so it’s necessary to define a concrete user mapper class that implements the methods defined by the abstract parent. This is basically Inheritance 101, so take a look at the following file, which partially defines the user mapper class:

(UserMapper.php)

 

 

<?php

 

 

class UserMapper extends DataMapperAbstract

{

    protected $_table = ‘users';

   

    // fetch domain object by ID

    public function find($id)

    {

        // if the requested domain object exists in the identity map, get it from the there

        if (array_key_exists($id, $this->_identityMap))

        {

            return $this->_identityMap[$id];

        }

        // if not, get domain object from the database

        $this->_db->query("SELECT * FROM $this->_table WHERE id = $id");

        if ($row = $this->_db->fetch())

        {

            $user = new User;

            $user->id = $row->id;

            $user->fname = $row->fname;

            $user->lname = $row->lname;

            $user->email = $row->email;

            // save domain object to the identity map

            $this->_identityMap[$id] = $user;

            return $user;

        }

    }

   

    // save domain object

    public function save(DomainObjectAbstract $user)

    {

        // update domain object

        if ($user->id !== NULL)

        {

            $this->_db->query("UPDATE $this->_table SET fname = ‘$user->fname’, lname = ‘$user->lname’, email = ‘$user->email’ WHERE id = $user->id");

        }

        // insert domain object

        else

        {

            $this->_db->query("INSERT INTO $this->_table (id, fname, lname, email) VALUES (NULL, ‘$user->fname’, ‘$user->lname’, ‘$user->email’)");

        }

    }

}

As the above file shows, building a user mapper class that retrieves, inserts and updates user domain objects is by no means rocket science. In the previous example, the mapper uses the MySQL adapter to perform the required database operations via its “query()” method, but naturally it’s possible to get the same results by using methods with a higher level of abstraction.

Also, you should pay attention to the implementation of the mapper’s “find()” method, which uses an identity map to keep track of which objects were retrieved from the database. In simple terms, if the requested object exists in the map, it’s retrieved from there. Otherwise, the mapper first fetches the required data from the corresponding MySQL table, then populates a fresh user object with the data, and finally saves the object to the map. Here, it’s clear to see that an identity map not only allows you to track objects easily, but behaves like a memory-based cache that saves unnecessary trips to the database.

Hopefully, at this point you’ve learned how to build a basic data mapper class that decouples user objects from their storage mechanism. In its current state, the mapper is somewhat immature, as it is only able to fetch, insert, and update objects. However, the capability for deleting objects will be added in the next tutorial, so in the meantime feel free to play with all the examples shown before. Such practice will help you to gain a better understanding of how to build data mappers in PHP.

Final thoughts

In this third episode of the series, I started developing a basic user mapper class, which allows you to map user domain objects to their associated database table in a fairly easy way. In its current state, this sample mapper is only capable of retrieving and saving the corresponding domain objects to the storage mechanism, which is fine for now.

Nevertheless, it’d be highly desirable to provide the mapper with the ability to delete domain objects via a simple method. That’s exactly what I’m going to discuss in the next part of the series, so you won’t want to miss it!

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

chat