将 Symfony 的依赖注入(自动装配)集成到遗留应用程序中

我有一个遗留应用程序,它是基于旧的自定义 MVC 框架构建的,我希望最终放弃该框架。这个框架不依赖于单个前端控制器,因此大多数页面仍然有专用的php文件来调用受人尊敬的控制器,其他页面是混合的php/html。我已经阅读了有关使用各种方法将应用程序迁移到 symfony 的内容(https://symfony.com/doc/current/migration.html),但是我在使用这两种方法时都遇到了问题,并且意识到我实际上并不需要 symfony 的路由处理。

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

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

非常感谢任何帮助。

非常感谢。

更新1

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

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

但这并不是很理想,因为我想自动加载我的服务,因此我可以以正确的方式使用服务,而不必显式定义我希望在旧应用程序中可用的每项服务。

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

多谢。


函数式编程
浏览 129回答 2
2回答

慕村225694

独立使用依赖注入:安装包:composer require symfony/dependency-injection在配置文件中定义您的服务(即src/Resources/config/services.yaml)。例子:services:    _defaults:        autowire: true        autoconfigure: true        public: false    App\Services\MyService:        class: App\Services\MyService        public: true您还可以使用服务自动导入功能https://symfony.com/doc/current/service_container.html#importing-many-services-at-once-with-resource使用以下代码编译 DI 容器:use Symfony\Component\Config\FileLocator;use Symfony\Component\DependencyInjection\ContainerBuilder;use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;$container = new ContainerBuilder();$loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/src/Resources/config'));$loader->load('services.yaml');$container->compile();将此容器实例注入到您的应用程序中。或者扩展该类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 completenessif (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: trueAWSLegacy 看起来像: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 在我的旧应用程序中处理路由(请求和响应),我只想访问新服务。
打开App,查看更多内容
随时随地看视频慕课网APP