首页 > 解决方案 > 在 Symfony 4 中创建单例实体的最佳方法是什么?

问题描述

我想创建一个设置页面,其中只有一个表单。如果提交了表单,它只会更新设置实体,但不会创建另一个。目前,我实现了这样的目标:

 /**
 * @param SettingsRepository $settingsRepository
 * @return Settings
 */
public function getEntity(SettingsRepository $settingsRepository): Settings
{
    $settings = $settingsRepository->find(1);
    if($settings == null)
    {
        $settings = new Settings();
    }

    return $settings;
}

在 SettingsController 我调用getEntity()返回新设置实体(如果尚未设置设置)或已经存在的设置实体(如果设置至少设置一次)的方法。

但是我的解决方案非常丑陋,并且它具有硬编码的实体 ID“1”,所以我正在寻找更好的解决方案。

设置控制器:

 public function index(
    Request $request,
    SettingsRepository $settingsRepository,
    FlashBagInterface $flashBag,
    TranslatorInterface $translator,
    SettingsService $settingsService
): Response
{
// getEntity() method above
    $settings = $settingsService->getEntity($settingsRepository);
    $settingsForm = $this->createForm(SettingsType::class, $settings);
    $settingsForm->handleRequest($request);

    if ($settingsForm->isSubmitted() && $settingsForm->isValid()) {
        $em = $this->getDoctrine()->getManager();
        $em->persist($settings);
        $em->flush();

        return $this->redirectToRoute('app_admin_settings_index');
    }

    return $this->render(
        'admin/settings/index.html.twig',
        [
            'settings_form' => $settingsForm->createView(),
        ]
    );
}

标签: symfonydoctrine-ormentitysymfony4

解决方案


你可以在这里使用Doctrine Embeddables

严格来说,设置不应映射到实体,因为它们不可识别,也不应如此。当然,这是一个有争议的问题。实际上,设置对象更像是一个值对象而不是一个实体。阅读此处了解更多信息。

因此,在这种情况下,比拥有一对一关系和所有那些模糊的情况更好,您可能会使用一个名为 settings 的简单值对象,它将作为 Doctrine Embeddable 映射到数据库。

您可以通过仅在工厂方法中创建它的实例、使构造函数私有、防止克隆等来使该对象成为单例。通常,仅使其不可变就足够了,也就是说,没有任何行为可以改变它的状态。如果你需要改变它,那么负责它的方法应该创建它的一个新实例。

你可以有一个这样的方法,并且在你新建一个实体时Settings::createFromArray()调用另一个方法:总是默认配置。Settings::createDefaults()

然后,您的实体上的 setSettings 方法仅接收一个设置对象作为参数。

如果您不喜欢不可变性,您还可以为 Settings 对象创建 setter 方法。


推荐阅读