make SymfonyContainer factory configurable with kernel_environment

This commit is contained in:
Tomas Votruba 2019-07-21 09:55:35 +02:00
parent ecf8a1d0f6
commit 2b1e07399d
7 changed files with 106 additions and 41 deletions

View File

@ -8,6 +8,7 @@ parameters:
exclude_paths: []
exclude_rectors: []
autoload_paths: []
php_version_features: ~ # what PHP version should be used for features, local PHP version is used by default
file_extensions:
- php

View File

@ -1,3 +1,9 @@
parameters:
# explicit environment of analyzed application
kernel_environment: ''
# explicit kernel class of analyzed application
kernel_class: ''
services:
_defaults:
public: true

View File

@ -5,7 +5,7 @@ namespace Rector\Symfony\Bridge;
use Rector\Bridge\Contract\AnalyzedApplicationContainerInterface;
use Rector\Configuration\Option;
use Rector\Exception\ShouldNotHappenException;
use Rector\Symfony\Bridge\DependencyInjection\ContainerFactory;
use Rector\Symfony\Bridge\DependencyInjection\SymfonyContainerFactory;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symplify\PackageBuilder\Parameter\ParameterProvider;
@ -13,6 +13,21 @@ use Throwable;
final class DefaultAnalyzedSymfonyApplicationContainer implements AnalyzedApplicationContainerInterface
{
/**
* @var SymfonyKernelParameterGuard
*/
private $symfonyKernelParameterGuard;
/**
* @var SymfonyContainerFactory
*/
private $symfonyContainerFactory;
/**
* @var ParameterProvider
*/
private $parameterProvider;
/**
* @var string[]
*/
@ -22,34 +37,14 @@ final class DefaultAnalyzedSymfonyApplicationContainer implements AnalyzedApplic
'doctrine.orm.default_entity_manager' => 'Doctrine\ORM\EntityManagerInterface',
];
/**
* @var ParameterProvider
*/
private $parameterProvider;
/**
* @var SymfonyKernelParameterGuard
*/
private $symfonyKernelParameterGuard;
/**
* @var ContainerFactory
*/
private $containerFactory;
/**
* @param array<string, string> $commonNamesToTypes
*/
public function __construct(
ParameterProvider $parameterProvider,
SymfonyKernelParameterGuard $symfonyKernelParameterGuard,
ContainerFactory $containerFactory,
array $commonNamesToTypes = []
SymfonyContainerFactory $symfonyContainerFactory,
ParameterProvider $parameterProvider
) {
$this->parameterProvider = $parameterProvider;
$this->symfonyKernelParameterGuard = $symfonyKernelParameterGuard;
$this->containerFactory = $containerFactory;
$this->commonNamesToTypes = array_merge($this->commonNamesToTypes, $commonNamesToTypes);
$this->symfonyContainerFactory = $symfonyContainerFactory;
$this->parameterProvider = $parameterProvider;
}
public function getTypeForName(string $name): ?string
@ -98,20 +93,27 @@ final class DefaultAnalyzedSymfonyApplicationContainer implements AnalyzedApplic
return $container->has($name);
}
/**
* @return object
*/
public function getService(string $name)
{
$container = $this->getContainer($name);
return $container->get($name);
}
/**
* @return ContainerBuilder
*/
private function getContainer(string $requestServiceName): Container
{
$kernelClass = $this->parameterProvider->provideParameter(Option::KERNEL_CLASS_PARAMETER);
if ($kernelClass === null) {
$kernelClass = $this->getDefaultKernelClass();
}
$kernelClass = $this->resolveKernelClass();
$this->symfonyKernelParameterGuard->ensureKernelClassIsValid($kernelClass, $requestServiceName);
/** @var string $kernelClass */
return $this->containerFactory->createFromKernelClass($kernelClass);
return $this->symfonyContainerFactory->createFromKernelClass($kernelClass);
}
private function getDefaultKernelClass(): ?string
@ -126,4 +128,14 @@ final class DefaultAnalyzedSymfonyApplicationContainer implements AnalyzedApplic
return null;
}
private function resolveKernelClass(): ?string
{
$kernelClassParameter = $this->parameterProvider->provideParameter(Option::KERNEL_CLASS_PARAMETER);
if ($kernelClassParameter) {
return $kernelClassParameter;
}
return $this->getDefaultKernelClass();
}
}

View File

