zf2 +主义架构.如何使用对象管理器?

shu*_*van 2 architecture doctrine-orm zend-framework2

使用Doctrine ObjectManager的最佳方法是什么?我将它注入module.config.php的控制器

'Telecom\Controller\Users' => function($sm){
    $ctr = new Telecom\Controller\UsersController();
    $ctr->setEntityManager(
               $sm->getServiceLocator()
                    ->get('Doctrine\ORM\EntityManager')
           );

    return $ctr;
},
Run Code Online (Sandbox Code Playgroud)

然后我在我的控制器中使用它如下

$this->getEntityManager()->persist($entity);
$this->getEntityManager()->flush();
Run Code Online (Sandbox Code Playgroud)

但是Marco Pivetta(Doctrine团队,zf2撰稿人)教导"如果你在控制器中注入objectmanager,你将会有一个糟糕的架构" http://marco-pivetta.com/doctrine-orm-zf2-tutorial/#/39/11.

所以请帮助我,使用Entity Manager的最佳架构方式是什么.我应该使用像我自己的服务这样的另一层来处理实体经理吗?

Ale*_*exP 5

如果控制器中有实体管理器,则引入"域逻辑"(数据库查询)的耦合,它们与应用程序逻辑不可分离(控制器应该只读取请求并返回正确的响应).这种耦合使得重用和维护代码变得相当困难.

一种解决方案是创建注入控制器的"服务".服务封装业务逻辑(例如数据库查询)并为控制器提供定义良好的API.好的一面是,业务逻辑应该随时改变(它总是会改变); 您只需要更改所述服务的实现,控制器将继续运行.

ZF2非常灵活,有很多方法可以完成相同的任务.我个人做了以下事情:

服务

服务并不意味着只封装一个实体; 它们应该封装执行该特定任务所需的所有实体.这完全取决于服务尝试做什么.例如,更复杂的服务可能需要其他服务.

在我的实现中,我有一个抽象类,AbstractEntityService这个类被扩展用于所有需要持久性的服务(需要数据库的任何东西).

这里的课程很长,但是关键位是下面的.

abstract class AbstractEntityService 
  extends Service\AbstractService 
  implements EntityMapperAwareInterface, FormProviderInterface
{ 

public function __construct(
  EntityMapper $entityMapper, 
  FormElementManager $formElementManager)
{
    $this->entityMapper = $entityMapper;
    $this->formElementManager = $formElementManager;

    $this->getEventManager()->addIdentifiers(array(__CLASS__));

    parent::__construct();
}

public function getForm($name)
{
   return $this->formElementManager->get($name);
}

public function create(Entity\EntityInterface $entity)
{
    $this->triggerEvent(static::EVENT_CREATE, array('entity' => $entity));

    $entity = $this->entityMapper->insert($entity);

    $this->triggerEvent(static::EVENT_CREATE_POST, array('entity' => $entity));

    return $entity;
}
Run Code Online (Sandbox Code Playgroud)

注意EntityMapperFormElementManager注入 - 否ObjectManagerServiceLocator此处.

EntityMapper

只是对象管理器周围的薄层; 这使我们能够换出EntityManagerDocumentManager,如果我们从做MySQLMongoDB的例子.

interface MapperInterface
{
   public function getObjectManager();

   public function setObjectManager(ObjectManager $objectManager);

   public function getRepository($className);

   public function insert(EntityInterface $entity);

   public function save(EntityInterface $entity);

   public function delete(EntityInterface $entity);

   public function flush();

 }
Run Code Online (Sandbox Code Playgroud)

所以具体服务的一个例子是:

class ListService extends AbstractEntityService
{
    public function __construct(
      EntityMapper $entityMapper,
      FormElementManager $formElementManager,
      ListRepository $listRepository
    ){
      parent::__construct($entityMapper, $formElementManager);
      $this->listRepository = $listRepository;
  }

  protected function init(EventManagerInterface $eventManager){
    parent::init($eventManager);
    $eventManager->attach(static::EVENT_CREATE, array($this, 'createList'));
  }

  public function createList(EventInterface $event)
  {
    $list = $event->getParam('entity');

    if (! $list instanceof Entity\ValueList) return;
    $name =  $list->getName();
    if (empty($name)) {
        $name = $this->formatName($list->getTitle());
        $list->setName($name);
    }
   }
Run Code Online (Sandbox Code Playgroud)

ListController

然后控制器只使用该服务(在上面的例子中它是一个"ListService")

class ListController extends AbstractActionController {

public function __construct(
    ListService $listService
){
    $this->listService = $listService;
}

public function createAction(){
   // validate request/form data...
   $form = $this->listService->getListCreateForm();

   $list = $this->listService->create($form->getData());

   // return view...
}
Run Code Online (Sandbox Code Playgroud)

哇; 有点长于计划,但希望它有所帮助.