Действительный шаблон для DI службы ZF3 для взаимосвязанных служб

Насколько я понимаю, действительный шаблон:

  • FooControllerFactory, которая создает необходимые службы (FooService)
  • FooController с конструктором __construct (FooService $ fooService)
  • Контроллер получает некоторые базовые данные и получает результат от сервиса
  • Сервис содержит всю необходимую бизнес-логику
    Это базовый сервис. В конце концов, эта служба будет нуждаться в других услугах для различных видов деятельности.
    Например, CacheService, SomeOtherDataService.

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

Реальный пример того, что мы сейчас очень упрощаем:

AuctionController

/**
* get vehicles for specific auction
*/
public function getVehiclesAction ()
{
$auctionService = $this->getAuctionService(); // via service locator
$auctionID = (int) $this->params('auction-id');
$auction = $auctionService->getAuctionVehicle($auctionID);
return $auction->getVehicles();
}

AuctionService

public function getAuctionVehicles($auctionID) {
$auction = $this->getAuction($auctionID);
// verify auction (active, permissions, ...)
if ($auction) {
$vehicleService = $this->getVehicleService(); // via service locator
$vehicleService->getVehicles($params); // $params = some various conditions or array of IDs
}
return false;
}

VehicleService

public function getVehicles($params) {
$cache = $this->getCache(); // via service locator
$vehicles = $cache->getItem($params);
if (!$vehicles) {
$vehicleDB = $this->getVehicleDB(); // via service locator
$vehicles = $vehicleDB->getVehicles($params);
}
return $vehicles;
}

Пример предложенного правильного шаблона

AuctionController

public function __construct(AuctionService $auctionService) {
$this->auctionService = $auctionService;
}

/**
* get vehicles for specific auction
*/
public function getVehiclesAction ()
{
$auctionID = (int) $this->params('auction-id');
$auction = $this->auctionService->getAuctionVehicle($auctionID);
return $auction->getVehicles();
}
**AuctionService**

public function getAuctionVehicles($auctionID) {
$auction = $this->getAuction($auctionID); // no problem, local function
// verify auction (active, permissions, ...)
if ($auction) {
$vehicleService = $this->getVehicleService(); // we don't have service locator
$vehicleService->getVehicles($params); // $params = some various conditions or array of IDs
}
return false;
}

VehicleService

public function getVehicles($params) {
$cache = $this->getCache(); // we don't have service locator, but cache is probably static?
$vehicles = $cache->getItem($params);
if (!$vehicles) {
$vehicleDB = $this->getVehicleDB(); // where and how do we get this service
$vehicles = $vehicleDB->getVehicles($params);
}
return $vehicles;
}

Некоторые заметки:

  • Услуги взаимосвязаны только в некоторых случаях, в 95% они автономны
    • Аукцион обладает большой функциональностью, которая не требует автомобиля
    • В транспортном средстве есть VehicleController и VehicleService, которые только в некоторых случаях связаны с аукционом, это отдельный модуль с другими функциями.
    • Внедрение каждой необходимой службы в контроллер будет пустой тратой ресурсов, потому что они не нужны в каждом действии (в реальном приложении у нас гораздо больше взаимосвязанных служб, а не только две).
  • Программирование одной и той же бизнес-логики в нескольких сервисах только для того, чтобы избежать поиска сервисов, очевидно, является недопустимым шаблоном и неприемлемо

4

Решение

Если контроллеру требуется слишком много разных служб, это обычно является показателем того, что у контроллера слишком много обязанностей.

В ответ на ответ @ AlexP, этот сервис будет добавлен в ваш контроллер. В зависимости от вашей настройки, это может привести к каскаду внедрения зависимостей при создании контроллера. Это по крайней мере ограничит созданные сервисы теми, которые фактически требуются контроллером (и те, которые связаны транзитивно).

Если некоторые из этих служб требуются редко, и вы беспокоитесь о том, чтобы создавать их все при каждом запросе, новый Service Manager теперь поддерживает ленивые услуги тоже. Они все еще могут быть введены в сервис / контроллер как обычная зависимость (как указано выше), но создаются только при первом вызове.

Копируем это из примера документации:

$serviceManager = new \Zend\ServiceManager\ServiceManager([
'factories' => [
Buzzer::class             => InvokableFactory::class,
],
'lazy_services' => [
// Mapping services to their class names is required
// since the ServiceManager is not a declarative DIC.
'class_map' => [
Buzzer::class => Buzzer::class,
],
],
'delegators' => [
Buzzer::class => [
LazyServiceFactory::class,
],
],
]);

При запросе сервиса он не создается сразу:

$buzzer = $serviceManager->get(Buzzer::class);

Но только когда это впервые используется:

$buzzer->buz();

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

5

Другие решения

Вы могли бы составить новый сервис, скажем VehicleAuctionService и оба AuctionService а также VehicleService вводится как зависимость с использованием фабрики.

Это объектная композиция.

class VehicleAuctionService
{
private $auctionService;
private $vehicleService;

public function __construct(
AuctionService $auctionService,
VehicleService $vehicleService
){
$this->auctionService = $auctionService;
$this->vehicleService = $vehicleService;
}

public function getAuctionVehicles($auctionID)
{
$auction = $this->auctionService->getAuction($auctionID);

if ($auction) {
$params = [
'foo' => 'bar',
];
$this->vehicleService->getVehicles($params);
}
return false;
}

}
1

По вопросам рекламы [email protected]