如何在大型CRUD应用程序中改进控制器代码?

时间:2015-12-29 13:57:57

标签: doctrine-orm coding-style doctrine symfony

大多数时候我在使用CRUD功能的Web应用程序上工作。每当我创建一个新网站时,它几乎都是一样的。

例如我有这段代码,我怎么能改进它呢?

这是非常糟糕的做法,还是在CRUD应用程序中使用此类代码是正常的?

我使用Symfony 3.0和Doctrine 2.5。

AnyObject

更新1

编辑:我对代码做了一些更改。如何改进代码呢?你的最佳实践是什么?

/**
 * @Route("/", name="contacts")
 */
public function listAction(Request $request)
{
    /* @var $em EntityManager */
    $em = $this->getDoctrine()->getManager();
    $searchTerm = $request->get('q');
    $currentGroupId = $request->get('g');

    $qb = $em->createQueryBuilder()
        ->select('c')
        ->from('AppBundle:Contact', 'c')
        ->leftJoin('c.phones', 'p');

    // Get current group from session if not passed by request
    if (empty($currentGroupId)) {
        $request->getSession()->get('contact_current_group_id');
    }

    // Get search term from session if not passed by request
    if (empty($searchTerm)) {
        $request->getSession()->get('contact_search_term');
    }

    // Search if search term is not empty
    if (!empty($searchTerm)) {
        $orX = $qb->expr()->orX();
        $orX->add($qb->expr()->like('c.name', ':searchTerm'));
        $orX->add($qb->expr()->like('p.number', ':searchTerm'));
        $qb->andWhere($orX);
        $qb->setParameter('searchTerm', '%'.$searchTerm.'%');
    }

    // Get and check current group
    $currentGroup = null;
    if ($currentGroupId) {
        $currentGroup = $em->getRepository('AppBundle:ContactGroup')
            ->findOneBy(['enabled' => true, 'id' => $currentGroupId]);

        if ($currentGroup) {
            $qb->andWhere(':groupId MEMBER OF c.groups');
            $qb->setParameter('groupId', $currentGroupId);
        }
    }

    // Get contacts / Pagination
    $paginator = $this->get('knp_paginator');
    $contacts = $paginator->paginate($qb->getQuery(),
        $request->query->getInt('page', 1), 25);

    // Get all groups
    $groups = $em->getRepository('AppBundle:ContactGroup')
        ->findBy(['enabled' => true]);

    return $this->render('contact/list.html.twig', [
        'currentGroup' => $currentGroup,
        'searchTerm' => $searchTerm,
        'contacts' => $contacts,
        'groups' => $groups,
    ]);
}

2 个答案:

答案 0 :(得分:4)

这就是所谓的基于意见的问题,最终可能会被关闭。但是我从未过于羞于提出我的意见。

您的代码实际上很常见。 Symfony是一个基于请求/响应的框架,其中控制器负责根据请求生成响应。这正是您的代码所做的。它很容易阅读,并且很清楚它的作用。坦率地说,如果另一个开发人员无法查看您的代码并弄清楚发生了什么,那么该开发人员真的不应该搞乱该项目。

您的方法的一个缺点是,如果您最终对Contact实体的建模方式进行了重大更改,那么您可能需要相当多的代码来搜索和更新,容易忽略某些内容。您的方法也可能导致额外的代码重复。例如,如果有其他控制器操作需要启用联系人组,那么您最终将复制相同的查询。如果您对代码感到满意并且项目相当稳定,那么这也可能没问题。

如果您想要编写一些命令,也可能会遇到问题。您最终将不得不从控制器复制/粘贴代码,并再次使用重复的代码。同样,如果你决定做一些像添加REST api的事情。

因此,如果您确实希望稍微改进一下(如@tooni所建议的那样),将功能移动到存储库将是一个很好的起点。使用存储库可以让您隔离查询特定的功能,并可能避免重复代码。

在您的情况下,您可以将联系人存储库定义为服务,从而产生:

$contactRepo = $this->get('contact_repository');
$contactQuery = $contactRepo->createQuery($currentGroup,$searchTerm);
$contactGroups = $contactRepo->getEnabledContactGroups();

使用这种方法,您的控制器代码变得更简单。所有查询构建的东西都被移动到存储库中。您可以分享一些功能。更微妙的优势是您的控制器不再需要了解“AppBundle:Contact”。它只是知道它正在获得某种联系查询。事实上,你的控制器根本不再直接依赖于Doctrine。

如果您真的想进入它,那么将您的控制器定义为服务并注入存储库以及paginator服务。现在你的控制器也独立于依赖注入容器。

总之,如果您的代码适合您并且维护它不是一个大问题那么坚持下去。如果你想尝试更复杂的方法,那么打破存储库,看看会发生什么。

答案 1 :(得分:2)

这真的是不好的做法。您永远不应该在Controller中构建查询。将内容移动到存储库(在您的情况下为ContactRepository)并将vars从控制器传递给名为" createSearchQuery"的函数。在那里,您可以构建查询并将其返回给控制器。从那里你可以将它传递给paginator

一般情况下 - 尝试从控制器中移出尽可能多的逻辑。在尽可能小的功能。这有助于其他开发人员理解您的代码,并使代码更好地进行测试。