Implementing the Data Mapper Design Pattern in PHP 5

In this first part of a five-part series, I introduce you to implementing the Data Mapper design pattern in PHP 5. This pattern attempts to solve the issue of the strong coupling that often exists between the domain objects present in an application and the underlying persistence mechanism. This benefit comes at a cost, since data mappers add a new layer of complexity. Living with this minor trade-off is quite worthwhile, though, as you’ll see.

Since the web is in constant evolution and merges a variety of technologies and languages, developing web applications (specially mid-sized and large-scale ones) has become a challenging process. Indeed, applications require extensive planning, modeling and testing, before reaching a stable deployment stage.

In the case of PHP, different solutions and tools have emerged in the last few years, aimed at making the development process as painless as possible. These include a large number of MVC-driven frameworks, which, when coupled with well-trusted libraries, allow developers to build complex web programs without having to write code from scratch.

Without a doubt, using a framework that implements an MVC layer will help in developing applications that separate business and application logic from the visual presentation. In many cases developers will start setting up the persistent storage mechanism, usually composed of some relational tables; then they’ll define the model classes that will manage those tables; and finally they’ll code the controllers and views respectively. In short, what could be faster, more effective and simpler than this strategy?

Well, for a small application tightly coupled to a specific framework, and even worse, to a predefined persistence mechanism, this approach will work fairly well. However, what happens if the application suddenly needs to be modified to persist using a web service or a bunch of XML files? All of those beautifully-crafted, database-dependent models will cry, and loudly, trust me. Usually, models encapsulate multiple domain objects, such as users, blog posts and comments, but this doesn’t necessarily mean that they must always maintain their state through the same persistence layer. Are you getting the big picture here?

Fortunately, there are a few design patterns that permit you to fairly easily decouple domain objects from the underlying persistent mechanism (a characteristic known as persistence ignorance or PI). Data Mapper is one of the most popular. Data Access Objects (DAO) are also used with similar purposes in many cases, but as this article’s title suggests, in the lines to come I’m going to discuss how to implement only the former.

Now that you have at least a vague idea of the goal for using the Data Mapper pattern, it’s time to show how to implement it in PHP 5. So, go ahead and start reading. A lot of code is waiting for us!

{mospagebreak title=The Data Mapper pattern: an introductory example}

As mentioned in the introduction, the implementation of the Data Mapper design pattern allows you to isolate all of the domain objects present in an application from the persistence mechanism in a pretty elegant and efficient way. Naturally, this brief description is somewhat obscure and abstract, so to shed some light, here’s a contrived example that shows how to use a data mapper to perform CRUD operations on some persistence-ignorant user domain objects. The example in question is as follows:

<?php

 

 

// get instance of MySQL adapter class

$db = MySQL::getInstance();

 

 

// create instance of ‘UserMapper’ class

$userMapper = new UserMapper($db);

 

 

// get existing user by ID

$user = $userMapper->find(1);

// display user data

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

 

 

// create a new user and add her to the database

$user = new User();

$user->fname = ‘Sandra';

$user->lname = ‘Smith';

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

$userMapper->save($user);

 

 

// update existing user

$user = $userMapper->find(2);

$user->fname = ‘Sandy';

$userMapper->save($user);

 

 

// delete existing user

$userMapper->delete($user);   

The above code sample shows how to use an instance of data mapper class to perform CRUD operations on a couple of user objects. As you can see, the data mapper is aware of the storage mechanism, which in this case happens to be a simple MySQL database, but the domain objects are completely ignorant of it. In consequence, it’s the responsibility of the data mapper to execute the pertinent database operations, a process that not only permits decoupling the domain objects from the persistence layer, but makes those objects much easier to test and maintain.

Of course, this is only an introductory example that hides all of the complexities of the Data Mapper pattern behind a clean interface. My plan for this series, though, is to build a complete example from scratch that covers the development of the domain object classes, along with the associated data mappers, so get ready to read a lot of code samples. You’ve been warned!

