Architecture zf2和x2B;理论架构。如何使用对象管理器?

Architecture zf2和x2B;理论架构。如何使用对象管理器?,architecture,doctrine-orm,zend-framework2,Architecture,Doctrine Orm,Zend Framework2,使用Doctrine ObjectManager的最佳方式是什么?我将其注入module.config.php的控制器中 'Telecom\Controller\Users' => function($sm){ $ctr = new Telecom\Controller\UsersController(); $ctr->setEntityManager( $sm->getServiceLocator()

使用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;
},
然后我在控制器中使用它,如下所示

$this->getEntityManager()->persist($entity);
$this->getEntityManager()->flush();
但Marco Pivetta(条令团队,zf2贡献者)教导“如果在控制器中注入objectmanager,那么您的体系结构将很糟糕”


请帮助我,使用实体管理器的最佳架构方式是什么。我是否应该使用另一个层(如我自己的服务)来处理entity manager?

您可以对每个模块执行以下操作:

| | - App
| | | - Controller
| | | | -IndexController.php
| | | - Entity
| | | | - User.php
| | | - Factory
| | | - Service
| | | | - UserService.php
在这种体系结构中,您必须在服务的类中插入实体管理器,以便您的服务必须实现ServiceManagerWareInterface

use Zend\ServiceManager\ServiceManagerAwareInterface;

class UsersService implements ServiceManagerAwareInterface {

    protected $sm;
/**
 * Retrouver l'entityManager voulue
 * @var [Object EntityManager]
 */
protected $em;

public function setServiceManager(ServiceManager $serviceManager)
{
    $this->sm = $serviceManager;
    return $this;
}

/*
 * Retrieve service manager instance
 *
 * @return ServiceManager
 */
public function getServiceManager()
{
    return $this->sm;
}

// do your crazy stuff here
...
}
在本例中,像User这样的实体有一个UserService。 用户是原则的映射类

您的体系结构从低级到高级如下所示: 模型(实体) 编辑:

'invokables' => array(
        'UsersService' => 'Application\Service\UsersService',
    ),
您可以在module.config.php中插入每个服务。 如果你有任何问题,我听你说。
(对不起,我的英语)我希望我清楚地知道,如果控制器中有实体管理器,则会引入“域逻辑”(数据库查询)的耦合,它们与应用程序逻辑不可分离(控制器只应读取请求并返回正确的响应)。这种耦合使得重用和维护代码变得相当困难

一种解决方案是创建注入控制器的“服务”。服务封装业务逻辑(如数据库查询),并为控制器提供定义良好的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;
}
请注意,
EntityMapper
FormElementManager
被注入-此处没有
ObjectManager
ServiceLocator

EntityMapper

只是对象管理器周围的一个薄层;例如,如果我们从
MySQL
MongoDB
,这允许我们将
EntityManager
替换为
DocumentManager

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();

 }
因此,具体服务的一个例子是:

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

然后,控制器只使用服务(在上面的示例中,它是一个“ListService”)


哇,;比计划的时间长一点,但希望能有所帮助。

所以,每个实体都应该有自己的服务,通过module.config.php中的注入来获取entitymanager,对吗?但是,还有另一个程序层的原因是什么?为什么EntityManager还不够?如果需要的话,要改变ORM层吗?原因是:尊重MVC,控制器不是为与DAO和服务层交互而设计的,另外,在zf3中,几乎计划在控制器中删除对SM的访问。这是一个糟糕的做法,对于简化教程,每个演示都是在控制器中完成的,这不是我们必须做的。EntityManager不足,服务管理器在服务层中获取EntityManager。仅此而已。此链接帮助我理解了所有这些内容:我建议您阅读它,它真的很好谢谢,我完全忘记了,厚控制器=糟糕的架构另一个答案中的AbstractService和您的ServiceManagerWareInterface之间有什么区别?我对很多服务类有点困惑。谢谢,让我想一想。上面的文字很清楚,但代码不是。为什么使用事件?有很多事件的代码很难理解。它们对架构有什么好处?为什么要通过uu构造而不是setter进行注入?@shukshin.ivan
AbstractEntityService
中的事件允许任何扩展服务类重用
create
方法;无需修改/重载它。如果我想为任何实体服务(比如列表服务)做一些特定的事情,我可以在
init()
方法中附加一个事件,就像我为
createList(EventInterface$event)
所做的那样。我将其注入构造函数()中,因为该类具有硬依赖项而不是软依赖项(此时应该使用setter)。你有一个更详细的例子,这段代码在网上的某个地方?很好的答案!我有一个疑问,我应该为每个模块的控制器创建一个服务,还是应该在所有控制器中使用一个服务?
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...
}