对于我的Symfony2项目,我想坚持Fat Model Skinny Controller方法。我的工作正常,但是,我的控制器中存在大量重复/不必要的业务逻辑。什么是最好的清洁方法?
控制器
<?php
namespace TestApp\PeopleBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class PeopleController extends Controller {
public function indexAction() {
return $this->render('TestAppPeopleBundle:People:index.html.twig');
}
public function loadAction() {
$repository = $this->getDoctrine()->getRepository('TestAppPeopleBundle:People');
$request = $this->getRequest();
$parsedFilters = array();
$extFilterParser = $this->get('ext_filter_parser');
$filters = $request->query->get('filter');
if(empty($filters) === FALSE) {
$parsedFilters = $extFilterParser->setFilters($filters)->parse()->getParsedFilters();
}
$format = $request->getRequestFormat();
$people = $repository->getListOfPeople($parsedFilters);
$data = array('success' => true, 'people' => $people);
return $this->render('::base.'.$format.'.twig', array('data' => $data));
}
public function exportGridAction($format) {
$repository = $this->getDoctrine()->getRepository('TestAppPeopleBundle:People');
$request = $this->getRequest();
$parsedFilters = array();
$extFilterParser = $this->get('ext_filter_parser');
$filters = $request->query->get('filter');
if(empty($filters) === FALSE) {
$parsedFilters = $extFilterParser->setFilters($filters)->parse()->getParsedFilters();
}
$format = $request->getRequestFormat();
$people = $repository->getListOfPeople($parsedFilters);
$grid = $request->get('grid');
return $this->render('::extgrid.'.$format.'.twig', array('grid' => $grid, 'data' => $people));
}
}
实体存储库(人员)
<?php
namespace TestApp\PeopleBundle\Repository;
use Doctrine\ORM\EntityRepository;
/**
* PeopleRepository
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class PeopleRepository extends EntityRepository {
public function getQbForListOfPeople(array $filters) {
$queryBuilder = $this->createQueryBuilder('p');
$queryBuilder->select('p.id', 'p.firstName', 'p.lastName', 'p.dateOfBirth', 'p.address', 'p.city', 'p.state', 'p.zipCode');
foreach($filters as $filter) {
$queryBuilder->andWhere('p.' . $filter['expression'] . ' ' . $filter['value']);
}
$queryBuilder->setMaxResults(50);
return $queryBuilder;
}
public function getListOfPeople() {
return $this->getQbForListOfPeople(array())->getQuery()->getResult();
}
}
我的想法是将解析过滤器的逻辑放在存储库中的$ _GET或$ _POST之外,但是存储库无法像控制器一样访问请求对象。
< / LI>我的第二个想法是将解析过滤器的逻辑放在ExtFilterParser服务中的$ _GET或$ _POST之外,但该服务无法像控制器一样访问请求对象。
答案 0 :(得分:3)
我会做第二个想法并注入@request
(请参阅我的回答,并提供有关此问题的代码 - How to inject the @request into a service?)。这种方法可以让您将此代码从控制器转移到服务中:
$parsedFilters = array();
$extFilterParser = $this->get('ext_filter_parser');
$filters = $request->query->get('filter');
if(empty($filters) === FALSE) {
$parsedFilters = $extFilterParser->setFilters($filters)->parse()->getParsedFilters();
}
其次,$request
将使用Request对象填充,而不必指定$request = $this->getRequest();
如果您使用它:
use Symfony\Component\HttpFoundation\Request;
public function loadAction(Request $request) { ... }
答案 1 :(得分:3)
考虑从控制器中删除所有的教义代码(存储库内容),并且只有一个PeopleManager服务,您可以将实体管理器注入其中。所以你会:
$peopleManager = $this->get('people.manager');
$people = $peopleManager->getListofPeople($parsedFilters);
这可以节省一些代码,并且无需控制器了解有关教义模块的任何信息。
使用
将请求直接注入控制器方法public function loadAction(Request $request) {
敲除了getRequest并消除了嵌入式控制器的可能问题。
不确定将Request注入解析器。但我会消除一些错误检查,只是:
$extFilterParser = $this->get('ext_filter_parser');
$filters = $request->query->get('filter');
// Return empty array if no filters
$parsedFilters = $extFilterParser->setFilters($filters)->parse()->getParsedFilters();
答案 2 :(得分:2)
我的行动中没有看到太多的业务逻辑。通常,您的控制器/操作角色是您的域模型和服务的网关,并处理协议特定的东西。 CLI命令处理命令行参数,带有HTTP请求的控制器,因此您的操作方法可以执行他们应该执行的操作。
您有很多选项可以使用一些重构模式重构代码,以消除控制器操作中的这些重复代码。 Extract method将这些行移动到控制器的受保护方法中。您可以extract a base class使用这些类似的控制器并将方法移到那里。
在更复杂的场景中,您可以将控制器逻辑(从HTTP请求中提取特定于域的信息)移动到服务中,尤其是在您需要其他DIC托管服务来完成此任务时。访问这些服务中的请求对象没有任何错误。您可以使这种服务请求作用域,或实现ContainerAware并从容器中获取请求。
<service id="controller-helper-service" class="%helper.class%" scope="request">
<argument type="service" id="request" />
<argument type="service" id="some-other-service" />
</service>