Home arrow PHP arrow Handling Collections of Domain Objects in PHP

Handling Collections of Domain Objects in PHP

In this fourth part of the series, I will build a simple countable iterator. It will be able to easily manipulate collections of entities by using an array-like notation. What’s more, if you frequently implement different kinds of inner iterators, then you'll quickly understand the logic behind this one.

TABLE OF CONTENTS:
  1. Handling Collections of Domain Objects in PHP
  2. Building a class to handle collections of entities
By: Alejandro Gervasio
Rating: starstarstarstarstar / 5
January 03, 2011

print this article
SEARCH DEV SHED

TOOLS YOU CAN USE

advertisement

Although in many cases the pragmatic nature of PHP coupled to the functionality provided by well-known design patterns permit you to tackle a certain number of problems in a fairly efficient and elegant way, sometimes it's necessary to appeal to more complex and abstract solutions. These are often used at the enterprise level, where large applications are the rule and not the exception.

That's exactly the case with a Unit of Work (UoW). This powerful paradigm allows you to optimize operations performed on domain objects via a transactional model that resembles the one found in many RDBMS. Simply put, domain objects are queued in memory and scheduled for further insertion, updating or removal according to the requirements of client code. Finally, all of these operations are executed in one go, therefore decreasing accesses to the underlying storage mechanism.

As with any other design pattern, it's feasible to implement a UoW using different programming languages, including PHP. In keeping with this concept, in earlier installments of this series I went through the development of a few loosely-coupled classes to demonstrate the functionality of the pattern. So far, I've created an abstract UoW, along with some additional dependencies, such as an abstract data mapper, an entity-modeling class and a simple MySQL adapter.

It's valid to note, though, that aside from performing insertions, updates and deletions, the UoW must also be capable of pulling collections of entities out of the persistence layer. Since the simplest way to achieve this is by creating a countable iterator, in this fourth tutorial of the series I'm going to create one whose driving logic will be quite simple to grasp.

Ready to continue learning how to implement a Unit of Work in PHP? Then begin reading!

Review: building a basic data access layer

Prior to showing the iterator that will be responsible for manipulating collections of domain objects, I'd like to spend a few moments reintroducing the source code corresponding to the interface and the MySQL abstraction class developed in the preceding installment of this series. When used in conjunction, they implement a simple database adapter. 

Having said that, here's the interface, whose signature looks as follows:

(DatabaseAdapterInterface.php)

<?php

interface DatabaseAdapterInterface
{
    function connect();
   
    function disconnect(); 
   
    function query($query);
   
    function fetch(); 
   
    function select($table, $where, $fields, $order, $limit, $offset);
   
    function insert($table, array $data);
   
    function update($table, array $data, $where);
   
    function delete($table, $where);
   
    function getInsertId();
   
    function countRows();
   
    function getAffectedRows();
}

As you'll surely agree with me, understanding the structure of the above "DatabaseAdapterInterface" interface is a straightforward process. Since the interface establishes a contract that must be fulfilled by all of the database adapters created from this point onward, here's the definition of the one that works specifically with MySQL. Check it out:

(MySQLAdapter.php)

<?php

class MySQLAdapter implements DataBaseAdapterInterface
{
    protected $_config = array();
    protected $_link;
    protected $_result;
    protected static $_instance;
   
    /**
     * Get the Singleton instance of the class
     */
    public static function getInstance(array $config = array())
    {
        if (self::$_instance === null) {
            self::$_instance = new self($config);
        }
        return self::$_instance;
    }
   
    /**
     * Class constructor
     */
    protected function __construct(array $config)
    {
        if (count($config) !== 4) {
            throw new MySQLAdapterException('Invalid number of connection parameters.');  
        }
        $this->_config = $config;
    }
   
    /**
     * Prevent cloning the instance of the class
     */
    protected function __clone(){}
   
    /**
     * Connect to MySQL
     */
    public function connect()
    {
        // connect only once
        if ($this->_link === null) {
            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());
            }
            unset($host, $user, $password, $database);      
        }
    }

    /**
     * Execute the specified query
     */
    public function query($query)
    {
        if (!is_string($query) || empty($query)) {
            throw new MySQLAdapterException('The specified query is not valid.');  
        }
        // lazy connect to MySQL
        $this->connect();
        if (!$this->_result = mysqli_query($this->_link, $query)) {
            throw new MySQLAdapterException('Error executing the specified query ' . $query . mysqli_error($this->_link));
        }
    }
   
    /**
     * Perform a SELECT statement
     */
    public function select($table, $where = '', $fields = '*', $order = '', $limit = null, $offset = null)
    {
        $query = 'SELECT ' . $fields . ' FROM ' . $table
               . (($where) ? ' WHERE ' . $where : '')
               . (($limit) ? ' LIMIT ' . $limit : '')
               . (($offset && $limit) ? ' OFFSET ' . $offset : '')
               . (($order) ? ' ORDER BY ' . $order : '');
        $this->query($query);
        return $this->countRows();
    }
   
    /**
     * Perform an INSERT statement
     */ 
    public function insert($table, array $data)
    {
        $fields = implode(',', array_keys($data));
        $values = implode(',', array_map(array($this, 'quoteValue'), array_values($data)));
        $query = 'INSERT INTO ' . $table . '(' . $fields . ')' . ' VALUES (' . $values . ')';
        $this->query($query);
        return $this->getInsertId();
    }
   
    /**
     * Perform an UPDATE statement
     */
    public function update($table, array $data, $where = '')
    {
        $set = array();
        foreach ($data as $field => $value) {
            $set[] = $field . '=' . $this->quoteValue($value);
        }
        $set = implode(',', $set);
        $query = 'UPDATE ' . $table . ' SET ' . $set
               . (($where) ? ' WHERE ' . $where : '');
        $this->query($query);
        return $this->getAffectedRows(); 
    }
   
    /**
     * Perform a DELETE statement
     */
    public function delete($table, $where = '')
    {
        $query = 'DELETE FROM ' . $table
               . (($where) ? ' WHERE ' . $where : '');
        $this->query($query);
        return $this->getAffectedRows();
    }
   
    /**
     * Single quote the specified value
     */
    public function quoteValue($value)
    {
        if ($value === null) {
            $value = 'NULL';
        }
        else if (!is_numeric($value)) {
            $value = "'" . mysqli_real_escape_string($this->_link, $value) . "'";
        }
        return $value;
    }
   
    /**
     * Fetch a single row from the current result set (as an associative array)
     */
    public function fetch()
    {
        if ($this->_result !== null) {
            if ((!$row = mysqli_fetch_array($this->_result, MYSQLI_ASSOC))) {
                $this->freeResult();
                return false;
            }
            return $row;
        }
    }

    /**
     * Get the insertion ID
     */
    public function getInsertId()
    {
        return $this->_link !== null ?
               mysqli_insert_id($this->_link) :
               null; 
    }
   
    /**
     * Get the number of rows returned by the current result set
     */ 
    public function countRows()
    {
        return $this->_result !== null ?
               mysqli_num_rows($this->_result) :
               0;
    }
   
    /**
     * Get the number of affected rows
     */
    public function getAffectedRows()
    {
        return $this->_link !== null ?
               mysqli_affected_rows($this->_link) :
               0;
    }
   
    /**
     * Free up the current result set
     */
    public function freeResult()
    {
        if ($this->_result !== null) {
            mysqli_free_result($this->_result);  
        }
    }
   
    /**
     * Close explicitly the database connection
     */
    public function disconnect()
    {
        if ($this->_link !== null) {
            mysqli_close($this->_link);
            $this->_link = null;
        }
    }
   
    /**
     * Close automatically the database connection when the instance of the class is destroyed
     */
    public function __destruct()
    {
        $this->disconnect();
    }
}

 

(MySQLAdapterException.php)

<?php

class MySQLAdapterException extends Exception{}

Since the above MySQL handling class was discussed in depth in a previous tutorial of the series, I'm not going to waste your valuable time (and mine, of course) explaining how it works one more time. The only detail worth stressing here is that the class is an implementer of the earlier interface, which means that it defines some discrete methods that allow it to perform CRUD operations on a selected table.

If you're asking yourself what the point is in coding a class like this, let me remind you that it'll be used by the sample UoW to insert, update and delete domain objects from a specific MySQL database. But before you have the chance to see this process in action, it's necessary to create a few additional classes, including one responsible for handling collections of entities.

In the next segment I'm going to define such a class, so if you want to learn more on this topic, just jump ahead and read the lines to come.



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