【问题标题】:how to inject reusable controller injection with php-di correctly如何使用 php-di 正确注入可重用的控制器注入
【发布时间】:2019-12-17 09:32:55
【问题描述】:

我正在启动一个新的 slim 4 应用程序,当前的 slim 版本更像是一个路由器而不是一个框架,并且没有开箱即用的 di 容器,所以我选择PHP-DI 作为 DI 容器。并且不描述容器中的每个控制器,也不将容器实例传递给我使用PHP-DI自动装配的控制器。

但是通过这种方法,我需要将所有依赖项注入每个控制器,并且大多数依赖项都可以被所有控制器重用。示例:

public function __construct(
    Environment $twig,
    Messages $flashMessage,
    RouteCollectorInterface $routeCollector
)
{
    $this->render = $twig;
    $this->flashMessage = $flashMessage;
    $this->routeCollector = $routeCollector;
}

有没有办法制作一个基本控制器,向它注入所有可重用的依赖项,所以当DIc 创建/自动装配每个新控制器时,所有已经注入 b-z 控制器的依赖项都扩展了基本控制器?此外,基本控制器可能应该使用方法注入,否则,我仍然需要创建一个构造函数并将每个控制器中的所有注入传递给基本控制器,如下所示:

public function __construct(
    Environment $twig,
    CommandBus $commandBus,
    Messages $flashMessage,
    RouteCollectorInterface $routeCollector
)
{
     parent::__construct($twig, $flashMessage, $routeCollector);
    $this->commandBus = $commandBus;
}

这可能与在没有基本控制器的情况下向每个控制器注入依赖项相同。

我尝试配置基本控制器:

   $definitions[BaseController::class] = static function(ContainerInterface $container): BaseController {
        /** @var BaseController $controller */
        $controller =new BaseController();
        $controller->setView($container->get(Environment::class));
        $controller->setRouter($container->get(RouteCollectorInterface::class));
        $controller->setFleshMessage($container->get(Messages::class));

        return $controller;
    };

但它不起作用,并且每个扩展基本控制器的控制器的依赖项是 null

PHP-DIhttp://php-di.org/doc/best-practices.html#writing-controllers 建议使用属性注入,但是对于我来说,为每个控制器注入所有可重用的注入仍然看起来像样板,并且当我们注入私有属性时它会破坏封装。

我能想到的解决方案之一是制作某种ControllerHelper,将所有可重用的依赖项作为桥接器/包装器并注入它而不是所有这些依赖项,这将减少重复代码的数量。但是,也许有更好的解决方案???

更新:我知道它实际上是在 OOP 中工作的,如果您扩展基类,则需要将所有依赖项传递给它。但是为了减少一些重复,这里有一些魔法会很好:)而且它不是一个会被其他人使用的外部包,所以如果有可能以某种方式实现的话,这种魔法可能是可以的。

更新: 换句话说,我想要实现的是:

 class SomeController extends BaseController {
// in this case constructor is empty 

        public function index(RequestInterface $request, ResponseInterface $response) {
             return $this->render($response, $templateName, [somedata]);
        }
    }

其中$this-render 是一个BaseController 类方法,它使用模板引擎依赖来渲染视图:

public function render(ResponseInterface $request, string $templateName, array $data): ResponseInterface {
          $response->getBody()->write(
            $this->render->render(
                $templateName,
                $data
            )
        );

        return $response;
}

如您所见,我不想将依赖项注入SomeController,但以某种方式将它们注入一次BaseController

【问题讨论】:

    标签: php dependency-injection controller php-di


    【解决方案1】:

    你可以尝试像下面的“BaseController”控制器类:

    <?php
    
    namespace App\Application;
    
    use Twig\Environment;
    use Laminas\Diactoros\Response;
    use Psr\Http\Message\ResponseInterface;
    
    abstract class BaseController
    {
        private $template;
    
        public function __construct(Environment $template)
        {
            $this->template = $template;
        }
    
        public function view(string $template, array $data = []) : ResponseInterface
        {
            $result = $this->template->render($template, $data);
    
            $response = new Response();
            $response->getBody()->write($result);
            return $response;
        }
    }
    

    然后在调用你的控制器时你可以这样做:

    <?php
    
    namespace App\Controller\Auth;
    
    use App\Application\Controller;
    
    class AuthController extends BaseController
    {
    
        public function showLogin()
        {
            return $this->view('auth/login.html');
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-09
      • 2016-07-06
      • 2017-01-20
      • 2019-06-23
      • 2019-06-14
      • 2012-04-23
      • 1970-01-01
      相关资源
      最近更新 更多