Функции повторного использования Symfony2 в контроллерах

Через некоторое время, не зная, как это сделать правильно, и избегайте дублирования кода в нескольких контроллерах, я искал и снова искал, но не могу найти четкого ответа.

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

Схема может быть:

  • Поля вычислений завершены «Данные А»
  • Поля вычислений завершены «Данные B»
  • Поля вычислений завершены «Данные C»

С этими 3 значениями я делаю более поздний общий расчет.

Возможные варианты:

  • Определите контроллер как службу для повторного использования позже в других контроллерах, но я не знаю, является ли это хорошей практикой. Вот хорошая статья, анализирующая эту проблему. Symfony2: Сделать мои службы контроллеров?
    • с одной стороны, как определить контроллеры как службы
    • а с другой – комментарий для Fabien Potencier. Рекомендуем пересмотреть практику «контроллер как услугу» в главе Controller # 457 и «New» Symfony Best Practices
  • Создайте абстрактный BaseController. Об этом говорится здесь, но идея не развита. Symfony2 и быть сухим в контроллерах

Любая идея, как решить этот сценарий?

большое спасибо

Услуги, похоже, очень соответствуют описанному использованию.

Недавно я работал над решением бухгалтерского учета. Я использовал множество сложных алгоритмов, и вскоре у меня были очень длинные методы, даже пытаясь оптимизировать код.

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

И они могут использоваться в других компонентах, если присутствует DependencyInjection, достаточно переместить логику, если вам может понадобиться применить ее в другом контексте, который является контроллером.

Об этом просто заявить:

services: acmeapp.calculation: class: Acme\AppBundle\Services\CalculationService arguments: ["@doctrine.orm.entity_manager", "@acmeapp.anotherservice"] 

И сервис

 class CalculationService { protected $em; protected $another; public function __constructor(EntityManager $entityManager, AnotherService $anotherService) { $this->em = $entityManager; $this->another = $anotherService; } //... } 

Подход Controller-Service – это, прежде всего, сервис со всеми его преимуществами.
Метод вашей службы может отображать представление и иметь маршрут, связанный с использованием атрибута _controller , например:

 display_data_a: path: /data/A methods: GET defaults: { _controller: acmeapp.calculation:dealWithData } 

Без расширения вашего сервиса с Symfony\Bundle\FrameworkBundle\Controller\Controller , но, конечно же, вы можете его использовать.

Кроме того, абстрактный BaseController может быть очень чистой альтернативой, если у вас много дублированного кода с несколькими разными символами между вашими контроллерами.
Это то, что я делаю перед использованием сервисов, если методы соответствуют моему определению контроллера, что соответствует тому, что @fabpot говорит в вашей ссылке.

DIC в основном помогает управлять «глобальными» объектами. Контроллеры не являются глобальными объектами. Кроме того, контроллер должен быть как можно более тонким. Это в основном клей между вашей моделью и View / Templates. Таким образом, если вам нужно настроить его, это, вероятно, означает, что вам нужно реорганизовать их и извлечь из них бизнес-логику.

Подробнее о BaseController в ООП,

Путь прост, если у вас есть строка кода, которая повторяется два или три раза в методе, вы используете переменную.
То же самое для блока кода, вы будете использовать метод. Для контроллеров это одно и то же, если у вас есть два или более объекта одного типа (здесь контроллер), вы должны использовать AbstractController (или BaseController), перемещать в нем свои дублированные методы (только один раз, конечно) и удалять их от дочерних контроллеров.

BaseController:

 class BaseController extends Controller { /** * Shortcut for get doctrine entity manager. */ public function getEntityManager() { return $this->getDoctrine->getEntityManager(); } /** * Shortcut for locate a resource in the application. */ public function locateResource($path) { return $this->get('kernel')->locateResource($path); } // ... } 

И используйте его как часть ваших дочерних контроллеров

 class ChildController extends BaseController { public function helloAction() { $em = $this->getEntityManager(); $file = $this->locateResource('@AcmeAppBundle/Resources/config/hello.yml'); // ... } } 

Надеюсь, это поможет вам избежать большого дублирования кода.