At this point, you should have a more appropriate idea of the advantages to using the Data Mapper design pattern specifically in PHP 5, so it’s time to start defining the sample classes required to implement it in a useful way. With that idea in mind, in the following segment I’m going to build the first of these classes, which will define the generic structure and behavior of the domain objects.

To learn how this initial class will be defined, click on the link below and read the next few lines.

{mospagebreak title=Building a generic domain object class}

Before I start showing you how to build a data mapper class whose responsibility will be focused on decoupling domain objects from the underlying persistence mechanism, it’s necessary to define the class that will permit you to create the concrete domain objects. This class will be an abstract one, and its definition will look like this:

(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{}

Essentially, the previous "DomainObjectAbstract" class is only a simple data container that adds and deletes domain object properties on the fly, thanks to the implementation of the "__set()," "__get()" and "__unset()" PHP 5 magic methods. Additionally, the class throws a couple of custom exceptions at the proper places, in case the client code attempts to assign an invalid property to the domain object being manipulated.

Apart from understanding the inner workings of this class, which is fairly straightforward, you should notice that it models common objects, or resembling the phrase coined in the Java world, plain old PHP objects (POPO). This obviously makes testing and maintaining domain objects a breeze, as they aren’t tied to any specific storage mechanism.

Finally, I’d like to mention that the approach that I followed here to create this abstract domain object class was partially inspired by the example included in Pádraic Brady’s online book. 

Having clarified that point, and now that the generic structure of the domain objects has been set, the next logical step is to derive a subclass from the parent "DomainObjectAbstract" to create some concrete domain objects.

To learn more about how this subclass will be defined, click on the link that appears below and keep reading.

{mospagebreak title=Creating concrete domain objects}

The purpose of coding the previous "DomainObjectAbstract" class was logically to encapsulate as much functionality as possible within a construct that defines generic domain objects. Since this base class is abstract, it’s necessary to derive a subclass from it to create concrete domain objects. That’s really simple to grasp, right?

Since in upcoming tutorials of the series I’m going to discuss how to build a data mapper that will perform CRUD operations on a MySQL table containing user data, it makes sense to define a "User" class that inherits from the parent "DomainObjectAbstract."

Fortunately, building a class like this is an extremely simple task. Still not convinced? Then take a look at the following code fragment, which will make your doubts vanish: 

(User.php)

 

 

<?php

 

 

class User extends DomainObjectAbstract

{

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

}

Done. Now, there’s a "User" class that can be utilized as a container for storing the ID, and the first and last names of any number of users. What’s more, if I ever need to create a user domain object and dynamically assign to it some properties, the process would be as easy as this:

$user = new User();

$user->fname = ‘Susan';

$user->lname = ‘Norton';

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

While at a glance, it seems that the earlier "User" class doesn’t help too much in implementing the Data Mapper pattern, this first impression is wrong. In reality, this is an impressive breakthrough, as now any domain object spawned from the base "DomainObjectAbstract" class will be a POPO (remember, that’s a plain old PHP object) with little or no complexity, which can be easily tested by using any unit testing framework.

And best of all, it won’t be coupled to the underlying storage system, as this will be exclusively a responsibility of the data mappers. There are still some additional classes that need to be built first, before we get our hands dirty with the mappers, so for the moment be patient and take a peek at my final thoughts.

Final thoughts

That’s all for now. In this first installment of the series, I introduced you to implementing the Data Mapper design pattern in PHP 5. As I explained, the issue this pattern attempts to solve is the strong coupling that often exists between the domain objects present in an application and the underlying persistence mechanism. This benefit comes at a cost, since data mappers add a new layer of complexity. Even so, living with this minor trade-off is really worthwhile, believe me.

So far, I showed how to create a plain user domain object, which is a simple data container. So, what’s the next step? Well, obviously at some point it’ll be necessary to define a user data mapper class that specifically maps user objects to the corresponding storage mechanism.

In consonance with the example that you saw at the beginning of this article, that mechanism will be comprised of a single MySQL database table, which will store user-related data. Therefore, in the following tutorial I’m going to build a brand new class that will work specifically with that RDBMS.

Don’t miss the upcoming part!

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

antalya escort bayan antalya escort bayan Antalya escort diyarbakir escort