大多数时候我在使用CRUD功能的Web应用程序上工作。每当我创建一个新网站时,它几乎都是一样的。
例如我有这段代码,我怎么能改进它呢?
这是非常糟糕的做法,还是在CRUD应用程序中使用此类代码是正常的?
我使用Symfony 3.0和Doctrine 2.5。
AnyObject
编辑:我对代码做了一些更改。如何改进代码呢?你的最佳实践是什么?
/**
* @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,
]);
}
答案 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
。
一般情况下 - 尝试从控制器中移出尽可能多的逻辑。在尽可能小的功能。这有助于其他开发人员理解您的代码,并使代码更好地进行测试。