@ -2,34 +2,72 @@
namespace Rector\Symfony\Bridge\DependencyInjection;
use Rector\Configuration\Option;
use Rector\Exception\ShouldNotHappenException;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Kernel;
use Symplify\PackageBuilder\Parameter\ParameterProvider;
use Symplify\PackageBuilder\Reflection\PrivatesCaller;
use Throwable;
final class ContainerFactory
final class SymfonyContainerFactory
{
/**
* @var string
*/
private const FALLBACK_ENVIRONMENT = 'dev';
/**
* @var Container[]
*/
private $containersByKernelClass = [];
/**
* @var ParameterProvider
*/
private $parameterProvider;
public function __construct(ParameterProvider $parameterProvider)
{
$this->parameterProvider = $parameterProvider;
}
public function createFromKernelClass(string $kernelClass): Container
{
if (isset($this->containersByKernelClass[$kernelClass])) {
return $this->containersByKernelClass[$kernelClass];
}
return $this->containersByKernelClass[$kernelClass] = $this->createContainerFromKernelClass($kernelClass);
$environment = $this->resolveEnvironment();
try {
$debug = (bool) ($_ENV['APP_DEBUG'] ?? $_SERVER['APP_DEBUG'] ?? true);
$container = $this->createContainerFromKernelClass($kernelClass, $environment, $debug);
} catch (Throwable $throwable) {
throw new ShouldNotHappenException(sprintf(
'Kernel "%s" could not be instantiated for: %s.%sCurrent environment is "%s". Try changing it in "parameters > kernel_environment" in rector.yaml',
$kernelClass,
$throwable->getMessage(),
PHP_EOL . PHP_EOL,
$environment
), $throwable->getCode(), $throwable);
}
$this->containersByKernelClass[$kernelClass] = $container;
return $container;
}
/**
* Mimics https://github.com/symfony/symfony/blob/f834c9262b411aa5793fcea23694e3ad3b5acbb4/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php#L200-L203
*/
private function createContainerFromKernelClass(string $kernelClass): Container
private function createContainerFromKernelClass(string $kernelClass, string $environment, bool $debug): Container
{
$kernel = $this->createKernelFromKernelClass($kernelClass);
/** @var Kernel $kernel */
$kernel = new $kernelClass($environment, $debug);
// preloads all the extensions and $containerBuilder->compile()
$kernel->boot();
@ -55,11 +93,14 @@ final class ContainerFactory
return $containerBuilder;
}
private function createKernelFromKernelClass(string $kernelClass): Kernel
private function resolveEnvironment(): string
{
$environment = $_ENV['APP_ENV'] ?? $_SERVER['APP_ENV'] ?? 'dev';
$debug = (bool) ($_ENV['APP_DEBUG'] ?? $_SERVER['APP_DEBUG'] ?? true);
/** @var string|null $kernelEnvironment */
$kernelEnvironment = $this->parameterProvider->provideParameter(Option::KERNEL_ENVIRONMENT_PARAMETER);
if ($kernelEnvironment) {
return $kernelEnvironment;
}
return new $kernelClass($environment, $debug);
return $_ENV['APP_ENV'] ?? $_SERVER['APP_ENV'] ?? self::FALLBACK_ENVIRONMENT;
}
}

View File

@ -13,7 +13,7 @@ final class SymfonyKernelParameterGuard
// ensure value is not null nor empty
if ($kernelClass === null || $kernelClass === '') {
throw new InvalidConfigurationException(sprintf(
'Make sure "%s" parameters is set in rector.yaml in "parameters:" section.%sIt is needed to resolve "%s" service name to type',
'Make sure "parameters > %s" is set in rector.yaml.%sIt is needed to resolve "%s" service name to type',
Option::KERNEL_CLASS_PARAMETER,
PHP_EOL,
$requestServiceName

View File

@ -7,4 +7,9 @@ interface AnalyzedApplicationContainerInterface
public function getTypeForName(string $name): ?string;
public function hasService(string $name): bool;
/**
* @return object
*/
public function getService(string $name);
}

View File

@ -27,12 +27,12 @@ final class Option
/**
* @var string
*/
public const OPTION_LEVEL = 'level';
public const KERNEL_CLASS_PARAMETER = 'kernel_class';
/**
* @var string
*/
public const KERNEL_CLASS_PARAMETER = 'kernel_class';
public const KERNEL_ENVIRONMENT_PARAMETER = 'kernel_environment';
/**
* @var string