Normalmente, eu uso Silex quando preciso construir um Backend. É simples e direto para fazer uma API endpoint usando esse micro framework. Mas há algo que eu não gosto nele: a forma de acessar o container de injeção de dependência, via “array access”. Eu preciso lembrar que tipo de objeto é o provedor do meu provedor de serviços e também a minha IDE não ajuda com autocomplete. Ok, eu poderia usar comentários do PHPDoc ou mesmo criar uma classe que herda de Silex\Application e use Traits. Normalmente, eu sou muito preguiçoso para fazer isso. Por causa disso, eu criei este simples provedor de serviços para me ajudar a fazer o que eu preciso. Deixe-me explicar um pouco.
Imagine que eu tenha uma classe assim:
class Math
{
public function sum($i, $j)
{
return $i+$j;
}
}
E que quero adicionar este serviço ao meu DIC:
$app['math'] = $app->share(function () {
return new Math();
});
Agora, eu quero usar meu serviço na aplicação Silex:
$app->get("/", function () use ($app) {
return $app['math']->sum(1, 2);
});
Mas eu quero usar meu serviço da mesma forma que estou usando meus serviços nas aplicações AngularJS. Eu quero fazer algo assim:
use Foo\Math;
...
$app->get("/", function (Math $math) {
return $math->sum(1, 2);
});
E isso é exatamente o que o meu provedor de serviços faz. Eu só preciso anexar meu provedor à minha aplicação e falar para o provedor qual é o relacionamento entre as chaves de serviço Pimple e suas instâncias concedidas.
$app->register(new InjectorServiceProvider([
'Foo\Math' => 'math',
]));
Este é um exemplo:
composer require gonzalo123/injector
include __DIR__ . "/../vendor/autoload.php";
use Silex\Application;
use Injector\InjectorServiceProvider;
use Foo\Math;
$app = new Application(['debug' => true]);
$app->register(new InjectorServiceProvider([
'Foo\Math' => 'math',
]));
$app['math'] = function () {
return new Math();
};
$app->get("/", function (Math $math) {
return $math->sum(1, 2);
});
$app->run();
E este é o Provedor de Serviços:
namespace Injector;
use Silex\Application;
use Silex\ServiceProviderInterface;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class InjectorServiceProvider implements ServiceProviderInterface
{
private $injectables;
public function __construct($injectables = [])
{
$this->injectables = $injectables;
}
public function appendInjectables($providedClass, $key)
{
$this->injectables[$providedClass] = $key;
}
public function register(Application $app)
{
$app->on(KernelEvents::CONTROLLER, function (FilterControllerEvent $event) use ($app) {
$reflectionFunction = new \ReflectionFunction($event->getController());
$parameters = $reflectionFunction->getParameters();
foreach ($parameters as $param) {
$class = $param->getClass();
if ($class && array_key_exists($class->name, $this->injectables)) {
$event->getRequest()->attributes->set($param->name, $app[$this->injectables[$class->name]]);
}
}
});
}
public function boot(Application $app)
{
}
}
Como você pode ver, eu estou escutando o evento CONTROLLER do event dispatcher e injetando a dependência a partir do container para requisição de atributos.
O código completo está no meu GitHub.
***
Gonzalo Ayuso faz parte do time de colunistas internacionais do iMasters. A tradução do artigo é feita pela redação iMasters, com autorização do autor, e você pode acompanhar o artigo em inglês no link: http://gonzalo123.com/2015/10/19/alternative-way-to-inject-providers-in-a-silex-application/




