Интегрировать внедрение зависимостей Symfony (автоматическое подключение) в устаревшее приложение - PullRequest
1 голос
/ 09 июля 2020

У меня есть унаследованное приложение, построенное на старой кастомной среде MVC, от которой я хотел бы со временем отказаться. Эта структура не полагается на один фронт-контроллер, поэтому на большинстве страниц все еще есть выделенные файлы php для вызова уважаемого контроллера, другие - смешанные php / html. Я читал о переносе приложений на symfony с использованием различных методов (https://symfony.com/doc/current/migration.html), но у меня были проблемы с обоими методами, и я понял, что мне это действительно не нужно symfony.

Symfony в настоящее время существует в нашем приложении, но используется только различными командами. Все наши основные logi c по-прежнему находятся в устаревшем приложении, поэтому Symfony может получить к нему доступ без проблем, поскольку все классы находятся в глобальном пространстве имен. Однако проблема в том, что унаследованное приложение не может использовать какие-либо новые классы Symfony, поскольку оно не поддерживает внедрение зависимостей. Эта возможность потребуется для того, чтобы начать перенос некоторых из наших основных logi c и функций в Symfony.

В идеале то, что я хотел бы сделать, sh загружается в контейнер. в наше устаревшее приложение, в котором доступны все наши сервисы с автоматическим подключением. Позволяет мне получить доступ к нашим новым службам на основе Symfony в нашем устаревшем приложении.

Любая помощь приветствуется.

Большое спасибо.

Обновить 1

Итак, я попробовал то, что сказал @Cerad, просто получите доступ к ядру, поскольку оно глобальное. Я скопировал bootstrap. php logi c в свою основную конфигурацию для моего устаревшего приложения (поэтому он загружает существующие файлы .env *), затем загрузил ядро ​​(создал его экземпляр и вызвал boot в моей устаревшей конфигурации ). Это работает, я могу ссылаться на $ kernel (используя global $ kernel) в своих файлах php и получить доступ к контейнеру. Однако, что соответствует ответу @Dmitry Solovov, службы должны быть опубликованы c.

Должен ли я установить все службы, которые мне нужны, как publi c? Если я вручную определяю службу в services.yaml, устанавливаю ее в publi c, она работает.

Но это не совсем идеально, поскольку я хотел бы автоматически загружать свои службы, поэтому я могу использовать службы правильный способ и не нужно явно определять каждую службу, которую я хочу, чтобы быть доступной в моем устаревшем приложении.

Как я могу внедрить службы в мои устаревшие контроллеры, не публикуя службу c? Так же, как контроллер Symfony позволяет вам внедрять службы в методы контроллера?

Большое спасибо.

Ответы [ 2 ]

2 голосов
/ 09 июля 2020

Чтобы использовать внедрение зависимостей независимо:

  • установите пакет:
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 и сделайте его синглтоном.

Службы для использования в вашем приложении должны быть publi c, чтобы вы могли получать их прямо из контейнера:

$service = $container->get(\App\Services\MyService::class);

Вы также можете опубликовать все свои услуги c по умолчанию:

services:
    _defaults:
        public: true
0 голосов
/ 09 июля 2020

У меня есть одна конфигурация, которая загружается на все страницы, туда я скопировал bootstrap logi c и загрузил ядро:

// ***** 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();

Оттуда я смог получить доступ к определенным Служба c, которую я хотел, - пока она была publi c:

global $kernel;
$service = $kernel->getContainer()->get(\App\Services\MyService::class);

Реальная идея, благодаря которой это хорошо работало для моего проекта, заключалась не в настройке всех служб publi c, а в создании устаревший сервис, который был вручную определен в services.yaml и установлен в publi c:

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 и установки их publi c.

Методы моста Symfony не работали для меня, как я Я не хочу, чтобы Symfony обрабатывал маршрутизацию (запросы и ответы) в моем устаревшем приложении, я просто хотел получить доступ к новым службам.

Спасибо @Cerad и @Dmitry Solovov за помощь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...