4

我们在决定将 ->flush() 调用放在 Symfony2 应用程序中的什么位置时遇到了麻烦。请让我们看看您是否可以“启发”我们。

我们的应用程序非常大。它目前有大约 30 个捆绑包。我们有 2 个独立的开发团队:一个负责前端(控制器 + 树枝),另一个负责核心(数据库 + 服务 + 模型等)。

前端是一个项目(有自己的包,没有任何理论模型、逻辑或服务,但有树枝、公共图像和 css 和控制器),并且存在于一个存储库中。

Core 是另一个项目(有自己的包,提供服务、模型对象等,内部有教义对象,没有控制器或树枝),并且存在于另一个 repo 中。

这种方法的目标是我们的产品提供不同的前端(Core+Frontend1 用于网络,Core+Frontend2 用于移动设备,Core+Frontend3 用于支持团队,具有一个特殊的网络来管理普通用户)。因此,所有“逻辑”都在“核心”中,并且一个或其他前端项目正在使用相同的服务,因此核心的改进可以改进所有部署,而无需重新测试每一块前端。

所以......我们正在尝试让控制器永远不要访问学说对象,而是访问“建模层”,所以如果持久层发生变化,控制器和树枝(即:所有前端)保持不变,所以我们只需要重新测试核心而不是前端。

我们正在尝试以这样一种方式制作一个模型,即所有对数据库的访问都以“封装”的形式进行,因此控制器不会访问该原则,而是访问反过来使用原则的“服务”。假设我们处理对象“cars”和“people”,那么控制器可以访问“cars_manager”服务或“people_manager”服务,从中执行所有必要的操作(创建对象、检索对象等)。

你会把同花跟注放在哪里?

示例(在伪代码中,以使其更易于阅读):

controller AjaxJsonAddDriverToCar( $CarId, $DriverId )
{
    try
    {
        $Cars = getService( "core.cars_manager" );
        $Car = $Cars->getCarById( $CarId );
        $Car->addDriver( $DriverId );
        $Result = JSON_OK;
    }
    catch
    {
        $Result = JSON_FAIL;
    }

    return $Result;
}

假设控制器不知道核心是如何实现的......它不应该得到学说并对其执行 ->flush() 。

欢迎灵感。谢谢。

4

2 回答 2

3

为了避免从控制器调用flush,我建议将所有更新数据库的代码封装到一个服务方法中,该方法最后调用flush(),在这种情况下,如果服务不会调用flush()方法抛出异常。

在您给出的示例中,这可以通过替换来完成:

    $Cars = getService( "core.cars_manager" );
    $Car = $Cars->getCarById( $CarId );
    $Car->addDriver( $DriverId );
    $Result = JSON_OK;

和:

    $Cars = getService( "core.cars_manager" );
    $Cars->addDriverToCar($CarId, $DriverId);
    $Result = JSON_OK;

和 CarsManager::addDriverToCar 将类似于:

    $Car = $this->getCarById( $CarId );
    $Car->addDriver( $DriverId );
    $this->getEntityManager()->flush();

然而,这是一个相当简单的例子,因为它只更新一个实体,而刷新的美妙之处在于它保存了对您添加/删除/更新的所有实体的更改,构成了一个工作单元的完成。

您描述的方法提到了特定于实体的管理器。虽然复杂实体的管理器没有理由不能拥有创建/更新/删除各种类型的多个实体的方法,但值得考虑管理器类的职责。对于每个实体类型都有一个管理器来处理该实体的简单查找和 CRUD 类型操作,然后在实体管理器和处理特定功能或一组功能的控制器之间有一个额外的管理器层,这可能会有所帮助。

于 2012-06-13T12:01:41.707 回答
2

我的第一个想法是某种主动记录,您可以在其中告诉汽车进行自我保护。由于 Car 只是样板代码,因此它可以了解数据库实现并访问一些服务。

我的第二个想法是汽车经理应该知道储蓄,所以这将与实体经理非常相似,你会告诉他同花,他同花。您基本上会抽象实体管理器并使他更易于使用(因为没有直接使用的存储库)。

我的第三个想法是wtf。我了解您想将前端与后端分开。我不明白为什么前端不能对模型进行操作,但需要对样板代码进行操作。有趣的是:如果模型改变了,你的层也会改变。如果您不想更改图层,也可以不更改模型(两种方式都一样)。例如,您想从数据库中删除一个字段:删除注释并忽略它。没有造成伤害。如果重命名它,您始终可以使用旧的 getter 和 setter,并使用新名称进行操作。等等。

当然我没有看到全貌,但你可能想再考虑一遍;)

这里有另一个想法:也许你只想告诉抽象层整个事情是成功还是失败,他会做所有需要做的事情(刷新数据库、写日志、发送电子邮件等等)。如果您可以将用例缩小到成功和失败,并且服务知道该做什么,那么这可能是最简单的解决方案。

于 2012-06-13T10:46:22.850 回答