我有这样的代码:
/* 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对象实例的代码?它把我的控制器方法弄得乱七八糟,我似乎无法想象有别的地方可以把它放进去。
目标
我的目标是找到好的结构/设计,而不是单纯地减少或减少“项目准备”行的数量。
根据Controller,我有大约5-7个Item实例,每个实例有10-16行代码创建和填充实例。
发布于 2016-05-18 02:54:20
正如你所提到的,实现这一目标的正确途径。如何使用委托者并将控制器(块)分割成委托者?它的术语术语它将是外观适配器
在./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',
),
),创建代理程序加载表单,填充它,验证并尝试保存teh数据
./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处理item Update任务的方式很短。
'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/
编辑:
为两个委派者(创建和读取)准备的控制器如下所示:
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;
}
}发布于 2016-05-18 15:26:06
观测
像$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()。
发布于 2016-07-08 04:37:10
我个人认为创建方法应该进入存储库。这是因为我希望存储库包含所有CRUD (创建、读取、更新、删除)方法。
这只是我对这个话题的个人想法..。
https://stackoverflow.com/questions/37286497
复制相似问题