在Symfony2中放置业务逻辑的位置?

时间:2012-07-17 13:02:30

标签: model-view-controller symfony

在阅读了很多帖子和Stack Overflow资源后,我仍然遇到一个关于“在哪里放置业务逻辑?”的着名问题。阅读StackOverflow QuestionA Blog Post,我相信我已经很好地理解了代码分离的问题。

假设我有一个Web表单,您可以在其中添加将添加到数据库的用户。这个例子涉及这些概念:

  • 表格
  • 控制器
  • 实体
  • 服务
  • 存储库

如果我没有遗漏某些东西,你必须创建一个包含一些属性,getter,setter等的实体,以使其持久存在于db中。如果您要获取或编写该实体,您将使用entityManager,对于“非规范”查询,entityRepository(您可以在其中使用“查询语言”查询)。< / p>

现在你必须为所有业务逻辑定义一个服务(这是一个带有“懒惰”实例的PHP类);这是放置“重”代码的地方。一旦您将服务记录到您的应用程序中,您几乎可以在任何地方使用它,并且涉及代码重用等等。

当你渲染和发布一个表单时,你将它与你的实体绑定(当然还有约束),并使用上面定义的所有概念将它们放在一起。

所以,“old-me”会以这种方式编写控制器的动作:

public function indexAction(Request $request)
    {
        $modified = False;
        if($request->getMethod() == 'POST'){ // submit, so have to modify data
            $em = $this->getDoctrine()->getEntityManager();
            $parameters = $request->request->get('User'); //form retriving
            $id = $parameters['id'];
            $user = $em->getRepository('SestanteUserBundle:User')->find($id);
            $form = $this->createForm(new UserType(), $user);
            $form->bindRequest($request);
            $em->flush();
            $modified = True;
        }

        $users = $this->getDoctrine()->getEntityManager()->getRepository('SestanteUserBundle:User')->findAll();
        return $this->render('SestanteUserBundle:Default:index.html.twig',array('users'=>$users));
    }

“New-me”以这种方式重构了代码:

   public function indexAction(Request $request)
    {
        $um = $this->get('user_manager');
        $modified = False;
        if($request->getMethod() == 'POST'){ // submit, so have to modify data
            $user = $um->getUserById($request,False);
            $form = $this->createForm(new UserType(), $user);
            $form->bindRequest($request);
            $um->flushAll();
            $modified = True; 
        }
        $users = $um->showAllUser();
        return $this->render('SestanteUserBundle:Default:index.html.twig',array('users'=>$users));
    }

$um是一种自定义服务,其中存储了从#1代码段到#2代码段无法看到的所有代码。

所以,这是我的问题:

  1. 我终于得到了symfony2和{M} VC的精华吗?
  2. 重构是好的吗?如果没有,那会是更好的方式吗?
  3. Post Scriptum :我知道我可以使用FOSUserBundle进行用户存储和身份验证,但这是教我自己如何使用Symfony的基本示例。 此外,我的服务是注入ORM.Doctrine。*以便工作(只是一个注释,谁用同样的困惑阅读这个问题)

4 个答案:

答案 0 :(得分:3)

关于业务逻辑的放置点有两种主要方法:SOA架构和域驱动架构。如果你的业务对象(实体)是贫血的,我的意思是,如果他们没有业务逻辑,只有getter和setter,那么你会更喜欢SOA。但是,如果您在业务对象中构建业务逻辑,那么您将更喜欢另一个。 Adam Bien讨论了这些方法:

使用Java EE 6进行域驱动设计:http://www.javaworld.com/javaworld/jw-05-2009/jw-05-domain-driven-design.html

使用Java EE 6的精益服务架构:http://www.javaworld.com/javaworld/jw-04-2009/jw-04-lean-soa-with-javaee6.html

这是Java,但你可以理解。

答案 1 :(得分:0)

  

重构是好的吗?如果没有,那会是更好的方式吗?

最好的框架实践之一是使用param转换器直接从用户请求中调用实体

Symfony文档中的示例:

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;

/**
 * @Route("/blog/{id}")
 * @ParamConverter("post", class="SensioBlogBundle:Post")
 */
public function showAction(Post $post)
{

}

有关param转换器的更多信息

http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html

答案 2 :(得分:0)

罗伯特·C·马丁(干净的代码人员)在他的新书clean architecture中说,你应该把你的业务逻辑独立于你的工作,因为框架会随着时间的推移而改变。

因此,您可以将业务逻辑放在App / Core或App / Manager等单独的文件夹中,并避免在此处使用symfony类:

<?php

namespace App\Core;


class UserManager extends BaseManager implements ManagerInterface
{

}

答案 3 :(得分:-1)

我意识到这是一个老问题,但由于我有类似的问题,我想分享我的经验,希望它可能对某人有所帮助。 我的建议是引入命令总线并开始使用命令模式。工作流程非常类似:

  1. Controller接收请求并将其转换为命令(表单可能用于执行此操作,您可能需要一些DTO将数据从一个层干净地移动到另一个层)
  2. Controller将该命令发送到命令总线
  3. 命令总线查找处理程序并处理命令
  4. 然后,控制器可以根据需要生成响应。
  5. 基于您的示例的一些代码:

    public function indexAction(Request $request)
    {
        $command = new CreateUser();
        $form = $this->createForm(new CreateUserFormType(), $command);
        $form->submit($request);
        if ($form->isValid()) {
            $this->get('command_bus')->handle();
        }
        return $this->render(
            'SestanteUserBundle:Default:index.html.twig', 
            ['users' => $this->get('user_manager')->showAllUser()]
        );
    }
    

    然后您的命令处理程序(实际上是服务层的一部分)将负责创建用户。这有几个好处:

    • 你的控制器不太可能变得臃肿,因为它们几乎没有逻辑
    • 您的业务逻辑与应用程序(HTTP)逻辑分离
    • 您的代码变得更易于测试
    • 您可以重复使用相同的命令处理程序,但来自不同端口的数据(例如CLI)

    还有一些缺点:

    • 为了应用此模式,您需要的类数量更高,并且通常与应用程序公开的功能数量呈线性关系
    • 有更多移动的部分,而且有点难以推理,所以团队的学习曲线可能会更陡峭。

    值得注意的几条指挥巴士:

    https://github.com/thephpleague/tactician https://github.com/SimpleBus/MessageBus