Pongo: when Object Oriented PHP meets MongoDB!

I’m constantly expanding my technology knowledge and my latest discovery is MongoDB!
I really love it and I’m gonna use it for a project I’m developing with another geek. The adopted language will be PHP, since it’s agile and an ideal candidate for a 2 men project which has to be completed in a reasonable time and using best development practices such TDD (Test Driven Development) to ensure an high level product.
My PHP knowledge was related to an “hello world” level at the time of PHP 3/4, so very old… but fortunately my skills in other languages and technologies have grew up hugely in the latest years, so I get used to the latest PHP version in less than a week and I discovered that finally PHP 5.x has full support for Object Oriented Programming, which is how I’m used to approach development since a long time (in every language I used).
So, let’s get to the point… MongoDB is cool and has excellent drivers for several languages, including PHP, but it makes use of dictionaries associative arrays to save objects into the database and to retrieve them later.
This generalization is not acceptable in a software developed in OOP, we should use specific objects describing subjects in our application to persist data and depending on the language and ecosystem you are working on these ones are usually called “beans” or “VO” (Value Object) or more generically “models” (from the MVC design pattern).
To achieve this, I realized a small and simple library called “Pongo” which allows the automatic conversion from/to arrays using PHP Mongo driver… and it does this lazily, acting like a proxy attached to the original library!
Let’s see how it works… first you have to clone the repository: https://github.com/daveoncode/Pongo (I’m assuming you have already a working MongoDB installation in your machine and that the PHP driver is properly configured) and once you have the sources you can start experimenting with Pongo:

use \Daveoncode\pongo\EntityManager;

// initialize the manager
$config = new ConnectionSettings('foo');
$manager = EntityManager::getInstance();

// register entities

EntityManager is the core class of the library, it’s a singleton which needs to be initialized (init()) using a ConnectionSettings which is merely a VO containing MongoDB configurable options to connecting to the database. By default it will use the default host and port without any user or password (‘foo’ is the name of the database we want to use).
Once initialized, we can register managed entities. An entity is a subclass of Entity which is an abstract class representing persistable objects which you must extend in order to make your VO manageable by the manager.
The registration is required in order to allow the dynamic creation of entities (handled by the EntityFactory). Entities must be registered using fully qualified class name (namespace + class name).
An entity class should be marked as final, since it represents a specific business object like an User which will be stored into a specific collection and thus should not be extended by let’s say an Admin, in this scenario the approach would be to create a Role entity or a simply role field in the class in order to discriminate user types.
The following is a simple entity example:

namespace MyApp\entities;
use \Daveoncode\pongo\Entity;

final class User extends Entity
	const TYPE = 'user';
	protected $name;
	protected $email;
	public function getName()
		return $this->name;
	public function setName($name)
		$this->name = $name;
	public function getEmail()
		return $this->email;
	public function setEmail($email)
		$this->email = $email;

The entity above represents an user and as you can see, it has only 2 properties: “name” and “email” plus a constant “TYPE”. That constant MUST be named as the entity type it refers to (User) lowercased. This constants is used by the library to point to the proper collection for CRUD (Create Read Update Delete) operations. The objective is that the client code doesn’t have to care about how and where objects are stored, all it has to do is telling the EntityManager it wants to save objects, that’s all! I admit that I don’t like to force the user to manually define those constants, but retrieving that string programmatically would be expensive (dynamically retrieve the called class + manipulate the string to retrieve the short name + lowercase that value).
If you are a smart developer you are probably wondering why properties have been defined as protected if the class is final, good catch… this is due to the implementation of the abstract class SimplifiableObject from which Entity inherits its “serializability”. SimplifiableObject has a method toArray() which lazily turns an instance into an associative array using its provided getters, this means that only initialized properties (isset() === true) are stored in the array and this class does “serialize” only public or protected properties… so if you don’t want a property to be serialized mark it as private.
Save an entity is simple as:

use \MyApp\entity\User;

$user = new User();


The code above will add new entry in the “user” collection, creating that collection if it doesn’t exist (this is the native MongoDB approach). saveEntiy() use the save() method of MongoCollection which can both insert/update objects, to delete or explicitly update entities you can use deleteEntity(), deleteEntitiesByType(), updateEntity() (signatures are very similar to MongoCollection ones)
To retrieve entities:

$users = $manager->getEntitiesByType(User::TYPE);

echo 'Printing users (' . $users->count() . '): <br />';

foreach ($users as $user)
   echo 'Name: ' . $user->getName() . '<br/>';
   echo 'Email: ' . $user->getEmail() . '<br/>';

Ok… let me explain what’s going on: getEntitiesByType as you may expect does not actually return a collection of Entity instances, it would be time-consuming and memory-expensive to initialize those objects, especially if many users are retrieved simultaneously. That method instead, will return an EntityCursor object, which is a wrapper/proxy for the underling MongoCursor and thus it has the same methods (like count()) and behaviors of the original one (documented here: http://php.net/manual/en/class.mongocursor.php). The only difference is that rather than returning plain associative arrays once getNext() it’s called (it get called automatically in foreach loops) it will return Entity instances automatically configured using defined setters. Yes, you don’t have to “deserialize” your beloved object manually, Pongo will do that for you automatically, lazily and effectively!

I think I explained the few concepts and the main functionalities of the library, by now you are able to experiment and play with the source code… by the way, I’m not going to support this project officially, the API may change considerably in the future, so if you are interested in this library it’s probably better to fork it! If you have ideas, suggestions, concerns about it, let me know! ;)


I updated Pongo in order to allow entities embedding (not possible before due to a limit in the “deserialization” from mongo to PHP).
I introduced a new class: EntityDescription, which must be used to register a managed entity. This class takes 3 arguments: 1. a fully qualified class name, 2. the name of the collection used to store/retrieve this kind of entity, 3. an optional associative array containing the directives to manage sub-entities.
If you have an entity called User and that entity has a property called “settings” which is in turn another entity such UserSettings, you will specify that using an array like:

array('settings' => 'myNameSpace\entities\UserSettings')

The registration looks like this:

$manager->registerEntity(new EntityDescription('myNameSpace\entities\User', 'users', array('settings' => 'myNameSpace\entities\UserSettings')));

The line above can be translated in:

“Dear manager, please handle my entity class called: ‘myNameSpace\entities\User‘, save instances of that class in a mongodb collection called ‘users‘ and remember that ‘settings‘ is an entity in turn… so please, use ‘myNameSpace\entities\UserSetting‘ to create it, thanks.”

By specifying the collection name during registration phase, I removed the constant “TYPE” in the Entity classes, so calls like:


must be refactored to:


the manager will search entities in the collection specified before (‘users’).
This is a more flexible and cleaner approach than before.
Is it possible to embed an unlimited number of entities recursively.
Bear in mind: you must register embeddable entities as well even if they are not stored into own collection!