Symfony: 在控制器中实例化一个实体类是否可以?

huangapple go评论62阅读模式
英文:

Symfony: is it fine to instantiate an entity in the controller?

问题

在上面的示例中,你使用了 "new User()",这违反了依赖倒置原则(Dependency Inversion Principle)。依赖倒置原则建议不要在代码中直接实例化依赖的类,而应该通过依赖注入或者工厂模式等方法来获取依赖的实例。因此,你可以考虑将 "User" 类的实例化移到构造函数或者通过依赖注入方式获取它,以遵循依赖倒置原则。

英文:

One of the SOLID principles is Dependency inversion. As I understand it means that I shouldn't instantiate other classes in my code and pass them to the constructor. Is it a violation of this principle when I write this?

UserController extends AbstractController
{
    public function create(Request $request): Response
    {
        $user = new User();
        $form = $this->createForm(RegistrationType::class, $user);

        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {
            $this->entityManager->persist($user);
            $this->entityManager->flush();

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

        return $this->render('user/register.html.twig');
    }
}

In the example above I used "new User()".

答案1

得分: 1

在我看来,你并没有违反SOLID原则,不是因为new User(),而是因为你在调用实体管理器。我更愿意使用一个模型层。在你的情况下,我的模型是一个UserService。你的控制器现在依赖于它,如果在这个用例中添加新任务,你(或你的团队)将在控制器中编写它,我不喜欢这样。

所以,我更愿意使用这段代码:

#[Route('/register', name: 'app_register')]
public function register(Request $request, UserService $userService): Response 
{        
    $user = new User();
    $form = $this->createForm(RegistrationFormType::class, $user);
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
        try {
            $message = $userService->createUser($user);
            $this->addFlash('success', $message);
        } catch (UserServiceException $e) {
            $this->addFlash($e->getLevel(), $e->getReason());
        }

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

    return $this->render('registration/register.html.twig', [
        'registrationForm' => $form->createView(),
    ]);
}

用户创建期间的所有逻辑步骤都在UserService中编码(包括持久化、激活电子邮件、管理员日志等)。

我的控制器只需要知道它是否正常工作。然后,它完成闪存消息。如果出现异常,它捕获人类消息(原因)并将其传递到闪存消息。

如果你的实体稍微复杂一些(比如一辆带有发动机和轮子的汽车),你可以使用CarModel。它只包含带有断言#[Assert\NotBlank()(就像任何简单实体一样)的私有属性和公共的getter和setter。

你可以在控制器中创建你的模型new CarModel(),并在表单提交并有效后,控制器将模型传递给CarServiceCarService将从模型创建复杂的Car实体、Motor实体和四个Wheels实体,然后将它们持久化。

总结一下,我的控制器:

  • 直接创建简单实体,或者对于复杂用例使用模型,使用new MyEntity()new MyModel()
  • 使用请求创建表单并完成实体;
  • 使用请求来判断表单是否已提交并有效;
  • 调用模型层(UserService)执行用例;
  • 根据结果完成闪存消息;
  • 完成并呈现视图,或者将用户重定向。
英文:

In my opinion, you aren't violating SOLID principles because of new User() BUT because you're calling the entity manager. I'd rather to use a model layer. In your case, my model is a UserService. Your controller is now depending of it, and if you add new task during this use case, you (or your team) will code it in your controller and you shouldn't and I don't like that.

So I'd rather to use this code:

    #[Route('/register', name: 'app_register')]
    public function register(Request $request, UserService $userService): Response 
    {        
        $user = new User();
        $form = $this->createForm(RegistrationFormType::class, $user);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            try {
                $message = $userService->createUser($user);
                $this->addFlash('success', $message);
            } catch (UserServiceException $e) {
                $this->addFlash($e->getLevel(), $e->getReason());
            }

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

        return $this->render('registration/register.html.twig', [
            'registrationForm' => $form->createView(),
        ]);

And all the logic steps during user creation are coded in the UserService (persisting, activation email, log for admin, etc.)

My controller only have to know if it works or not. Then it completes the flash message. If it's an exception, it catches a human message (the reason) and forward it to flash message.

If your entity is a bit more complex (let's use a Car with its motor and wheels), you could use a CarModel. It only contains private properties with assertion #[Assert\NotBlank() (like any simple entities) and public getters and setters.

You create your model in your controller new CarModel(), and your model is forwarded by the controller to the CarService as soon as the form is submitted and valid. CarService will create the complex Car entity, the Motor entity, the four Wheels entities from the Model, persist them.

To summarize, my controller :

  • directly creates the simple entities, or a model for complex use case with a new MyEntity() or `new MyModel();
  • uses the request to create form and complete entities ;
  • uses the request to know if the form has been submitted is valid ;
  • calls the model layer (UserService) to execute the use case ;
  • completes the flash messages based on the result,
  • completes and render the view or redirects the user.

huangapple
  • 本文由 发表于 2023年2月27日 06:02:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/75575273.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定