2013-06-24 1 views
3

Я разрабатываю приложение RESTful ZF2 и использую реализацию TableGateway (подкласс Zend\Db\TableGateway) в сочетании с простым картографом для модели, аналогичным Album example of the ZF2 manual.Как обрабатывать многомерный вывод с (вложенными) списками с помощью Zend Db TableGateway с помощью mapper в Zend Framework 2?

класс Таблица

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

<?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); 
    } 

} 

Контроллер

<?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; 
    } 

    ... 

} 

Это работает для ш позволяют вывод так:

{ 
    "data":{ 
     "id":"123", 
     "title":"test title", 
     "details":"test details" 
    } 
} 

Но теперь мне нужно многомерный выход с вложенными списками, как это:

{ 
    "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" 
          } 
         ] 
        ] 
       } 
      ] 
     } 
    } 
} 

Как/где я должен собрать данные в этой структуре? Непосредственно в преобразователе, чтобы он содержал все данные? Или я должен обрабатывать это с помощью нескольких запросов базы данных anb, чтобы создать структуру в контроллере?

ответ

3

То, что вы пытаетесь выполнить, не имеет ничего общего с TableGateway -Pattern. Шаблон TableGateway-Pattern предназначен для доступа к данным одной указанной таблицы. Это одна из причин, почему в ZF2 у вас больше нет опции findDependantRowsets(). Это просто не TableGateways Job.

Чтобы добиться того, что вы ищете у вас есть довольно много два варианта:

1. Регистрация Запрос

Вы могли бы написать большой запрос, который объединяет все соответствующие таблицы, а затем вы бы вручную сопоставить выход в ваш желаемый формат JSON.

2. Несколько запросов

Чуть менее производительный подход (если смотреть на SQL стороне вещей), но «легче» на «карте» в вашем JSON формате.

Чтобы дать некоторое представление, доктрина будет идти по принципу множественного запроса по умолчанию. Это главным образом (я предполагаю!) Сделано для обеспечения функций, которые будут работать по данным каждого бакэнду возможно, а не просто несколько версий SQL ...

Класс обслуживания

Поскольку вы задаетесь вопросом о сборке json/array, я бы установил его так:

'service_manager' => array(
    'factories' => array(
     'MyEntityService' => 'Mynamespace\Service\Factory\MyEntityServiceFactory' 
    ) 
) 

// MyEntityServiceFactory.php 
// assuming you only need one dependency! more lines for more dependencies ;) 
class MyEntityServiceFactory implements FactoryInterface { 
    public function createService(ServiceLocatorInterface $serviceLocator) { 
     return new MyEntityService($serviceLocator->get('YourTableGateway')); 
    } 
} 

// Your SERVICE Class 
class MyEntityService { 
    // do constructor and stuff to handle dependency 

    public function someBigQueryAsArray() { 
     // Query your Gateway here and create the ARRAY that you want to return, 
     // basically this array should match your json output, but have it as array 
     // to be used for other stuff, too 
    } 
} 

// lastly your controller 
public function someAction() { 
    $service = $this->getServiceLocator()->get('MyEntityService'); 
    $data = $service->someBigQueryAsArray(); 

    // do that viewmodel selector stuff 

    // ASSUMING $data is a array of more than one baseObject 
    // i did this in my app to produce the desired valid json output, there may be better ways... 
    if ($viewModel instanceof JsonModel) { 
     foreach($data as $key => $value) { 
      $viewModel->setVariable($key, \Zend\Json\Json::encode($value)); 
     } 
     return $viewModel; 
    } 

    // Handle other ViewModels .... 
} 
+0

Спасибо, что ответите, Сэм! Я думаю, возможно, мой вопрос не совсем достаточно. 1. В шаблон TableGateway: я написал, что я использую его здесь, чтобы описать контекст: модель, состоящая из реализации TableGateway (подкласс «Zend \ Db \ TableGateway») + mapper. 2. К вашим двум решениям: Да, на самом деле есть два способа получить данные.Но я хочу понять, как/где (в каком классе) собирать * данные (уже взятые с одним жирным или несколькими меньшими запросами) в эту структуру сложной структуры с вложенными списками. – automatix

+0

@automatix Либо Service-Class, либо ваш контроллер. Я бы сказал, что путь к тому, чтобы Служба вернула соответствующий массив, который вам понадобится (вложенная версия, как вы классифицировали выше), и ваш контроллер будет обрабатывать массив в зависимости от потребностей запроса. – Sam

+0

Сборка в контроллере сделает контроллер довольно толстым. Но что вы имеете в виду с «Service-Class»? Специальный класс «сборщик»/«объединитель»? Если да: этот класс должен общаться с классом Table, правильно? Таким образом, код, который в настоящее время выполняется в контроллере ('$ this-> getCourseTable() -> findOnceByID ($ id) -> current();') и некоторые более похожие аналогичные вызовы для получения данных для подсписок - этот код переместится в этот класс ассемблера. Контроллер просто выполнит что-то вроде '$ courseAssembler-> getCourse()'? Спрашивая, чтобы быть уверенным, что я понял, что вы соответствуете. – automatix