I'm developing a RESTful ZF2 based application and using a TableGateway implementation (subclass of the Zend\Db\TableGateway
) in combination with a simple mapper for the model, similar to the Album example of the ZF2 manual.
Table class
<?php
namespace Courses\Model;
use ...
class CourseTable {
protected $tableGateway;
public function __construct(TableGateway $tableGateway) {
$this->tableGateway = $tableGateway;
}
public function findOnceByID($id) {
$select = new Select();
$where = new Where();
$select->columns(array(
'id',
'title',
'details',
));
$select->from($this->tableGateway->getTable());
$select->where($where, Predicate::OP_AND);
$resultSet = $this->tableGateway->selectWith($select);
return $resultSet;
}
}
Mapper class
<?php
namespace Courses\Model;
use ...
class CourseDetails implements ArraySerializableInterface {
public $id;
public $title;
public $details;
public function exchangeArray(array $data) {
$this->id = (isset($data['id'])) ? $data['id'] : null;
$this->title = (isset($data['title'])) ? $data['title'] : null;
$this->details = (isset($data['details'])) ? $data['details'] : null;
}
public function getArrayCopy() {
return get_object_vars($this);
}
}
Controller
<?php
namespace Courses\Controller;
use ...
class CoursesController extends RestfulController // extends AbstractRestfulController
{
protected $acceptCriteria = array(
'Zend\View\Model\JsonModel' => array(
'application/json',
),
'Zend\View\Model\FeedModel' => array(
'application/rss+xml',
),
);
private $courseTable;
public function get($id)
{
$course = $this->getCourseTable()->findOnceByID($id)->current();
$viewModel = $this->acceptableViewModelSelector($this->acceptCriteria);
$viewModel->setVariables(array('data' => array(
'id' => $courseDetails->id,
'title' => $courseDetails->title,
'details' => $courseDetails->details
)));
return $viewModel;
}
...
}
It's working for a shallow output like this:
{
"data":{
"id":"123",
"title":"test title",
"details":"test details"
}
}
But now I need a multidimensional output with nested lists like this:
{
"data":{
"id":"123",
"title":"test title",
"details":"test details",
"events":{
"count":"3",
"events_list":[ <- main list
{
"id":"987",
"date":"2013-07-20",
"place":"Berlin",
"trainers":{
"count":"1",
"trainers_teamid":"14",
"trainers_teamname":"Trainers Team Foo",
"trainers_list":[ <- nested list
{
"id":"135",
"name":"Tom"
}
]
}
},
{
"id":"876",
"date":"2013-07-21",
"place":"New York",
"trainers":{
"count":"3",
"trainers_teamid":"25",
"trainers_teamname":"Trainers Team Bar",
"trainers_list":[ <- nested list
{
"id":"357",
"name":"Susan"
},
{
"id":"468",
"name":"Brian"
},
{
"id":"579",
"name":"Barbara"
}
]
}
},
{
"id":"756",
"date":"2013-07-29",
"place":"Madrid",
"trainers":{
"count":"1",
"trainers_teamid":"36",
"trainers_teamname":"Trainers Team Baz",
"trainers_list":[ <- nested list
{
"id":"135",
"name":"Sandra"
}
]
]
}
]
}
}
}
How / where should I assemble the data to this structure? Directly in the mapper, so that it contains the whole data? Or should I handle this with multiple database requests anb assemple the structure in the controller?
What you are trying to accomplish has nothing to do with the
TableGateway
-Pattern. The TableGateway-Pattern is there to gain access to the Data of one specified Table. This is one of the reasons why in ZF2 you no longer have the option tofindDependantRowsets()
. It's simply not the TableGateways Job to do so.To achieve what you are looking for you have pretty much two options:
1. Joined Query
You could write a big query that joins all respective tables and then you'd manually map the output into your desired JSON Format.
2. Multiple Queries
A little less performant approach (looking at the SQL side of things) but "easier" to "map" into your JSON Format.
To give some insight, Doctrine would go with the multiple query approach by default. This is mostly (i guess!) done to provide features that would work on every data backend possible rather than just a couple of SQL Versions...
Service Class
Since you're wondering about the assembling of the json / array, i would set it up like this