何时在 Symfony2 的前端/核心方法中调用 ->flush()


When to call ->flush() in a frontend/core approach in Symfony2?

我们在决定在 Symfony2 应用程序中放置 ->flush() 调用的位置时遇到了麻烦。让我们看看你是否能"激励"我们,拜托。

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

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

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

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

所以

......我们试图控制器永远不会访问教义对象,而是访问"建模层",所以如果持久性层发生变化,控制器和树枝(即:所有前端)仍然没有一个变化,所以我们只需要重新测试核心而不是前端。

我们试图以这样一种方式制作一个模型,即所有对数据库的访问都"封装",这样控制器就不会访问原则,而是访问反过来使用原则的"服务"。假设我们将对象视为"汽车"和"人",那么控制器可以访问"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()。

欢迎灵感。谢谢。

为了避免从控制器调用 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 类型操作,然后在实体管理器和控制器之间设置一个额外的管理器层

来处理特定功能或一组功能,这可能会很有帮助。

我的第一个想法是某种活跃的记录,在那里你会告诉汽车自救。由于 Car 只是样板代码,因此它知道数据库实现并访问某些服务可能是可以的。

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

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

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

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