Php 集成Symfony';将依赖项注入(自动连接)到旧版应用程序

Php 集成Symfony';将依赖项注入(自动连接)到旧版应用程序,php,symfony,symfony4,Php,Symfony,Symfony4,我有一个遗留应用程序,它是建立在一个旧的定制MVC框架之上的,我希望最终摆脱它。此框架不依赖于单个前端控制器,因此大多数页面仍然有专用的php文件来调用受尊重的控制器,其他页面是混合的php/html。我读过关于使用各种方法()将应用程序迁移到symfony的文章,但这两种方法都有问题,我意识到我并不真正需要symfony的路由处理 Symfony目前存在于我们的应用程序中,但仅由各种命令使用。我们所有的核心逻辑仍然在遗留应用程序中,因此Symfony可以访问它,因为类都在全局名称空间中。但是,

我有一个遗留应用程序,它是建立在一个旧的定制MVC框架之上的,我希望最终摆脱它。此框架不依赖于单个前端控制器,因此大多数页面仍然有专用的php文件来调用受尊重的控制器,其他页面是混合的php/html。我读过关于使用各种方法()将应用程序迁移到symfony的文章,但这两种方法都有问题,我意识到我并不真正需要symfony的路由处理

Symfony目前存在于我们的应用程序中,但仅由各种命令使用。我们所有的核心逻辑仍然在遗留应用程序中,因此Symfony可以访问它,因为类都在全局名称空间中。但是,问题是,遗留应用程序无法利用任何新的Symfony类,因为它不支持依赖项注入。要开始将我们的一些核心逻辑和功能转移到Symfony,就需要这种能力

理想情况下,我希望能够完成的是在容器中加载到遗留应用程序,该应用程序具有所有可用的自动连线服务。允许我在传统应用程序中访问新的基于Symfony的服务

任何帮助都是非常感激的

多谢各位

更新1

所以我尝试了@Cerad所说的,只需访问内核,因为它是全局的。我将bootstrap.php逻辑复制到遗留应用程序的主配置中(因此它会加载现有的.env*文件),然后启动内核(在遗留配置中实例化它并调用boot)。它可以工作,我可以在php文件中引用$kernel(使用全局$kernel)并访问容器。然而,这与@Dmitry Solovov的响应一致,服务必须是公共的

我必须将我想要的所有服务设置为公共服务吗?如果我在services.yaml中手动定义服务,将其设置为public,它就会工作

但这并不理想,因为我想自动加载我的服务,因此我可以正确使用服务,而不必明确定义我希望在遗留应用程序中提供的每个服务

在不公开服务的情况下,如何将服务注入到遗留控制器中?就像Symfony的控制器如何允许您将服务注入控制器方法一样


非常感谢。

独立使用依赖项注入:

  • 安装软件包:
  • 在配置文件中定义您的服务(即
    src/Resources/config/services.yaml
    )。例如:
您还可以使用服务自动导入功能

  • 使用以下代码编译DI容器:
  • 将此容器实例注入到应用程序中。或者扩展
    ContanerBuilder
    类并使其成为单例
要在应用程序中使用的服务应该是公共的,因此您可以直接从容器中获取它们:

$service = $container->get(\App\Services\MyService::class);
默认情况下,您还可以公开所有服务:

services:
    _defaults:
        public: true

我在所有页面上都加载了一个配置,在这里我复制了引导逻辑并加载了内核:

// ***** legacy config code above

// This probably could just be loaded using require, but kept it here for completeness
if (is_array($env = @include dirname(__DIR__).'/.env.local.php')) {
    foreach ($env as $k => $v) {
        $_ENV[$k] = $_ENV[$k] ?? (isset($_SERVER[$k]) && 0 !== strpos($k, 'HTTP_') ? $_SERVER[$k] : $v);
    }
} elseif (!class_exists(Dotenv::class)) {
    throw new RuntimeException('Please run "composer require symfony/dotenv" to load the ".env" files configuring the application.');
} else {
    // load all the .env files
    (new Dotenv(false))->loadEnv(dirname(__DIR__).'/config/.env');
}

$_SERVER += $_ENV;
$_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? null) ?: 'dev';
$_SERVER['APP_DEBUG'] = $_SERVER['APP_DEBUG'] ?? $_ENV['APP_DEBUG'] ?? 'dev' == $_SERVER['APP_ENV'];
$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = (int) $_SERVER['APP_DEBUG'] || filter_var($_SERVER['APP_DEBUG'], FILTER_VALIDATE_BOOLEAN) ? '1' : '0';
// End Symfony's bootstrap

// Load Symfony's kernel
$kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
$kernel->boot();
从那里我可以访问我想要的特定服务——只要它是公开的:

global $kernel;
$service = $kernel->getContainer()->get(\App\Services\MyService::class);
在我的项目中,让这项工作正常运行的真正想法不是将所有服务设置为公共服务,而是创建一个遗留服务,该服务在services.yaml中手动定义并设置为公共服务:

services:
    App\Services\Legacy\AWSLegacy:
        public: true
AWSLegacy看起来像:

namespace App\Services\Legacy;

use App\Services\AWS\S3;

class AWSLegacy
{
    /** @var S3 */
    public $s3;

    public function __construct(
        S3 $s3
    )
    {
        $this->s3 = $s3;
    }
}
这使我能够将我希望在遗留应用程序中可用的类似服务分组在一起,而无需在services.yaml中手动为每个服务创建引用并将其设置为公共

Symfony桥接方法对我不起作用,因为我不想Symfony在我的旧应用程序中处理路由(请求和响应),我只想访问新的服务


感谢@Cerad和@Dmitry Solovov的帮助。

可以通过$kernel访问容器,而$kernel又是一个全局变量。这就是您所要求的吗?服务必须是公共的,实际上没有办法向您的应用程序控制器注入非公共服务。我用一个示例编辑了我的答案,以公开所有服务。最好用一个简单的示例开始一个新问题。首先,您说您的遗留类不支持注入,然后,通过编辑,您说您的遗留控制器支持注入。在最后一句话中,你问了关于注入控制器方法的问题,这是一个完全不同的主题,而不是容器本身所做的事情。术语很重要。有一个Reddit Symfony论坛,可能是解决此类问题的更好平台。很抱歉造成混乱。起初他们没有,但您关于只使用$kernel的评论让我只在主配置中加载内核。在这一点上,我能够获得所有的公共服务。谢谢你的帮助,你让我走上了正确的道路;然而,由于我的项目有遗留应用程序和symfony并排运行,我可以只使用现有的services.yaml文件,而不是使用$container->complile(),我只是实例化内核并运行boot()。尽管我没有公开所有服务,因为我不希望我现有的symfony应用程序走上那条糟糕的道路。相反,我创建了遗留服务,并将其设置为公共服务。然后,这些服务将我想要的各种服务注入到我的遗留应用程序中。因为我在技术上并不要求所有的服务都可用,我想继续使用一些遗留的核心逻辑。例如,我们希望用基于symfony的AWS S3代码替换旧的AWS S3代码。这为我们提供了这条道路。谢谢。
global $kernel;
$service = $kernel->getContainer()->get(\App\Services\MyService::class);
services:
    App\Services\Legacy\AWSLegacy:
        public: true
namespace App\Services\Legacy;

use App\Services\AWS\S3;

class AWSLegacy
{
    /** @var S3 */
    public $s3;

    public function __construct(
        S3 $s3
    )
    {
        $this->s3 = $s3;
    }
}