Php 在Slim 4中重写路由组中的注入类?

Php 在Slim 4中重写路由组中的注入类?,php,slim,php-di,slim-4,Php,Slim,Php Di,Slim 4,我有一个Slim4应用程序,由几个模块组成,这些模块在不同的路由组中分开,如下所示: $app->group('/app', function(RouteCollectorProxy $app) { /*blah blah*/ })->add(MyMiddleWare::class); $app->group('/api', function(RouteCollectorProxy $app) { /*blah blah*/ })->add(MyMidd

我有一个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();

我的主要问题是:

是否可以基于路由组覆盖
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();
    },
];
特定路由组容器设置:

/*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
,另一个名为
apimidleware
。使用
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();

由于DI容器很早就在应用程序中注册,我认为您必须决定它将进入哪个组,并相应地构建DI容器。这可能意味着必须确保此代码保持一致。看看是否有其他建议。如果我正确理解了这个问题,我会建议避免基于某些条件(即您将中间件添加到哪个路由组)覆盖定义,而是添加接口的不同实现(即实现同一接口的不同中间件)到不同的路线组。类似于
$app->group('/admin')->add(AdminMiddleware::class)
$app->group(apimideware::class)@Nima,所以您可以为不同的中间件类使用不同的DI容器?@NigelRen不是不同的容器,而是同一容器中的不同定义。因此,如果要同时使用
AdminMiddleware
APIMddleware
,那么容器中应该存在这两个类名的相应定义。用户可以明确定义应该传递给这两个中间件的构造函数的内容。容器中应该有一个使用
AdminService
实例化
AdminMiddleware
的定义,以及一个使用
ApiService
实例化
ApiMiddleware
@Nima的条目,如果它解决了OP的问题-然后将其作为答案发布。我刚刚开始使用Slim 4,所以我以前从未这样使用过。