【问题标题】:PHP - Where should Unit Of Work lie in an MVC application?PHP - 工作单元应该在 MVC 应用程序中的什么位置?
【发布时间】:2015-05-06 21:05:17
【问题描述】:

问题的背景信息

在我的 index.php 文件中,我有这个:

$service_factory = new ServiceFactory(new MapperFactory($db), new DomainFactory);

我对 UnitOfWork 应该如何与我的应用程序一起工作的理解是这样的(状态指的是脏、干净等):

  • Mapper - 标记对象的状态
    • $user->markNew();$uow->registerNew($user);
  • 域 - 可以检查它的当前状态。例如:$this->isDirty();
  • Service - 调用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 - 服务工厂

专业人士:如果我有一个服务调用另一个服务,我不必担心在彼此之间不传递域对象,因为它们将共享同一个 UnitOfWork 实例。

Con:我必须将 UnitOfWork 对象一直传递到映射器对象,这将是这么多级别:ServiceFactory -> Service -> MapperFactory -> Mapper... 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 文件。我将为每个 Service 对象创建一个新的 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:我无法让服务相互调用。然而,我正处于这个项目的开始阶段,这是我第一次尝试一个有点“正确”的 MVC 应用程序,所以我不确定我是否会让服务相互调用很多或根本不调用。

选项 #3 - MapperFactory

专业人士:我看不到任何东西,但它仍然是一种选择。在我的 index.php 中我可以有这个:

$uow = new UnitOfWork($db);
$service_factory = new ServiceFactory(new MapperFactory($db,$uow), new DomainFactory);

我的 UnitOfWork 类可以扩展 MapperFactory 类,因此不需要创建两个 MapperFactory 实例。我会将 UnitOfWork 的相同实例传递给每个 Mapper。

Con:我必须通过执行以下操作在我的 Service 类中提交事务:

$this->mapperFactory->unitOfWork->commit();

我喜欢的函数调用太多。另外,我不确定如何允许域对象在不引用 UnitOfWork 对象的情况下检查它们的状态。

也许我缺少一些东西,但非常感谢任何建议或有用的见解!

【问题讨论】:

    标签: php model-view-controller domain-driven-design unit-of-work


    【解决方案1】:

    工作单元控制通常放在 DDD 中的应用程序服务中,所以我猜这意味着选项 #2。

    请注意,您的整个问题可能是由于设计过于复杂。

    • 太多Factories 通常是代码异味——尤其是DomainFactory 一个:) 使用它们是否有特定原因?

    • 通过传递域对象来创建(对象/关系,我猜)映射器实例似乎是做作的。此外,MapperFactory 的含义并不明显。它会创建映射器吗?它是否映射和创建

    • 您是否尝试从头开始实施您自己的工作单元?可能是在重新发明轮子,大多数 ORM 框架都内置了该功能。不过我不了解 PHP。

    【讨论】:

    • "请注意,您的整个问题可能是由于设计过于复杂。"我有一种感觉,但不确定如何/在哪里。我明白你关于工厂太多的观点。是否最好在需要时手动创建它们?映射器工厂创建数据映射器(Ex in Service:$this->mapperFactory->create('User');)创建一个新的MyApp\Mapper\UserMapper 实例。我从网上找到的其他一些 UOW 复制了代码,这些代码似乎运行良好。只是在我的应用中实现它们时遇到了麻烦。
    • 我只在对象需要控制其依赖项之一的整个生命周期、创建它并按照它认为合适的方式处置它时才使用工厂(在Abstract Factory 模式意义上)。这意味着,几乎从来没有。 99% 的情况下,我直接通过对象的构造函数注入依赖项,而不是注入会产生依赖项的工厂。您可能希望应用相同的推理来将您的系统从所有多余的工厂中剥离。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多