Спустя некоторое время, не зная, как это сделать правильно, и избегая дублирования кода на нескольких контроллерах, я искал и снова искал, но не могу найти четкого ответа.
В одном случае, в частности, необходимо рассчитать несколько статистических данных, заполненных субъектом. Этот расчет будет использовать в 3 разных контроллерах.
В двух из них я покажу разбитые на разные макеты, а в третьих я буду использовать эти данные для глобальных вычислений.
Бизнес-логика для каждого вычисления включает в себя более 100 строк кода, мне пришлось бы утроить в разных контроллерах.
Схема может быть:
С этими 3 значениями я делаю более поздний общий расчет.
Варианты, которые я мог бы найти:
Есть идеи, как решить этот сценарий?
большое спасибо
Услуги, кажется, очень соответствуют описанному использованию.
Недавно я работал над бухгалтерским решением. Я использовал много сложных алгоритмов, и вскоре у меня были очень длинные методы, даже пытавшиеся оптимизировать код.
Сервисы легко доступны, и их использование может сделать контроллеры намного более сексуальными, легкими и сделать большие методы удобочитаемыми и более удобными в использовании, используя отдельные сервисы, соответствующие определенным действиям.
И их можно использовать в других компонентах, пока присутствует 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 в основном помогает управлять «глобальными» объектами. Контроллеры не являются глобальными объектами. Более того, контроллер должен быть максимально тонким. В основном это связующее звено между вашей моделью и видом / шаблонами. Таким образом, если вам необходимо настроить его, это, вероятно, означает, что вам нужно реорганизовать их и извлечь из них бизнес-логику.
Подробнее о 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');
// ...
}
}
Надеюсь, это поможет вам избежать дублирования кода.
Других решений пока нет …