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 应如何与我的应用程序一起工作的理解是这样的(状态是指脏、干净等):

我的 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。