Architecture zf2和x2B;理论架构。如何使用对象管理器?
使用Doctrine ObjectManager的最佳方式是什么?我将其注入module.config.php的控制器中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()
'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...
}