Home arrow PHP arrow Page 2 - PHP Service Layers: Modeling Domain Objects

Taking the first step: modeling domain objects - PHP

In this first part of a series, I introduce you to what a service layer is and how to use it in conjunction with an MVC stack. While you don’t need to use one in every possible case, a service layer can be of great help in interfacing sections of an application with multiple client layers.

TABLE OF CONTENTS:
  1. PHP Service Layers: Modeling Domain Objects
  2. Taking the first step: modeling domain objects
By: Alejandro Gervasio
Rating: starstarstarstarstar / 0
October 11, 2011

print this article
SEARCH DEV SHED

TOOLS YOU CAN USE

advertisement

As I explained in the preceding section, the first step toward the implementation of a user service layer is to set up a basic domain model. This model will contain some user objects. To accomplish this, in this case I’m going to use the following abstract class, responsible for modeling generic entities:

(MyApplication/Entity/AbstractEntity.php)

<?php

namespace MyApplication\Entity;

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 MyApplication\Entity;

class EntityException extends \Exception{}

As shown above, the “AbstractEntity” class is pretty similar to others that you’ve probably seen in articles previously published here at the Developer Shed network. In short, this class simply implements some magic PHP methods, like “__get()” and “__set(),” which are used to dynamically assign and retrieve the values assigned to the fields of a generic entity via the corresponding mutators/getters (if they’ve been implemented). Its driving logic is that simple.

So far, so good. With this abstract class neatly modeling the structure and minimal behavior of generic domain objects, you may be wondering what comes next, right? Since the service layer that I plan to build here will manipulate user entities, it’s necessary to spawn, from the previous abstract parent, a subclass that specifically models such objects.

Fear not, as the implementation of this derivative will be shown below. Just keep reading.   

Going one step further: modeling user entities

In reality, creating a subclass that exclusively models user entities is a simple process. If you’re still reluctant to believe in my words, take a peek at the following code fragment, which shows the implementation of this derivative:

(MyApplication/Entity/User.php)

<?php

namespace MyApplication\Entity;

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;
    }                   
}

Even though at first glance it looks rather complex, don’t be fooled. The earlier “User” class is nothing but a simple data holder (with a few specific constraints) which implements some mutators to store the ID, the first and last names of a user, and their email address.

With this subclass already up and running, I finally managed to set up a basic, clean domain model, which is composed of plain user objects. Of course, there’s no much that can be done with this layer on its own; the implementation of a fully-functional user service requires building mapping and data access layers as well. However, this is a work in progress; these additional structures will be developed in upcoming installments of this series.  

Final Thoughts

In this first part of the series, I attempted to provide you with an introduction to what a service layer is and how to use it in conjunction with an MVC stack. As with many other enterprise-level patterns, you don’t need to use a service layer in every possible use case. However, its implementation can be of great help for interfacing sections of an application with multiple client layers, such as the action controllers that you’ll see in many current MVC frameworks.

In addition, I've started developing the domain layer of a sample program. It will employ a service for manipulating user data, independently of the underlying infrastructure. At this point, this domain model is pretty anemic. It's currently composed of only a few user entities, which live in happy isolation.

With this structure already set, the next step is to create some data mappers, which will act like mediators between the entities nd the persistence layer. The creation of the mappers will be discussed in depth in the upcoming tutorial.

Don’t miss the next part!



 
 
>>> 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: