Symfony2: Как уменьшить количество дублирующейся логики в контроллере и джойстике с помощью модели с тонким контроллером Жир? - PullRequest
2 голосов
/ 18 февраля 2012

Для моего проекта 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 внутри хранилища, но хранилище не имеет доступа к объекту запроса, как контроллер.

  • Моя вторая мысль заключалась в том, чтобы поместить логику для разбора фильтров из $ _GET или $ _POST внутри службы ExtFilterParser, но у службы нет доступа к объекту запроса, как у контроллера.

Ответы [ 3 ]

3 голосов
/ 18 февраля 2012

Подумайте об удалении всего кода доктрины (репозитория) из вашего контроллера и просто используйте службу PeopleManager, в которую вы внедряете менеджер сущностей.Таким образом, вы должны иметь:

$peopleManager = $this->get('people.manager');
$people = $peopleManager->getListofPeople($parsedFilters);

Это сохраняет некоторый код и устраняет необходимость для вашего контроллера знать что-либо о модуле doctrine.1006 *

public function loadAction(Request $request) {

Это выбивает getRequest и устраняет возможные проблемы со встроенными контроллерами.

Нет уверенности в том, что запрос Inject будет введен в ваш парсер.Но я бы исключил некоторые проверки ошибок и просто получил бы:

    $extFilterParser = $this->get('ext_filter_parser');
    $filters = $request->query->get('filter');

    // Return empty array if no filters
    $parsedFilters = $extFilterParser->setFilters($filters)->parse()->getParsedFilters();
3 голосов
/ 18 февраля 2012

Я бы сделал вашу вторую мысль и вставил бы @request (см. Мой ответ с кодом на этот вопрос - Как внедрить @request в сервис? ).Этот подход позволяет перенести этот код из контроллера в службу:

    $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 = $this->getRequest();, если вы используете это:

use Symfony\Component\HttpFoundation\Request;

public function loadAction(Request $request) { ... }
2 голосов
/ 18 февраля 2012

Я не вижу слишком много бизнес-логики в ваших действиях.Обычно ваша роль контроллеров / действий заключается в том, чтобы быть шлюзом для вашей доменной модели и сервисов и обрабатывать специфичные для протокола вещи.Команды CLI работают с аргументами командной строки, а контроллеры - с HTTP-запросами, поэтому ваши методы действий делают то, что им положено.

У вас есть много возможностей для рефакторинга кода, чтобы исключить подобные дубликаты кодов в действиях контроллера.используя некоторые шаблоны рефакторинга. Метод извлечения , чтобы переместить эти строки в защищенный метод вашего контроллера.Вы можете извлечь базовый класс для этих похожих контроллеров и переместить туда методы.

В более сложных сценариях вы можете перемещать логику контроллера (извлекая информацию о домене из запроса 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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...