我有一个Slim4应用程序,它由几个模块组成,这些模块分成不同的路由组,如下所示:
$app->group('/app', function(RouteCollectorProxy $app) {
/*blah blah*/
})->add(MyMiddleWare::class);
$app->group('/api', function(RouteCollectorProxy $app) {
/*blah blah*/
})->add(MyMiddleware::class);
$app->group('/admin', function(RouteCollectorProxy $app) {
/*blah blah*/
})->add(MyMiddleware::class);
MyMiddleware收到接口
class MyMiddleware
{
public function __construct(IMyInterface $myServiceImplementingInterface) { /*blah blah*/ }
}
[设置容器时,我们告诉它要注入哪个类,以便PHP-DI知道使用哪个类来构造中间件:
/* bootstraping */
$containerBuilder = new ContainerBuilder();
$containerBuilder->addDefinitions(__DIR__ . '/container.php');
$container = $containerBuilder->build();
和
/*container.php*/
return [
IMyInterface::class => function (ContainerInterface $container) {
return new MyServiceImplementingInterface();
},
];
我的主要问题是:
是否有可能基于路由组覆盖IMyInterface::class
的容器设置的实现?这样我就可以像:
主容器设置:
/*container.php*/
return [
IMyInterface::class => function (ContainerInterface $container) {
return new MyServiceImplementingInterface();
},
];
特定路线组容器设置:
/*container.admin.php*/
return [
IMyInterface::class => function (ContainerInterface $container) {
return new AnotherServiceImplementingInterface();
},
];
我建议对不同的组使用MyMiddleware
类的两个不同对象,每个对象都使用IMyInterface
的适当实现构造。您可以告诉PHP-DI使用所需的参数来调用构造函数。
在这里,我在容器中创建了两个MyMiddleware
实例,一个实例名为AdminMiddleware
,另一个实例名为ApiMiddleware
。使用DI\create()->constructor()
方法,我将DI配置为在构建这两个对象时注入IMyInterface
的不同实现:
<?php
use DI\ContainerBuilder;
use Slim\Factory\AppFactory;
// this is the path of autoload.php relative to my index.php file
// change it according to your directory structure
require __DIR__ . '/../vendor/autoload.php';
interface IMyInterface {
public function sampleMethod();
}
class MyServiceImplementingInterface implements IMyInterface {
public function sampleMethod() {
return 'This implementation is supposed to be used for API endpoint middleware';
}
}
class AnotherServiceImplementingInterface implements IMyInterface {
public function sampleMethod() {
return 'This implementation is supposed to be used for Admin middleware';
}
}
class MyMiddleware
{
private $service;
public function __construct(IMyInterface $myServiceImplementingInterface) {
$this->service = $myServiceImplementingInterface;
}
public function __invoke($request, $handler)
{
$response = $handler->handle($request);
$response->getBody()->write($this->service->sampleMethod());
return $response;
}
}
$containerBuilder = new ContainerBuilder();
$containerBuilder->addDefinitions([
'AdminMiddleware' => DI\create(MyMiddleware::class)->constructor(DI\get(AnotherServiceImplementingInterface::class)),
'ApiMiddleware' => DI\create(MyMiddleware::class)->constructor(DI\get(MyServiceImplementingInterface::class))
]);
$container = $containerBuilder->build();
AppFactory::setContainer($container);
$app = AppFactory::create();
$app->group('/admin', function($app) {
$app->get('/dashboard', function($request, $response, $args){
return $response;
});
})->add($container->get('AdminMiddleware'));
$app->group('/api', function($app) {
$app->get('/endpoint', function($request, $response, $args){
return $response;
});
})->add($container->get('ApiMiddleware'));
$app->run();