As far as I understand the valid pattern is:
- a FooControllerFactory that instantiates the needed service(s) (FooService)
- a FooController with constructor __construct(FooService $fooService)
- the Controller acquires some basic data and gets a result from the service
- the Service contains all the required business logic This is a base service. Eventualy this service will need other services for various activities. For example CacheService, SomeOtherDataService.
The question is, what is a valid/appropriate pattern for including/injecting those other interconnected services?
A reallife example of that we have currently, extremely simplified:
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;
}
Example of a suggested valid pattern
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;
}
Some notes:
- Services are interconnected only in some cases, in 95% they are standalone
- Auction has a lot funcionality that does not need Vehicle
- Vehicle has VehicleController and VehicleService that does only in some cases relate do Auction, it's a standalone module that has other functionalities
- The Injection of every needed service in a controller would be a waste of resources, because they are not needed in every action (in the real-life application we have many more interconnected services, not just two)
- Programming the same business logic in multiple services just to avoid the service locator is obviously an invalid pattern and not acceptable.