Где я могу разместить свой длинный код, который готовит объекты домена к сохранению в репозитории?

У меня есть код, например, так:

/* Part of Controller::saveAction() */

//create new object instance
$item = new Item();

//populate the Item
$item->setDescription($description);
$item->setQuantity($quantity);
$item->setPrice($price);

//once we have a fully populated object,
//send it to Repository pattern,
//which saves it to persistent storage
$this->repository->saveItem($item);

Представьте себе несколько блоков, как указано выше, в одном методе / методе, и вы увидите мою проблему … Я очень доволен своим repository строка кода, но я не знаю, где разместить всю «подготовительную работу», которая выполняется до вызова Repository,

Вопрос:

Где я могу разместить большую часть кода, который создает &заселяет Item экземпляр объекта? Это загромождает мой метод Контроллера, и я не могу представить себе другое место для его установки.

Цель

Моя цель — найти хорошую структуру / дизайн, а не просто уменьшить или свести к минимуму количество строк «подготовки предмета».

В зависимости от контроллера у меня примерно 5-7 Item экземпляры, каждый из которых имеет 10-16 строк кода, создающих и заполняющих экземпляры.

0

Решение

наблюдение

Индивидуальные ценности, такие как $description, $quantity, $price должен прийти откуда-то. Это может быть GET, POST, SESSION, COOKIES, база данных или внешние методы. Давайте назовем это $_SOMEWHERE для ясности. Затем мы получаем:

$description = $_SOMEWHERE['description'];
$quantity = $_SOMEWHERE['quantity'];
$price = $_SOMEWHERE['price'];

Определить вход&Подготовительный класс, который делает работу за вас и возвращает подготовленный Item,

class AcquireItem
{
function getItem()
{
$item = new Item();

$item->setDescription($_SOMEWHERE['description']);
$item->setQuantity($_SOMEWHERE['quantity']);
$item->setPrice($_SOMEWHERE['price']);

return $item;
}
}

контроллер

$item = (new AcquireItem())->getItem();
$this->repository->saveItem($item);

Контроллер становится короче, эффективно «запихивая» громоздкий код беспорядка в класс, который занимается чтением и подготовкой ввода, а также очисткой контроллера. Код должен где-то существовать, но может быть и вне поля зрения, и в другом месте.

Для разных типов ItemВы можете варьировать метод, т.е. getItemA(), getItemB(),

0

Другие решения

Как вы упомянули о правильном способе достижения
так .. как насчет использования делегаторов и разбиения контроллера (блоков) на делегаторы? По терминологии это будет Фасад [Адаптер]

добавьте следующее в ./module/MyModule/config/module.config.php:

'controllers' => array(
'invokables' => array(
'MyModule\CreateController' => 'MyModule\Controller\MyController',
'MyModule\ReadController' => 'MyModule\Controller\MyController',
),
'delegators' => array(
'MyModule\CreateController' => array(
'MyModule\Controller\Delegator\CreateItemDelegatorFactory'
),
'MyModule\ReadController' => array(
'MyModule\Controller\Delegator\ReadItemDelegatorFactory'
),
),
),
'form_elements' => array(
'invokables' => array(
'item_create' => 'MyModule\Form\CreateForm',
),
),

Create Delegator загружает форму, заполняет ее, проверяет и пытается сохранить данные

./module/MyModule/src/MyModule/Controller/Delegator/CreateItemDelegatorFactory.php:

namespace MyModule\Controller\Delegator;

use Zend\ServiceManager\DelegatorFactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use MyModule\Entity\Item as Entity;

/**
*  Class loads the form, checks if form been posted and if is valid.
*  If form is valid it tries to save the item with repository service
*  Class sets the Form per controller, such solution keeps form
*  validation messages
*/
class CreateItemDelegatorFactory implements DelegatorFactoryInterface
{
/**
* Determines name of the form to be loaded with formElementManager
*
* @var string
*/
private $form_name = "item_create";

/**
* Name of repository service. It may be database, api or other
*
* @var string
*/
private $service_repository_name = "service.repository";

public function createDelegatorWithName(
ServiceLocatorInterface $serviceLocator,
$name,
$requestedName,
$callback
) {
// assign serviceManager locally
$parentLocator = $serviceLocator->getServiceLocator();
// assign services locally
$routerService = $parentLocator->get('router');
$requestService = $parentLocator->get('request');
// get repository service
$repositoryService = $parentLocator->get($this->service_repository_name);

// read the CreateForm with formElementManager and bind the Entity
$callback->setForm(
$parentLocator->get('FormElementManager')->get($this->form_name)
);
$entity = new Entity;
$callback->getForm($this->form_name)->bind($entity);

// check if data been posted
if($requestService->isPost()) {
$postData = $requestService->getPost($this->form_name);
$callback->getForm($this->form_name)->setData($postData);
// validate form
if($callback->getForm($this->form_name)->isValid()) {
// form is valid
$repositoryService->saveItem($entity);
}
}
}
}

