Подтвердить что ты не робот

Где разместить бизнес-логику в Symfony2?

После прочтения большого количества сообщений и ресурсов, у меня все еще есть некоторые проблемы с известным вопросом о том, "где поставить бизнес-логику"? Чтение qaru.site/info/236277/... и Сообщение в блоге, я считаю, что понял эту проблему хорошо разделяемого кода.

Предположим, у меня есть веб-форма, где вы можете добавить пользователя, который будет добавлен в db. Этот пример включает в себя следующие понятия:

  • Форма
  • контроллер
  • Entity
  • Сервис
  • Repository

Если я ничего не пропустил, вам нужно создать сущность с некоторыми свойствами, геттерами, сеттерами и т.д., чтобы он сохранялся в db. Если вы хотите получить или записать этот объект, вы будете использовать entityManager и для "неканонического" запроса entityRepository (то есть, где вы можете поместить свой запрос "запрос" ).

Теперь вам нужно определить службу (то есть класс PHP с "ленивым" экземпляром) для всей бизнес-логики; это место, где можно поставить "тяжелый" код. После того, как вы зарегистрировали услугу в своем приложении, вы можете использовать ее почти везде, и это связано с повторным использованием кода и т.д.

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

Итак, "old-me" будет писать действие контроллера таким образом:

public function indexAction(Request $request)
    {
        $modified = False;
        if($request->getMethod() == 'POST'){ // submit, so have to modify data
            $em = $this->getDoctrine()->getEntityManager();
            $parameters = $request->request->get('User'); //form retriving
            $id = $parameters['id'];
            $user = $em->getRepository('SestanteUserBundle:User')->find($id);
            $form = $this->createForm(new UserType(), $user);
            $form->bindRequest($request);
            $em->flush();
            $modified = True;
        }

        $users = $this->getDoctrine()->getEntityManager()->getRepository('SestanteUserBundle:User')->findAll();
        return $this->render('SestanteUserBundle:Default:index.html.twig',array('users'=>$users));
    }

"New-me" имеет реорганизованный код следующим образом:

   public function indexAction(Request $request)
    {
        $um = $this->get('user_manager');
        $modified = False;
        if($request->getMethod() == 'POST'){ // submit, so have to modify data
            $user = $um->getUserById($request,False);
            $form = $this->createForm(new UserType(), $user);
            $form->bindRequest($request);
            $um->flushAll();
            $modified = True; 
        }
        $users = $um->showAllUser();
        return $this->render('SestanteUserBundle:Default:index.html.twig',array('users'=>$users));
    }

Где $um - это настраиваемая услуга, в которой сохраняется весь код, который вы не видите из фрагмента кода # 1 с номером кода # 2.

Итак, вот мои вопросы:

  • Получил ли я, наконец, сущность symfony2 и {M} VC вообще?
  • Является ли рефактор хорошим? Если нет, то что было бы лучше?

Post Scriptum. Я знаю, что я могу использовать хранилище FOSUserBundle для пользователя и аутентификацию, но это основной пример, чтобы научить себя работе с Symfony. Кроме того, моя служба была введена ORM.Doctrine. * Для работы (просто записка для тех, кто читал этот вопрос с той же путаницей)

4b9b3361

Ответ 1

Существует два основных подхода к тому, где можно разместить бизнес-логику: архитектуру SOA и архитектуру, управляемую доменом. Если ваши бизнес-объекты (субъекты) анемичны, я имею в виду, если у них нет бизнес-логики, просто геттеры и сеттеры, тогда вы предпочтете SOA. Однако, если вы строите бизнес-логику внутри своих бизнес-объектов, тогда вы предпочтете другую. Адам Бьен обсуждает эти подходы:

Проект с поддержкой домена с Java EE 6: http://www.javaworld.com/javaworld/jw-05-2009/jw-05-domain-driven-design.html

Архитектуры старых серверов с Java EE 6: http://www.javaworld.com/javaworld/jw-04-2009/jw-04-lean-soa-with-javaee6.html

Его Java, но вы можете получить эту идею.

Ответ 2

Я понимаю, что это старый вопрос, но поскольку у меня была аналогичная проблема, я хотел поделиться своим опытом, надеясь, что это может помочь кому-то. Мое предложение состояло в том, чтобы ввести командную шину и начать использовать шаблон команды. Рабочий процесс примерно такой:

  • Контроллер получает запрос и переводит его в команду (форма может быть использована для этого, и вам может понадобиться некоторый DTO для переноса данных с одного уровня на другой)
  • Контроллер отправляет эту команду на командную шину
  • Командная шина просматривает обработчик и обрабатывает команду
  • Затем контроллер может генерировать ответ на основе того, что ему нужно.

Некоторый код, основанный на вашем примере:

public function indexAction(Request $request)
{
    $command = new CreateUser();
    $form = $this->createForm(new CreateUserFormType(), $command);
    $form->submit($request);
    if ($form->isValid()) {
        $this->get('command_bus')->handle();
    }
    return $this->render(
        'SestanteUserBundle:Default:index.html.twig', 
        ['users' => $this->get('user_manager')->showAllUser()]
    );
}

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

  • У ваших контроллеров гораздо меньше шансов стать раздутыми, потому что у них мало логики.
  • Ваша бизнес-логика отделена от логики приложения (HTTP)
  • Ваш код станет более проверяемым
  • Вы можете повторно использовать один и тот же обработчик команд, но с данными, поступающими из другого порта (например, CLI).

Есть также несколько недостатков:

  • количество классов, необходимых для применения этого шаблона, выше и обычно линейно масштабируется с количеством функций, которые предоставляет ваше приложение.
  • Есть больше движущихся частей, и это немного сложнее рассуждать, поэтому кривая обучения для команды может быть немного круче.

Несколько командных шин стоит отметить:

https://github.com/thephpleague/tactician https://github.com/SimpleBus/MessageBus

Ответ 3

Является ли рефактор хорошим? Если нет, что было бы лучше?

Одна из лучших практик в кармане - использование преобразователей параметров для непосредственного вызова объекта из пользовательского запроса.

Пример из документации Symfony:

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;

/**
 * @Route("/blog/{id}")
 * @ParamConverter("post", class="SensioBlogBundle:Post")
 */
public function showAction(Post $post)
{

}

Подробнее о преобразователях параметров:

http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html