Home arrow PHP arrow PHP Services Layers: Data Mappers

PHP Services Layers: Data Mappers

In this second part of a series on PHP services layers, I add a couple of data mappers to our sample application. These data mappers will allow us to bridge the domain model with the data access layer. With this addition, we're one step closer to implementing a fully-functional user service.

TABLE OF CONTENTS:
  1. PHP Services Layers: Data Mappers
  2. Building an abstract data mapper
By: Alejandro Gervasio
Rating: starstarstarstarstar / 0
October 17, 2011

print this article
SEARCH DEV SHED

TOOLS YOU CAN USE

advertisement

If you need to develop flexible, highly-extendable PHP applications that can be interfaced easily with different client layers, you will want to consider a service layer. As a fundamental pillar of Domain Driven Design (DDD), a service is an enterprise-level pattern that will let you encapsulate application logic behind a single interface -- which can be consumed by distinct clients (yes, including your carefully-crafted action controllers!) while keeping code duplication to a minimum.

There's little sense to highlighting the benefits of a service layer without providing proof. To partially address this issue, in the introductory part of this series I started building a sample application. It will use the functionality offered by a service to manipulate some user entities.

Admittedly, in its current state the application looks somewhat skeletal. I only managed to create its domain model, which is pretty simplistic. In this second installment, however, Iím going to turn it into a slightly more functional structure. And how will I do that? Well, we need to build an additional layer that permits you to bridge the domain model with the underlying storage mechanism (not yet implemented). Not surprisingly, this new layer will be made up of some easily customizable data mappers.

With that said, are you ready to continue this educational journey of building a service in PHP? Then jump in and start reading!

Recap time: a brief look at the applicationís domain model

Just in case you missed the preceding part of this series, where I developed the sample domain model, below I included its source classes.

The first class is an abstract parent, responsible for modeling the common structure and behavior of generic entities. Here it is:

(MyApplication/Entity/AbstractEntity.php)

<?php

namespace MyApplicationEntity;

abstract class AbstractEntity
{
    protected $_values = array();
    protected $_allowedFields = array();
   
    /**
     * Class constructor
     */
    public function __construct(array $data)
    {
        foreach ($data as $name => $value) {
            $this->$name = $value;
        }
    }
   
    /**
     * Assign a value to the specified field via the corresponding mutator (if it exists);
     * otherwise, assign the value directly to the '$_values' protected array
     */
    public function __set($name, $value)
    {  
        if (!in_array($name, $this->_allowedFields)) {
            throw new EntityException('The field ' . $name . ' is not allowed for this entity.'); 
        }
        $mutator = 'set' . ucfirst($name);
        if (method_exists($this, $mutator) && is_callable(array($this, $mutator))) {
            $this->$mutator($value);          
        }
        else {
            $this->_values[$name] = $value;
        }   
    }
   
    /**
     * Get the value assigned to the specified field via the corresponding getter (if it exists);
    otherwise, get the value directly from the '$_values' protected array
     */
    public function __get($name)
    {
        if (!in_array($name, $this->_allowedFields)) {
            throw new EntityException('The field ' . $name . ' is not allowed for this entity.');   
        }
        $accessor = 'get' . ucfirst($name);
        if (method_exists($this, $accessor) && is_callable(array($this, $accessor))) {
            return $this->$accessor;   
        }
        if (isset($this->_values[$name])) {
            return $this->_values[$name];  
        }
        throw new EntityException('The field ' . $name . ' has not been set for this entity yet.');
    }

    /**
     * Check if the specified field has been assigned to the entity
     */
    public function __isset($name)
    {
        if (!in_array($name, $this->_allowedFields)) {
            throw new EntityException('The field ' . $name . ' is not allowed for this entity.');
        }
        return isset($this->_values[$name]);
    }

    /**
     * Unset the specified field from the entity
     */
    public function __unset($name)
    {
        if (!in_array($name, $this->_allowedFields)) {
            throw new EntityException('The field ' . $name . ' is not allowed for this entity.');
        }
        if (isset($this->_values[$name])) {
            unset($this->_values[$name]);
        }
    }

    /**
     * Get an associative array with the values assigned to the fields of the entity
     */
    public function toArray()
    {
        return $this->_values;
    }             
}

 

(MyApplication/Entity/EntityException.php)

<?php

namespace MyApplicationEntity;

class EntityException extends Exception{}

While at first glance the implementation of the above ďAbstractEntityĒ class seems intimidating, this is a mistaken impression, trust me. In fact, the class simply uses some PHP magic methods to get and fetch the values assigned to the fields of an entity. This process can be performed either via the corresponding mutators/getters (if they exist) or by using the protected $_values array. Got it? Great.

And now that you understand the logic of the previous class, itís time to look at the next one. This is a derivative of the abstract parent, tasked with modeling plain user objects. Check it out:

(MyApplication/Entity/User.php)

<?php

namespace MyApplicationEntity;

class User extends AbstractEntity
{  
    protected $_allowedFields = array('id', 'fname', 'lname', 'email');
   
    /**
     * Set the user's ID
     */
    public function setId($id)
    {
        if(!filter_var($id, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 999999)))) {
            throw new EntityException('The specified ID is invalid.');
        }
        $this->_values['id'] = $id;
    }
   
    /**
     * Set the user's first name
     */ 
    public function setFname($fname)
    {
        if (strlen($fname) < 2 || strlen($fname) > 32) {
            throw new EntityException('The specified first name is invalid.');
        }
        $this->_values['fname'] = $fname;
    }
       
    /**
     * Set the user's last name
     */
    public function setLname($lname)
    {
        if (strlen($lname) < 2 || strlen($lname) > 32) {
            throw new EntityException('The specified last name is invalid.');
        }
        $this->_values['lname'] = $lname;
    }
   
    /**
     * Set the user's email address
     */
    public function setEmail($email)
    {
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            throw new EntityException('The specified email address is invalid.');
        }
        $this->_values['email'] = $email;
    }                   
}

There you have it. With minor effort, I managed to set up a basic, yet functional domain model,  composed of only a few simple user entities. So, whatís the next step? Well, considering that the model must be persisted in some form, itís necessary to build a new layer that acts like a mediator with the persistence mechanism.

Usually, this layer is implemented through some mapping classes, and Iíll be using this approach. So, in the following section Iím going to create a couple of data mappers. They will be responsible for performing CRUD operations with the user entities present in the domain model.      

To see how these mappers will be developed, click on the link below and keep reading.



 
 
>>> More PHP Articles          >>> More By Alejandro Gervasio
 

blog comments powered by Disqus
escort Bursa Bursa escort Antalya eskort
   

PHP ARTICLES

- Hackers Compromise PHP Sites to Launch Attac...
- Red Hat, Zend Form OpenShift PaaS Alliance
- PHP IDE News
- BCD, Zend Extend PHP Partnership
- PHP FAQ Highlight
- PHP Creator Didn't Set Out to Create a Langu...
- PHP Trends Revealed in Zend Study
- PHP: Best Methods for Running Scheduled Jobs
- PHP Array Functions: array_change_key_case
- PHP array_combine Function
- PHP array_chunk Function
- PHP Closures as View Helpers: Lazy-Loading F...
- Using PHP Closures as View Helpers
- PHP File and Operating System Program Execut...
- PHP: Effects of Wrapping Code in Class Const...

Developer Shed Affiliates

 


Dev Shed Tutorial Topics: