Home arrow PHP arrow Page 2 - Finishing a Data Mapper Class for the Data Mapper Design Pattern

Review: mapping domain objects to database tables - PHP

In this penultimate part of the series on the data mapper design pattern, I demonstrate how to provide the UserMapper class we've previously created with the ability to delete users from its associated MySQL table.

TABLE OF CONTENTS:
  1. Finishing a Data Mapper Class for the Data Mapper Design Pattern
  2. Review: mapping domain objects to database tables
  3. Enabling the user mapper class to delete users
  4. The user mapper class's full source code
By: Alejandro Gervasio
Rating: starstarstarstarstar / 3
March 31, 2010

print this article
SEARCH DEV SHED

TOOLS YOU CAN USE

advertisement

As usual, before I provide the user mapper class with the capability to delete users from the associated MySQL table, I'd like to spend a few moments reintroducing the definitions of all of the sample classes developed so far. This includes the ones that allow you to create both domain objects and mappers, and the basic database driver that abstracts the access to MySQL.

First, here's the base "DomainObjectAbstract" class that models generic domain objects:

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

Did you recall how this class does its thing? Good. Now, it's time to show the one that creates user domain objects. Here it is:

(User.php)

 

 

<?php

 

 

class User extends DomainObjectAbstract

{

    protected $_data = array('id' => NULL, 'fname' => '', 'lname' => '', 'email' => '');

}

The above class was easy to code and read, indeed. Therefore, let's move on and look at the following one, which is the MySQL driver that makes up the data access layer:

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

Having shown the definition of the previous "MySQLAdapter" class, it's time now to list the full source code of the data mappers. Here you have them:

(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);

}

(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')");

        }

    }

}

That was truly a lot of code to read! Yet the effort was really worthwhile, as the process reminded you how we built a few simple data mappers in PHP. What's more, you recalled how to implement an identity map within a user mapper class, in order to keep track of what user objects have been retrieved from the database. What else can you ask for?

Well, the earlier user mapper still lacks the ability to delete users from the corresponding MySQL table. This issue obviously must be addressed properly. Therefore, in the following section I'm going to implement an additional method that will perform this deletion task in a comprehensive fashion.

Now, to see how this whole new method will be defined, 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: