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

Querying collections of user entities: building a user repository - PHP

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

To keep things understandable and easy to follow, the repository class that I plan to construct here will only be able to retrieve user collections that match some simple criteria. It's possible to encapsulate more complex query logic, however, as the layer that does the leg work is the mapping one, which in turn uses the persistence mechanism to run the actual SQL queries behind the scenes.    

But it's time to stop talking and show the initial definition of the repository. This one, not surprisingly, is a new class. It's called "UserRepository" and its source code is shown below:

(UserRepository.php)

<?php

class UserRepository
{
    protected $_userMapper;
   
    /**
     * Class constructor
     */
    public function __construct(UserMapper $userMapper)
    {
        $this->_userMapper = $userMapper;   
    }
   
    /**
     * find users by their first names
     */
    public function findByFirstName($fname)
    {
        return $this->_userMapper->search("fname = '$fname'");
    }
   
    /**
     * find users by their last names
     */
    public function findByLastName($lname)
    {
        return $this->_userMapper->search("lname = '$lname'");
    }
   
    /**
     * find users by their email addresses
     */
    public function findByEmail($email)
    {
        return $this->_userMapper->search("email = '$email'");
    }
}

While the finders exposed by the above "UserRepository" class are pretty simplistic, they show in a nutshell the relevant role that a repository plays when you're abstracting query logic within an application. Notice that the names assigned to these methods are very explicit, which makes it easy to guess what they do. In this case, however, all the complexity required to find users by their first and last names, or even by their email addresses (although additional finders can be added in a snap) is delegated down the line -- first to the mapper (injected via the repository's constructor), and then to the persistence layer.  

At the risk of being repetitive, this illustrates an important concept that I've outlined from the very beginning: a repository retrieves collections of related domain objects as if they were actually residing in memory. Obviously, this is only an illusion to the eyes of client code, which consumes the repository's API, ignoring the complexities involved in each retrieval process.

Having the previous user repository comfortably seated between the domain and mapping layers of this sample application comes with a hidden cost: due to the heavy use of dependency injection (AKA Inversion of Control), its instantiation demands the creation, in turn, of a bunch of additional collaborators.

In general, it's considered a good programming habit to keep object instantiation isolated as much as possible from application logic. This means that the appropriate construction of the previous user repository should be delegated to a factory class, which would encapsulate the entire construction process in a way similar to what a dependency injection container does in more complicated scenarios. Given that, in the following section I'm going to define this repository factory, so you can quickly grasp how it works.

Now, just keep reading. 

Isolating object instantiation from application logic: building a repository factory

In most use cases, the implementation of a concrete factory is a fairly straightforward process that doesn't present major difficulties. And certainly, the one that I included below, whose responsibility is to create repositories, isn't the exception to this rule. Take a close look at it, please:

(RepositoryFactory.php)

<?php

class RepositoryFactory
{
    /**
     * Create a repository based on the given name
     */
    public function create($name, array $options = array())
    {
        $name = ucfirst(strtolower($name));
        $adapter    = MySQLAdapter::getInstance();
        $collection = $name . 'Collection';
        $mapper     = $name . 'Mapper';
        $repository = $name . 'Repository';
        return new $repository(
            new $mapper($adapter, new $collection, $options));
    } 
}

Mission accomplished. As you can see above, the earlier "RepositoryFactory" class only defines a single method called "create()," which accepts the name of the repository that will be returned to client code. In addition, the factory follows a simple convention; it assumes that the associated collaborators will be named according to the task that each of them perform (a mapper will be suffixed "Mapper," while a collection will be suffixed "Collection"). This basic rule permits you to create different kinds of repositories, including the one defined in the preceding section. What's more, the process would be as easy as writing the following lines:

$repositoryFactory = new RepositoryFactory;
$userRepository = $repositoryFactory->create('user');

Did you get the point as far as defining a factory that builds only repositories? I guess you did. In doing so, it's possible to keep application logic neatly separated from the instantiation of repositories (and therefore of their dependencies), since the internals of this creation process have been encapsulated behind an isolated class.

Finally, it's worth noting that the development of the previous user repository is still unfinished. It's mandatory to provide it with the ability to add and remove user entities from the underlying MySQL database. This will be done in the forthcoming part of the series. 

Final thoughts

In this sixth part of the series, things became more interesting, since I finally started using all of the sample classes defined previously to create a basic user repository class. Even the partial construction of this class required us to do some extra work, such as defining a repository factory. In general the entire development process was pretty straightforward, and showed how useful this kind of abstraction layer can be when concentrating querying code behind an intuitive API.

As I said before, however, this example repository is still incomplete, as can't add and delete user entities from the underlying persistence layer. Don't feel concerned about this issue, though, as this extended functionality will be implemented in the coming installment of the series.

Don't miss the next tutorial! 



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