Home arrow MySQL arrow Building a PHP ORM: Deploying a Blog

Building a PHP ORM: Deploying a Blog

In this conclusion to a three-part tutorial, you'll see that implementing a customizable ORM using modern development techniques is a fairly straightforward process. We'll use the dependency injection technique, the data mapper pattern and a domain model. This powerful combination allows you to easily manipulate relationships between entities.

TABLE OF CONTENTS:
  1. Building a PHP ORM: Deploying a Blog
  2. Building Dependency Injection Containers and Service Locators
By: Alejandro Gervasio
Rating: starstarstarstarstar / 0
December 08, 2011

print this article
SEARCH DEV SHED

TOOLS YOU CAN USE

advertisement

Letís face it: building a full-featured ORM in PHP (or in any other programming language) is a challenging and difficult process that requires careful planning. You'll need a solid background in some popular data persistence patterns, such as Active Record and Data Mapper. Thatís a tall order, especially since this kind of package must be able to handle all of the possible relationships between the objects that compose an application, not to mention the validation that must be performed on them.

Fortunately, thereís a healthy variety of ORMs available that will do the hard work for you. Whatís more, Doctrine, RedBeanPHP and Propel (just to name a few) are good examples of well-trusted ORMs that provide a remarkable set of features right out of the box.

While itís fair to admit that these libraries (and others) boast many happy users in active and vibrant communities, in some use cases, using them may be overkill. Perhaps there are times when you only need to define some common relationships between your domain objects and use some clever approaches (like proxy objects) to load them on request from the database, and nothing else.

If at this moment youíre facing a situation like this, hopefully this tutorial will catch your attention. It will show you in a step-by-step manner how to build a small ORM, which youíll be able to tweak and customize at will to fit your own requirements. Moreover, if you've already read the two installments that precede this one, itís probable that youíre familiar with the inner workings of this sample ORM. In those chapters I implemented the ORMís data access and mapping layers, along with a simple domain model.

To be frank, the development of this last tier is entirely optional; however, it's useful for demonstrating the ORMís actual functionality in the deployment of a blog program, which naturally will handle some ďtypicalĒ domain objects, namely blog entries, comments and authors.

With the aforementioned layers ready to be put into action, itís time to give to the project its final touches. In line with this idea, in this last episode Iíll be adding to the ORM the remaining components that it needs to work as intended. These include a mixture of proxy classes, dependency injection containers and a few basic services.

Want to see how all these pieces can be put to work side by side in a productive way? Then keep reading!

Creating Proxy Classes

In consonance with the concepts deployed in the introduction, itís necessary to add to the ORMís existing structure a set of proxy classes. These will be responsible for lazy-loading domain objects from the underlying storage (in this particular case a MySQL database). 

With that said, hereís the definition of these proxies, along with the interface that they implement. Check them out:

(Blog/Model/Proxy/ProxyInterface.php)

<?php

namespace Blog\Model\Proxy;

interface ProxyInterface
{
    public function load();
}

 

(Blog/Model/Proxy/AbstractProxy.php)

<?php

namespace Blog\Model\Proxy;
use Blog\Model\Mapper;

abstract class AbstractProxy
{
    protected $_mapper;
    protected $_params;

    /**
     * Constructor
     */
    public function __construct(Mapper\AbstractMapper $mapper, $params)
    {
        if (!is_string($params) || empty($params)) {
            throw new \InvalidArgumentException('The mapper parameters are invalid.');
        }
        $this->_mapper = $mapper;
        $this->_params = $params;
    }

    /**
     * Get the mapper
     */
    public function getMapper()
    {
        return $this->_mapper;
    }

    /**
     * Get the mapper parameters
     */
    public function getParams()
    {
        return $this->_params;
    }
}

 

(Blog/Model/Proxy/EntityProxy.php)

<?php

namespace Blog\Model\Proxy;
use Blog\Model;

class EntityProxy extends AbstractProxy implements ProxyInterface
{
    protected $_entity;

    /**
     * Load an entity via the mapper's 'findById()' method
     */
    public function load()
    {
        if ($this->_entity === null) {
            $this->_entity = $this->_mapper->findById($this->_params);
            if (!$this->_entity instanceof Model\AbstractEntity) {
                throw new \RuntimeException('Unable to load the related entity.');
            }
        }
        return $this->_entity;
    }
}

 

(Blog/Model/Proxy/CollectionProxy.php)

<?php

namespace Blog\Model\Proxy;
use Blog\Model\Collection;

class CollectionProxy extends AbstractProxy implements ProxyInterface, \Countable, \IteratorAggregate
{
    protected $_collection;

    /**
     * Load the entity collection via the mapper's 'find()' method
     */
    public function load()
    {
        if ($this->_collection === null) {
            $this->_collection = $this->_mapper->find($this->_params);
            if (!$this->_collection instanceof Collection\EntityCollection) {
                throw new \RuntimeException('Unable to load the related collection.');
            }
        }
        return $this->_collection;
    }

    /**
     * Count the number of elements in the collection
     */
    public function count()
    {
        return count($this->load());
    }

    /**
     * Load the entity collection when the proxy is used in a 'foreach' construct
     */
    public function getIterator()
    {
        return $this->load();
    }
}

From the above code snippet, itís clear to see how the aforementioned proxy classes do their thing. Simply put, they act like ďstand-inĒ elements, which use the functionality of an injected mapper (notice the implementation of the constructor in the abstract proxy) to fetch on request from the database either a single entity or a collection of them.

Although the use of proxies might seem somewhat confusing and even irrelevant at this point, don't worry. When I show you how to retrieve from storage some blog entries and lazy-load the related comments and authors, youíll realize how useful they are in the implementation of more efficient model persistence strategies.

So far, so good. Having shown you the previous proxy classes, this sample ORM is now a bit more functional. However, thereís no need to rush, as there are still some additional components that must be constructed to improve the projectís overall efficiency.

Object instantiation should be separated as much as possible from application logic. To achieve this goal, in the next section Iíll be defining a couple of dependency injection containers, which will neatly hide from client code the creation of some complex object graphs.    

To see how this will be done, click on the link below and read the lines to come.



 
 
>>> More MySQL Articles          >>> More By Alejandro Gervasio
 

blog comments powered by Disqus
escort Bursa Bursa escort Antalya eskort
   

MYSQL ARTICLES

- Oracle Unveils MySQL 5.6
- MySQL Vulnerabilities Threaten Databases
- MySQL Cloud Options Expand with Google Cloud...
- MySQL 5.6 Prepped to Handle Demanding Web Use
- ScaleBase Service Virtualizes MySQL Databases
- Oracle Unveils MySQL Conversion Tools
- Akiban Opens Database Software for MySQL Use...
- Oracle Fixes MySQL Bug
- MySQL Databases Vulnerable to Password Hack
- MySQL: Overview of the ALTER TABLE Statement
- MySQL: How to Use the GRANT Statement
- MySQL: Creating, Listing, and Removing Datab...
- MySQL: Create, Show, and Describe Database T...
- MySQL Data and Table Types
- McAfee Releases Audit Plugin for MySQL Users

Developer Shed Affiliates

 


Dev Shed Tutorial Topics: