Zend Framework 2 : Using HydratingResultSet and ObjectProperty’s Hydrator
When joining table using Zend\Db, calling coloumn(s) in other table when make a join is a pain. It because if we use normal Zend\Db\ResultSet\ResultSet and setting up ArrayObjectPrototype with the class object, we only get the current model class only ( that consist of columns of single table). Register other table column on that class is NOT a solution, it will make a confusion on what entity is for. Maybe not best (errr…good) solution but simplest solution is to use Zend\Db\ResultSet\HydratingResultSet and Zend\Stdlib\Hydrator\ObjectProperty.
There is I explain on case situation : “we have a table named album ( with columns : `id`, `artist`, `title` ) and table named track ( with columns : `track_id`, `track_title`, and `album_id` as foreign key agains album )”.
Ok, let’s create model like as the docs :
//filename : module/Album/src/Album/Model/Album.php
namespace Album\Model;
class Album
{
public $id;
public $artist;
public $title;
public function exchangeArray($data)
{
$this->id = (isset($data['id'])) ? $data['id'] : null;
$this->artist = (isset($data['artist'])) ? $data['artist'] : null;
$this->title = (isset($data['title'])) ? $data['title'] : null;
}
public function getArrayCopy()
{
return get_object_vars($this);
}
}
Ok, Let’s create a sample table class for album table :
//filename : module/Album/src/Album/Model/AlbumTable.php
namespace Album\Model;
use Zend\Db\TableGateway\TableGateway;
class AlbumTable
{
protected $tableGateway;
public function __construct(TableGateway $tableGateway)
{
$this->tableGateway = $tableGateway;
}
//to retrieve tableGateway object when needed.
public function getTableGateway()
{
return $this->tableGateway;
}
public function JoinfetchAll()
{
$sqlSelect = $this->tableGateway->getSql()
->select()
->join('track', 'track.album_id = album.id', array('*'), 'left');
return $this->tableGateway->selectWith($sqlSelect);
}
}
If you want to reduce closure usage at your application, you can create factory for AlbumTable creation like the following :
//filename : module/Album/src/Album/Factory/Model/AlbumTableFactory.php
namespace Album\Factory\Model;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\Db\TableGateway\TableGateway;
use Album\Model\AlbumTable;
use Album\Model\Album;
use Zend\Stdlib\Hydrator\ObjectProperty;
use Zend\Db\ResultSet\HydratingResultSet;
class AlbumTableFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$db = $serviceLocator->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new HydratingResultSet();
$resultSetPrototype->setHydrator(new ObjectProperty());
$resultSetPrototype->setObjectPrototype(new Album());
$tableGateway = new TableGateway('album', $db, null, $resultSetPrototype);
$table = new AlbumTable($tableGateway);
return $table;
}
}
and we just make a call like this :
//filename : module/Album/Module.php
namespace Album;
class Module
{
// getAutoloaderConfig() and getConfig() methods here
// Add this method:
public function getServiceConfig()
{
return array(
'factories' => array(
'Album\Model\AlbumTable' => 'Album\Factory\Model\AlbumTableFactory'
),
);
}
}
That’s it, we now can call like this :
$table = $this->getServiceLocator()->get('Album\Model\AlbumTable');
$joinedData = $table->JoinfetchAll();
foreach($joinedData as $row) {
//$row->track_id will called even not registered
//in album model class.
echo $row->artist.' : '.$row->track_id;
}
We know that we need to retrieve track table column form *JoinfetchAll()* table. but we don’t need to register it to be retrieve-able.
Ok, done, happy hacking 😉
15 comments