【问题标题】:Dependency Injection Slim Framework 3依赖注入 Slim 框架 3
【发布时间】:2016-08-19 03:33:25
【问题描述】:

我正在使用 Slim Framework 3 创建 API。应用结构为:MVCP(模型、视图、控制器、提供者)。

是否可以让我的所有类都注入 Slim 依赖项?

我正在使用 composer 来自动加载我的所有依赖项。

我的目录结构如下:

/app
   - controllers/
   - Models/
   - services/
   index.php
/vendor
 composer.json

这是我的composer.json 文件。

{
  "require": {
    "slim/slim": "^3.3",
    "monolog/monolog": "^1.19"
  },
  "autoload" : {
    "psr-4" : {
        "Controllers\\" : "app/controllers/",
        "Services\\" : "app/services/",
        "Models\\" : "app/models/"
    }
  }
}

这是我的index.php 文件。同样,依赖项由 composer 自动注入

<?php
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;

require '../vendor/autoload.php';

$container = new \Slim\Container;
$app = new \Slim\App($container);

$app->get('/test/{name}', '\Controllers\PeopleController:getEveryone');

$app->run();

我的控制器是这样的

<?php #controllers/PeopleController.php

namespace Controllers;

use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;


class PeopleController
{
    protected $peopleService;

    protected $ci;
    protected $request;
    protected $response;

    public function __construct(Container $ci, PeopleService $peopleService)
    {
        $this->peopleService = $peopleService;
        $this->ci = $ci;
    }

    public function getEveryone($request, $response)
    {
        die($request->getAttribute('name'));

        return $this->peopleService->getAllPeoples();
    }
}

我的 PeopleService 文件如下所示:

<?php

namespace Services;

use Model\PeopleModel;
use Model\AddressModel;
use Model\AutoModel;


class PeopleService
{
    protected $peopleModel;
    protected $autoModel;
    protected $addressModel;

    public function __construct(PeopleModel $peopleModel, AddressModel $addressModel, AutoModel $autoModel)
    {
        $this->addressModel = $addressModel;
        $this->autoModel = $autoModel;
        $this->peopleModel = $peopleModel;
    }

    public function getAllPeopleInfo()
    {
        $address = $this->addressModel->getAddress();
        $auto = $this->autoModel->getAutoMake();
        $person = $this->peopleModel->getPeople();

        return [
            $person[1], $address[1], $auto[1]
        ];
    }
}

Models/AddressModels.php

<?php

namespace Model;

class AddressModel
{

    public function __construct()
    {
        // do stuff
    }

    public function getAddress()
    {
        return [
            1 => '123 Maple Street',
        ];
    }
}

Models/AutoModel.php

namespace Model;

class AutoModel
{

    public function __construct()
    {
        // do stuff
    }

    public function getAutoMake()
    {
        return [
            1 => 'Honda'
        ];
    }
}

Models/PeopleModel.php

<?php
namespace Model;

class PeopleModel
{

    public function __construct()
    {
        // do stuff
    }

    public function getPeople()
    {
        return [
            1 => 'Bob'
        ];
    }

}

错误 我现在收到以下错误:

PHP Catchable fatal error:  Argument 2 passed to Controllers\PeopleController::__construct() must be an instance of Services\PeopleService, none given, called in /var/www/vendor/slim/slim/Slim/CallableResolver.php on line 64 and defined in /var/www/app/controllers/PeopleController.php on line 21

问题 我如何依赖注入我所有的类?有没有办法自动告诉 Slim 的 DI 容器去做?

【问题讨论】:

  • 所以你想注入或自动加载它们?如果您的意思是自动加载,您可能忘记在index.php 的开头包含vendor/autoload.php 文件。它包含生成的自动加载器。
  • 嗯,这是我的问题之一。谢谢!我已更新 index.php 以包含供应商自动加载 PHP 文件。我已经更新了问题以包含我现在遇到的错误。同样,问题是如何依赖注入我的类。
  • 嗯,错误是不言自明的。这里有什么不清楚的地方?
  • 不清楚的是如何将参数传递给我的控制器的构造方法。 $app-&gt;get('/test', '\Controllers\PeopleController:getEveryone(new Service\PeopleService'); 不起作用
  • 这是一个完全符合您要求的示例:slimframework.com/docs/objects/router.html#container-resolution 您需要将您的控制器注册为 DIC 中的服务,并在其定义中传递依赖项。

标签: php dependency-injection slim slim-3


【解决方案1】:

当你在路由中引用一个类时,Slim 会向 DIC 询问它。如果 DIC 没有该类名的注册,那么它将实例化该类本身,将容器作为唯一参数传递给该类。

因此,要为控制器注入正确的依赖项,您只需创建自己的 DIC 工厂:

$container = $app->getContainer();
$container['\Controllers\PeopleController'] = function ($c) {
    $peopleService = $c->get('\Services\PeopleService');
    return new Controllers\PeopleController($c, $peopleService);
};

当然,您现在需要一个用于 PeopleService 的 DIC 工厂:

$container['\Services\PeopleService'] = function ($c) {
    $peopleModel = new Models\PeopleModel;
    $addressModel = new Models\AddressModel;
    $autoModel = new Models\AutoModel;
    return new Services\PeopleService($peopleModel, $addressModel, $autoModel);
};

(如果 PeopleModel、AddressModel 或 AutoModel 有依赖关系,那么您也可以为它们创建 DIC 工厂。)

【讨论】:

  • Slim 是否要求您将容器传递给需要它的 每个 类?这似乎不是一个非常干燥的方法。我习惯于使用 CakePHP,并且在使用它时似乎东西“全局”可用(可能是由于 AppModel 和 AppController)。在 Slim 中,您似乎每次需要时都需要传递诸如容器之类的东西?所以如果我有 100 个类,我必须使用相当于你放 100 次以上的代码?
  • 这取决于你。没有什么可以阻止您创建一个允许您抓取容器的全局静态函数。就个人而言,我不喜欢这种级别的耦合,所以不要那样做。
猜你喜欢
  • 2015-02-12
  • 1970-01-01
  • 1970-01-01
  • 2014-09-06
  • 2010-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多