Symfony2:如何通过瘦控制器脂肪模型方法减少控制器中的重复逻辑数量?

时间:2012-02-18 06:19:31

标签: php model-view-controller symfony

对于我的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之外,但该服务无法像控制器一样访问请求对象。

3 个答案:

答案 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>