При использовании вышеупомянутого делегатора вашему контроллеру (MyModule \ Controller \ MyController) потребуется дополнительное свойство и два метода:

/**
* Holds the form object
* @var object
*/
private $form

public function setForm($form=null)
{
$this->form = $form;
return $this;
}

public function getForm()
{
return $this->form;
}

./module/MyModule/src/MyModule/Controller/Delegator/ReadItemDelegatorFactory.php:

namespace MyModule\Controller\Delegator;

use Zend\ServiceManager\DelegatorFactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use MyModule\Entity\Item as Entity;

/**
* Creates Delegator which tries read item's id from the (segment type) route
* and read the Item from the repository service
*
*/
class ReadItemDelegatorFactory implements DelegatorFactoryInterface
{
/**
* Item's ID from route
*
* @var string
*/
private $route_identifier = "item_id";

/**
* Name of repository service. It may be database, api or other
*
* @var string
*/
private $service_repository_name = "service.repository";

public function createDelegatorWithName(
ServiceLocatorInterface $serviceLocator,
$name,
$requestedName,
$callback
) {
// assign serviceManager locally
$parentLocator = $serviceLocator->getServiceLocator();
// assign services locally
$routerService = $parentLocator->get('router');
$requestService = $parentLocator->get('request');
// get repository service
$repositoryService = $parentLocator->get($this->service_repository_name);
// get the router match and the item_id
$routerMatch = $routerService->match($requestService);
$itemId = $routerMatch->getParam($this->route_identifier);
// set the data for the target controller
$callback->setItem($repositoryService->readItem($itemId));

return $callback;
}

При использовании вышеупомянутого делегатора вашему контроллеру (MyModule \ Controller \ MyController) потребуются дополнительные свойство и метод:

/**
* Holds the Item object
* @var object \MyModule\Entity\Item
*/
private $item

public function setItem($item=null)
{
$this->item = $item;
return $this;
}

Такой способ использования контроллера помогает коду оставаться СУХИМЫМ и кажется возможным управлять потоком. Делегаторы загружаются как LIFO, поэтому можно предварительно сконфигурировать контроллер ($ callback) перед передачей его другому делегатору.

Если ReadController читает элемент, а CreateController загружает форму, это короткий путь для UpdateItemDelegator для обработки задачи обновления элемента.

'controllers' => array(
'invokables' => array(
'MyModule\UpdateController' => 'MyModule\Controller\MyController',
'delegators' => array(
'MyModule\ReadController' => array(
'MyModule\Controller\Delegator\UpdateItemDelegatorFactory',
'MyModule\Controller\Delegator\CreateItemDelegatorFactory',
'MyModule\Controller\Delegator\ReadItemDelegatorFactory'
),
),
),

Делегаты объяснили:
http://ocramius.github.io/blog/zend-framework-2-delegator-factories-explained/

Редактировать:

Контроллер, подготовленный для обоих делегатов (Create и Read), будет выглядеть так:

namespace MyModule\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;

class CreateController extends AbstractActionController
{
/**
* Holds the Item object
* @var object \MyModule\Entity\Item
*/
private $item

/**
* Holds the form object
* @var mixed null|object
*/
private $form;

/**
* Item's details. It reads item by the `item_id` which is param set in route with same name
* @return \Zend\View\Model\ViewModel
*/
public function readAction()
{
$v = new ViewModel();
// set item, access it in template as `$this->item`
$v->setVariable('item',$this->getItem());

return $v;
}

/**
* The Form preconfigured with CreateItemDelegatorFactory should be av. in template as `$this->form`
* @return \Zend\View\Model\ViewModel
*/
public function createAction()
{
$v = new ViewModel();
// set form, access the in template as `$this->form`
$v->setVariable('form',$this->getForm());

return $v;
}

/**
* Sets the Item object
* @var $item \MyModule\Entity\Item
* @return $this
*/
public function setItem($item=null)
{
$this->item = $item;
return $this;
}

/**
* Gets the Item object
* @return object \MyModule\Entity\Item
*/
public function getItem()
{
return $this->item;
}

public function setForm($form=null)
{
$this->form = $form;
return $this;
}

/**
* Returns form defined in config and CreateItemDelegatorFactory::form_name
* @return \Zend\Form\Form
*/
public function getForm()
{
return $this->form;
}
}
0

Я лично считаю, что create-методы должны идти в хранилище.
Это потому, что я ожидал бы, что репозитории будут содержать все методы CRUD (создание, чтение, обновление, удаление).

Это просто моя личная мысль на эту тему …

0
По вопросам рекламы [email protected]