sras/entity-builder

A library to convert database query results to entities.

dev-default 2014-03-22 14:35 UTC

This package is not auto-updated.

Last update: 2020-08-17 10:15:30 UTC


README

Create fully hydrated aggregate entities from query results.

This is a library to build aggregate root objects from the result of a simple or join query.

Installation via composer

{
    "require":{"sras/entity-builder": "dev-default"}
}

Please see the sections below for actual usage.

How it works.

It works by accepting a set of rules, that define the structure of the result. It uses these rules to populate entity objects and wire them up. The rules define,

  1. A prefix for columns to identify the columns belonging to an entity.
  2. An alias for an instance of the entity.
  3. Methods in entities that are used to wire them up.
  4. Primary keys for entities by which rows belonging to a particular entity can be identified.
  5. The entity to return to the caller.

It scans each row and separates data for each entity using prefixes. It then transforms the columns name to setter method names by perpending 'set' after removing underscores and camel casing the rest. It then assignees the entities to elements of an array with aliases as key, and uses rules and methodes specified in then to wire them up. When all rows belonging to an entity is completed, it yields the fully populated entity to the calling code.

For eg. Suppose we have the result of a query in an array as shown below.

<?php
$result = array(
                array('u_id'=>1, 'u_name'=>'sandeep','u_country_id'=>33,'p_pid'=>23,'p_title'=>'post_1','c_id'=>33,'c_name'=>'india'),
                array('u_id'=>1, 'u_name'=>'sandeep','u_country_id'=>33,'p_pid'=>34,'p_title'=>'post_2','c_id'=>33,'c_name'=>'india'),
                array('u_id'=>1, 'u_name'=>'sandeep','u_country_id'=>33,'p_pid'=>4,'p_title'=>'post_5','c_id'=>33,'c_name'=>'india'),
                array('u_id'=>2, 'u_name'=>'max','u_country_id'=>34,'p_pid'=>6,'p_title'=>'post_6','c_id'=>34,'c_name'=>'japan'),
                array('u_id'=>2, 'u_name'=>'max','u_country_id'=>34,'p_pid'=>6,'p_title'=>'post_6','c_id'=>34,'c_name'=>'japan'),
                );

This result contains the rows from three tables, user, post and country. Our goal is to convert this array into two User objects with its posts and country properties populated with 'Post' and 'Country' entities. We use the following rules to initialize the Builder object.

<?php
$rules = array(    'columns for \Test\User u1  prefixed by u_',
                    'columns for \Test\Post p1 prefixed by p_',
                    'columns for \Test\Country c1 prefixed by c_',
                    'add p1 to u1 using addPost',
                    'add u1 to p1 using setUser',
                    'add c1 to u1 using setCountry',
                    'primary key for \Test\User is id',
                    'primary key for \Test\Post is pid',
                    'return u1',
                    );

and you can get the two User entities in an array using the following code.

<?php
$eb = \sras\EntityBuilder::getInstance($rules);  // initialize the builder with the rules
$eb->setResult($result); // sets the result to be interpreted. It can be an array or any iterable object, like a pdo statement.
$entities = $eb->getAll(); // Convert all the data in the result set into entities, based on the rules.

echo count($entities); //outputs 2
echo $entities[0]->getCountry()->getName(); // outputs 'india'

Iterating over the result

Instead of converting whole result set into entities, you can get an Iterator by calling getIterator(), instead of getAll(). The iterator will yield (uses a generator) a fully populated entity when ever it finishes building one. If you have a big result in a PDO statement, you can get nicely populated entities, one by one, from it. This wont require as much memory, as all the entities in the result are not built at once. Instead, when it finish processing the rows that belong to a single entity, it yields it and waits for the next iteration to build the next one.

<?php
$eb = \sras\EntityBuilder::getInstance($rules);  // initialize the builder with the rules
$eb->setResult($result); // sets the result to be interpreted. It can be an array or any iterable object, like a pdo statement.

// Get User entities as they are built by the builder
foreach($eb->getIterator() as $user) { 
    echo $user->getCountry()->getName(); // prints 'india', 'japan' in two iterations
}

Identity Map.

The builder maintains an identity map that is shared between all the builders for all the entities returned from it. This means you get the same instance of the object even if it is from different parts of the result. This means if you have a User entity with id 10 returned by the builder and you change its properties. It will keep returning the same instance of User in the future calls when it encounters a User with id of 10. Please see the below code sections.

<?php
$eb = \sras\EntityBuilder::getInstance($rules);  // initialize the builder with the rules
$eb->setResult($result); // sets the result to be interpreted. It can be an array or any iterable object, like a pdo statement.
$entities = $eb->getAll(); // Convert all the data in the result set into entities, based on the rules.

echo $entities[0]->getCountry()->getName(); // outputs 'india'
$entities[0]->getCountry()->setName('INDIA');

//Build the entities from result again
$entities = $eb->getAll(); // Convert all the data in the result again
echo $entities[0]->getCountry()->getName(); // outputs 'INDIA', instead of 'india'.