Home arrow PHP arrow Roll Your Own Repository in PHP: Building a User Repository Class

Roll Your Own Repository in PHP: Building a User Repository Class

In this sixth part of the series, I start using all of the sample classes defined previously to create a basic user repository class. The partial construction of this class calls for some extra work, such as defining a repository factory. The development process, as you'll see, is pretty straightforward, and shows how useful this kind of abstraction layer can be for concentrating querying code behind an intuitive API.

TABLE OF CONTENTS:
  1. Roll Your Own Repository in PHP: Building a User Repository Class
  2. Querying collections of user entities: building a user repository
By: Alejandro Gervasio
Rating: starstarstarstarstar / 3
December 08, 2010

print this article
SEARCH DEV SHED

TOOLS YOU CAN USE

advertisement

One of the biggest advantages of PHP is its pragmatism (which can turn into a curse when used inappropriately), as it allows developers to quickly start building functional web programs without having to tackle a steep learning curve or deal with a complicated API. As an application becomes larger and more complex, however, it is sometimes necessary to sacrifice a little of this pragmatism and construct some additional abstraction layers that permit you to keep the application modular and scalable for further improvements.

One typical case where an extra abstraction layer can be useful is in the construction of a repository, where it can help concentrate the query logic in a program that reveals a rich domain composed of a great variety of objects. Being a fundamental piece of Domain-Driven Design (DDD), a repository can be thought of as a mediator that acts between the domain and the mapping layers of a program. This mediator allows you to easily query collections of objects ,and produces the illusion of those collections residing in memory at the same time.

As with other topics related to applying the OOP paradigm in PHP, the most effective way to grasp the logic of a repository is by example. In keeping with this idea, in previous installments of this series I started building from scratch a sample web application. This application was responsible for manipulating simple user entities. So far, I've created the domain, mapping and data access layers corresponding to this application, and also defined a couple of additional classes that handle collections of entities through an array-like interface.

With all of these layers already up and running, the next logical step is to build a structure that permits you to put them to work together, while maintaining their isolation from each other. You're probably wondering what that structure is, right? Well, the "glue" for the aforementioned layers is a user repository class, and in this article I'm going to partially implement it, so that you can understand its driving logic.

Ready to learn how to create such a repository in a few simple steps? Then begin reading!             

Reviewing the collection classes created previously

As I explained in the introduction, a repository must be capable of querying collections of domain objects through a friendly API. To restrict the responsibility of the classes that compose this sample application and make them perform only a few discrete tasks, in this case I decided to create two independent classes responsible for handling collections of objects.

The first of these classes is an abstract parent tasked with manipulating generic entities. Its source code looks like this:

(CollectionAbstract.php)

<?php

abstract class CollectionAbstract implements Iterator, Countable, ArrayAccess
{
    protected $_entities = array();
   
    /**
     * Get the entities stored in the collection
     */
    public function getEntities()
    {
        return $this->_entities;
    }
   
    /**
     * Clear the collection
     */
    public function clear()
    {
        $this->_entities = array();
    }
    
    /**
     * Reset the collection (implementation required by Iterator Interface)
     */    
    public function rewind()
    {
        reset($this->_entities);
    }
   
    /**
     * Get the current entity in the collection (implementation required by Iterator Interface)
     */
    public function current()
    {
        return current($this->_entities);
    }
   
    /**
     * Move to the next entity in the collection (implementation required by Iterator Interface)
     */
    public function next()
    {
        next($this->_entities);
    }
   
    /**
     * Get the key of the current entity in the collection (implementation required by Iterator Interface)
     */
    public function key()
    {
        return key($this->_entities);
    }
   
    /**
     * Check if there are more entities in the collection (implementation required by Iterator Interface)
     */
    public function valid()
    {
        return (boolean) $this->current();
    }
   
    /**
     * Count the number of entities in the collection (implementation required by Countable Interface)
     */
    public function count()
    {
        return count($this->_entities);
    }
   
    /**
     * Add an entity to the collection (implementation required by ArrayAccess interface)
     */
    public function offsetSet($key, $entity)
    {
        if ($key === null) {
            if (!in_array($key, $this->_entities, true)) {
                $this->_entities[] = $entity;
                return;
            }
        }
        else if (!array_key_exists($key, $this->_entities)) {
            $this->_entities[$key] = $entity;
        }
    }
   
    /**
     * Remove an entity from the collection (implementation required by ArrayAccess interface)
     */
    public function offsetUnset($key)
    {
        if ($key instanceof EntityAbstract) {
            $entities = array();
            foreach ($this->_entities as $_entity) {
                if ($_entity !== $key) {
                    $entities[] = $_entity;
                }  
            }
            $this->_entities = $entities;
            return;
        }
        if (array_key_exists($key, $this->_entities)) {
            unset($this->_entities[$key]);
        }
    }
   
    /**
     * Get the specified entity in the collection (implementation required by ArrayAccess interface)
     */
    public function offsetGet($key)
    {
        if (array_key_exists($key, $this->_entities)) {
            return $this->_entities[$key];
        }
    } 
   
    /**
     * Check if the specified entity exists in the collection (implementation required by ArrayAccess interface)
     */    
    public function offsetExists($key)
    {
        return array_key_exists($key, $this->_entities);
    }
}

As you can see from the above code fragment, the previous "CollectionAbstract" class is an implementer of the Countable, Iterator and ArrayAccess PHP built-in interfaces. Its objective is to handle collections of generic entities through the set of methods declared by the interfaces. Its underlying logic is that simple.

With the earlier abstract parent neatly encapsulating most of the functionality required for manipulating domain objects by using an array-like approach, building a class that only works with user entities is a breeze. If you're still not convinced of this, then focus your attention on the following "UserCollection" subclass, which does exactly that: 

(UserCollection.php)

<?php

class UserCollection extends CollectionAbstract
{
    /**
     * Add a user to the collection
     */
    public function add($key, User $user)
    {
        $this->offsetSet($key, $user);
    }     
}

Were you expecting to see a longer code snippet? I don't think so. In either case, the above "UserCollection" class only implements a single method. This method, called "add()," assures that every object added to its internal collection will be effectively a user entity.

So far, so good. Provided that you've grasped how the two collection classes do their thing, it's time to  start building the user repository mentioned at the beginning. You'll finally see how all of the classes previously defined fit together.

To learn more on this topic, click on the link that appears below and read the following segment.



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