28/06/2018 - SYMFONY
"Servis bulucu" servisleri, servis isimlerini alarak diğer servislere ulaşmamıza yardımcı olurlar. Bu yaklaşımın iki ana faydası vardır. İlk olarak, ana class sadece "servis bulucu" servisini bilir ve ikincisi ise, ana class içine enjekte edilen servislerin sayısı en az seviyede tutulur. Daha fazla bilgi için Service Subscribers & Locators sayfasını okuyun.
Bir servis bulucu servisimiz olmasaydı, kontrolörümüz aşağıdaki gibi olurdu.
class LocatorController
{
public function __construct(
ServiceA $serviceA,
ServiceB $serviceB,
ServiceC $serviceC,
ServiceD $serviceD,
...
) {
}
}
Yukarıdakinin yerine aşağıdaki örneğe sahip olacağız.
class LocatorController
{
public function __construct(
ServiceLocator $serviceLocator
) {
}
}
parameters:
services:
_defaults:
autowire: true
autoconfigure: true
public: false
App\:
resource: '../src/*'
exclude: '../src/{Entity,Repository,Service,Kernel.php}'
App\Controller\:
resource: '../src/Controller'
tags: ['controller.service_arguments']
App\Factory\ModelFactory:
arguments:
$id: 1
Bu sadece bir gösteri amaçlı!
declare(strict_types=1);
namespace App\Controller;
use App\Factory\ModelFactoryInterface;
use App\Locator\ServiceLocatorInterface;
use App\Service\CountryServiceInterface;
use App\Util\CalculatorUtilInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
/**
* @Route("/locators")
*/
class LocatorController
{
private $serviceLocator;
public function __construct(
ServiceLocatorInterface $serviceLocator
) {
$this->serviceLocator = $serviceLocator;
}
/**
* @Route("/{type}")
* @Method({"GET"})
*/
public function getService(string $type): Response
{
if ('util' === $type) {
/** @var CalculatorUtilInterface $service */
$service = $this->serviceLocator->get(CalculatorUtilInterface::class);
$result = $service->sum(1, 2);
} elseif ('factory' === $type) {
/** @var ModelFactoryInterface $service */
$service = $this->serviceLocator->get(ModelFactoryInterface::class);
$result = $service->create('inanzzz');
} else {
$this->serviceLocator->get(CountryServiceInterface::class);
// This would throw an exception because it is not registered in ServiceLocator class
}
return new JsonResponse($result);
}
}
declare(strict_types=1);
namespace App\Exception;
use RuntimeException;
class ServiceLocatorException extends RuntimeException
{
}
declare(strict_types=1);
namespace App\Factory;
use stdClass;
interface ModelFactoryInterface
{
public function create(string $name): stdClass;
}
declare(strict_types=1);
namespace App\Factory;
use stdClass;
class ModelFactory implements ModelFactoryInterface
{
private $id;
public function __construct(int $id)
{
$this->id = $id;
}
public function create(string $name): stdClass
{
$model = new stdClass();
$model->id = $this->id;
$model->name = $name;
return $model;
}
}
declare(strict_types=1);
namespace App\Util;
interface CalculatorUtilInterface
{
public function sum(int $a, int $b): int;
}
declare(strict_types=1);
namespace App\Util;
class CalculatorUtil implements CalculatorUtilInterface
{
public function sum(int $a, int $b): int
{
return $a+$b;
}
}
declare(strict_types=1);
namespace App\Locator;
interface ServiceLocatorInterface
{
public function get(string $id);
}
declare(strict_types=1);
namespace App\Locator;
use App\Exception\ServiceLocatorException;
use App\Factory\ModelFactoryInterface;
use App\Util\CalculatorUtilInterface;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\ContainerInterface;
use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
class ServiceLocator implements ServiceLocatorInterface, ServiceSubscriberInterface
{
private $locator;
public function __construct(ContainerInterface $locator)
{
$this->locator = $locator;
}
public static function getSubscribedServices()
{
return [
'App\Factory\ModelFactoryInterface' => ModelFactoryInterface::class,
'App\Util\CalculatorUtilInterface' => CalculatorUtilInterface::class,
];
}
public function get(string $id)
{
if (!$this->locator->has($id)) {
throw new ServiceLocatorException(sprintf(
'The entry for the given "%s" identifier was not found.',
$id
));
}
try {
return $this->locator->get($id);
} catch (ContainerExceptionInterface $e) {
throw new ServiceLocatorException(sprintf(
'Failed to fetch the entry for the given "%s" identifier.',
$id
));
}
}
}
# GET /locators/factory
{"id":1,"name":"inanzzz"}
# GET /locators/util
3
# GET /locators/invalid
ServiceLocatorException
The entry for the given "App\Service\CountryServiceInterface" identifier was not found.