PHP - 工作单元应该位于 MVC 应用程序的什么位置?
PHP - Where should Unit Of Work lie in an MVC application?
问题的背景信息
在我的 index.php 文件中我有这个:
$service_factory = new ServiceFactory(new MapperFactory($db), new DomainFactory);
我对 UnitOfWork 应如何与我的应用程序一起工作的理解是这样的(状态是指脏、干净等):
- Mapper - 标记一个对象的状态
$user->markNew();
或 $uow->registerNew($user);
- 域 - 可以检查它的当前状态。例如:
$this->isDirty();
- 服务 - 调用
commit()
来完成交易
$this->uow->commit()
或 $mapper->commit()
我的 UnitOfWork 的提交函数是这样的(欢迎改进):
public function commit()
{
// Inserts the new objects
foreach ($this->newObjects as $newObject) {
$mapper = $this->mapperFactory->createFromDomainObject($newObject);
$mapper->insert($newObject);
}
// Update the dirty objects
foreach ($this->dirtyObjects as $updateObject) {
$mapper = $this->mapperFactory->createFromDomainObject($updateObject);
$mapper->update($updateObject);
}
// Delete the removed
foreach ($this->deletedObjects as $deletedObject) {
$mapper = $this->mapperFactory->createFromDomainObject($deletedObject);
$mapper->delete($deletedObject);
}
}
选项 #1 - ServiceFactory
Pro:如果我有一个服务调用另一个,我将不必担心彼此之间不会传递域对象,因为它们将共享相同的实例工作单位。
Con:我必须将 UnitOfWork 对象一直向下传递到映射器对象,这将有很多级别:ServiceFactory -> Service -> MapperFactory ->映射器... Ew。这对我来说不太合适。
此外,由于 UnitOfWork 需要一个 MapperFactory,我的 index.php 将更改为:
$uow = new UnitOfWork(new MapperFactory($db));
$mapper_factory = new MapperFactory($db, $uow);
$service_factory = new ServiceFactory($mapper_factory, new DomainFactory, $uow);
如您所见,它就像到处都是 UnitOfWorks 和 MapperFactories 的捆绑包,只是不够漂亮。
选项 #2 - 服务
Pro:我不会有丑陋的 index.php 文件。我只想为每个服务对象创建一个新的 UnitOfWork 实例。我的 ServiceFactory 内部看起来像这样:
/**
* Create method
*
* This will create a new Service class if it hasn't
* already been instantiated, and return it.
*
* @param string $name The class name
* @return mixed
*/
public function create($name)
{
$class = '\MyApp\Service\' . $name;
if ( array_key_exists($class, $this->cache) === false) {
if (class_exists($class)) {
$uow = new UnitOfWork($this->mapperFactory);
$this->cache[$class] = new $class(
$this->mapperFactory,
$this->domainFactory,
$uow
);
} else {
throw new Exception(sprintf('Service class %s does not exist.', $class));
}
}
return $this->cache[$class];
}
我觉得这看起来干净多了。
Con:我无法让服务相互调用。但是,我正处于这个项目的开始阶段,这是我第一次尝试有点 "correct" MVC 应用程序,所以我不确定我是否会让服务经常互相调用或根本不调用。
选项 #3 - MapperFactory
Pro:我看不到任何东西,但它仍然是一个选择。在我的 index.php 我可以有这个:
$uow = new UnitOfWork($db);
$service_factory = new ServiceFactory(new MapperFactory($db,$uow), new DomainFactory);
我的 UnitOfWork class 可以扩展 MapperFactory class,因此不需要创建两个 MapperFactory 实例。我会将相同的 UnitOfWork 实例传递给每个 Mapper。
Con:我必须通过执行以下操作在我的服务 class 中提交事务:
$this->mapperFactory->unitOfWork->commit();
我不喜欢太多的函数调用。另外,我不确定如何允许域对象在不引用 UnitOfWork 对象的情况下检查它们的状态。
也许我遗漏了什么,但非常感谢任何建议或有用的见解!
工作单元控制通常放置在 DDD 中的应用程序服务中,所以我想这意味着选项 #2。
请注意,您的整个问题可能是由于设计过于复杂。
太多 Factories
通常是一种代码味道——尤其是 DomainFactory
一个 :) 使用它们有特定的原因吗?
通过将域对象传递给它来创建(Object/relational,我猜)映射器实例似乎是人为的。此外,MapperFactory
的含义并不明显。它会创建映射器吗?它映射并创建吗?
您是否正在尝试从头开始实施您自己的工作单元?可能是在重新发明轮子,大多数 ORM 框架都内置了该功能。不过我不知道 PHP。
问题的背景信息
在我的 index.php 文件中我有这个:
$service_factory = new ServiceFactory(new MapperFactory($db), new DomainFactory);
我对 UnitOfWork 应如何与我的应用程序一起工作的理解是这样的(状态是指脏、干净等):
- Mapper - 标记一个对象的状态
$user->markNew();
或$uow->registerNew($user);
- 域 - 可以检查它的当前状态。例如:
$this->isDirty();
- 服务 - 调用
commit()
来完成交易$this->uow->commit()
或$mapper->commit()
我的 UnitOfWork 的提交函数是这样的(欢迎改进):
public function commit()
{
// Inserts the new objects
foreach ($this->newObjects as $newObject) {
$mapper = $this->mapperFactory->createFromDomainObject($newObject);
$mapper->insert($newObject);
}
// Update the dirty objects
foreach ($this->dirtyObjects as $updateObject) {
$mapper = $this->mapperFactory->createFromDomainObject($updateObject);
$mapper->update($updateObject);
}
// Delete the removed
foreach ($this->deletedObjects as $deletedObject) {
$mapper = $this->mapperFactory->createFromDomainObject($deletedObject);
$mapper->delete($deletedObject);
}
}
选项 #1 - ServiceFactory
Pro:如果我有一个服务调用另一个,我将不必担心彼此之间不会传递域对象,因为它们将共享相同的实例工作单位。
Con:我必须将 UnitOfWork 对象一直向下传递到映射器对象,这将有很多级别:ServiceFactory -> Service -> MapperFactory ->映射器... Ew。这对我来说不太合适。 此外,由于 UnitOfWork 需要一个 MapperFactory,我的 index.php 将更改为:
$uow = new UnitOfWork(new MapperFactory($db));
$mapper_factory = new MapperFactory($db, $uow);
$service_factory = new ServiceFactory($mapper_factory, new DomainFactory, $uow);
如您所见,它就像到处都是 UnitOfWorks 和 MapperFactories 的捆绑包,只是不够漂亮。
选项 #2 - 服务
Pro:我不会有丑陋的 index.php 文件。我只想为每个服务对象创建一个新的 UnitOfWork 实例。我的 ServiceFactory 内部看起来像这样:
/**
* Create method
*
* This will create a new Service class if it hasn't
* already been instantiated, and return it.
*
* @param string $name The class name
* @return mixed
*/
public function create($name)
{
$class = '\MyApp\Service\' . $name;
if ( array_key_exists($class, $this->cache) === false) {
if (class_exists($class)) {
$uow = new UnitOfWork($this->mapperFactory);
$this->cache[$class] = new $class(
$this->mapperFactory,
$this->domainFactory,
$uow
);
} else {
throw new Exception(sprintf('Service class %s does not exist.', $class));
}
}
return $this->cache[$class];
}
我觉得这看起来干净多了。
Con:我无法让服务相互调用。但是,我正处于这个项目的开始阶段,这是我第一次尝试有点 "correct" MVC 应用程序,所以我不确定我是否会让服务经常互相调用或根本不调用。
选项 #3 - MapperFactory
Pro:我看不到任何东西,但它仍然是一个选择。在我的 index.php 我可以有这个:
$uow = new UnitOfWork($db);
$service_factory = new ServiceFactory(new MapperFactory($db,$uow), new DomainFactory);
我的 UnitOfWork class 可以扩展 MapperFactory class,因此不需要创建两个 MapperFactory 实例。我会将相同的 UnitOfWork 实例传递给每个 Mapper。
Con:我必须通过执行以下操作在我的服务 class 中提交事务:
$this->mapperFactory->unitOfWork->commit();
我不喜欢太多的函数调用。另外,我不确定如何允许域对象在不引用 UnitOfWork 对象的情况下检查它们的状态。
也许我遗漏了什么,但非常感谢任何建议或有用的见解!
工作单元控制通常放置在 DDD 中的应用程序服务中,所以我想这意味着选项 #2。
请注意,您的整个问题可能是由于设计过于复杂。
太多
Factories
通常是一种代码味道——尤其是DomainFactory
一个 :) 使用它们有特定的原因吗?通过将域对象传递给它来创建(Object/relational,我猜)映射器实例似乎是人为的。此外,
MapperFactory
的含义并不明显。它会创建映射器吗?它映射并创建吗?您是否正在尝试从头开始实施您自己的工作单元?可能是在重新发明轮子,大多数 ORM 框架都内置了该功能。不过我不知道 PHP。