Skip to content

Commit

Permalink
Обработка переменных окружения.
Browse files Browse the repository at this point in the history
  • Loading branch information
ProklUng committed Jul 4, 2021
1 parent d87053c commit 7d5c1d9
Show file tree
Hide file tree
Showing 6 changed files with 305 additions and 8 deletions.
23 changes: 23 additions & 0 deletions readme.MD
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,29 @@ $serviceProvider = new ServiceProvider('local/configs/services.yaml');
Для обеспечения "преемственности" (похожести) с оригиналом можно задать путь к файлу конфигурации (скажем, `bundles.php`)
бандлов вторым (необязательным) параметром конструктора.

#### Переменные среды

Предполагается, что переменные среды к моменту инициализации контейнера уже загружены тем или иным способом.

Значимые переменные среды:

- `DEBUG` (булево значение - режим отладки), `APP_DEBUG` - алиас `DEBUG`, но с большим приоритетом
(если одновременно присустствуют `DEBUG` и `APP_DEBUG`, то в дело пойдет значение `APP_DEBUG`).

- `APP_ENV` - код окружения. Если код не задан, то будет проинтерпретировано значение `DEBUG` в смысле - если в режиме отладки,
то окружение `dev`, иначе `prod`.

Если переменные среды не заданы, то с помощью класса `Prokl\ServiceProvider\LoadEnvironment` их можно загрузить.

Скажем, в `init.php`, перед инициализацией контейнера:

```php
// Параметр конструктора - путь, где лежат файлы .env
$loader = new \Prokl\ServiceProvider\LoadEnvironment($_SERVER['DOCUMENT_ROOT'] . '/../..');
$loader->load(); // Загрузка $_ENV
$loader->process(); // Обработка переменных
```

## Конфигурирование

1) Опция `compile.container` в подтягиваемом конфиге - компилировать ли контейнер в файл. Если не задана, то "нет, не компилировать".
Expand Down
71 changes: 71 additions & 0 deletions src/LoadEnvironment.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

namespace Prokl\ServiceProvider;

use Symfony\Component\Dotenv\Dotenv;

/**
* Class LoadEnvironment
* Хэлпер: загрузка окружения (dev или prod).
* @package Prokl\ServiceProvider
*/
class LoadEnvironment
{
/**
* @var string $pathEnvFile Путь к env файлам.
*/
private $pathEnvFile;

/**
* LoadEnvironment constructor.
*
* @param string $pathEnvFile Путь к env файлам.
*/
public function __construct(string $pathEnvFile)
{
$this->pathEnvFile = $pathEnvFile;
}

/**
* Загрузка конфигурации окружения.
*
* @return void
*/
public function load() : void
{
/** Путь к конфигурации окружения. .env.prod - продакшен. */
$pathEnvFile = @file_exists($this->pathEnvFile . '/.env.prod')
? $this->pathEnvFile . '/.env.prod'
:
$_SERVER['DOCUMENT_ROOT'] . '/.env';

if (@file_exists($this->pathEnvFile . '/.env.local')) {
$pathEnvFile = $this->pathEnvFile . '/.env.local';
}

$dotenv = new Dotenv();

$dotenv->loadEnv($pathEnvFile);
}

/**
* Обработка переменных окружения.
*
* @return void
*/
public function process() : void
{
$_ENV['DEBUG'] = $_ENV['DEBUG'] ?? false;

if (array_key_exists('APP_DEBUG', $_ENV) && $_ENV['APP_DEBUG'] !== null) {
$_ENV['DEBUG'] = (bool)$_ENV['APP_DEBUG'];
}

$_SERVER = array_merge($_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'] ?? 'prod' !== $_SERVER['APP_ENV'];
$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = (int)$_SERVER['APP_DEBUG']
|| filter_var($_SERVER['APP_DEBUG'], FILTER_VALIDATE_BOOLEAN) ? '1' : '0';
}
}
16 changes: 12 additions & 4 deletions src/ServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -176,11 +176,18 @@ public function __construct(
) {
// Buggy local fix.
$_ENV['DEBUG'] = env('DEBUG', false);
if (array_key_exists('APP_DEBUG', $_ENV) && $_ENV['APP_DEBUG'] !== null) {
$_ENV['DEBUG'] = (bool)$_ENV['APP_DEBUG'];
}

$this->environment = $_ENV['DEBUG'] ? 'dev' : 'prod';
if (array_key_exists('APP_ENV', $_ENV) && $_ENV['APP_ENV'] !== null) {
$this->environment = $_ENV['APP_ENV'];
}

$this->debug = (bool)$_ENV['DEBUG'];

$this->errorHandler = new ErrorScreen(new CMain());

$this->filesystem = new Filesystem();

if (!$filename) {
Expand Down Expand Up @@ -429,7 +436,9 @@ private function getContainerClass() : string
$class = str_replace('\\', '_', $class).ucfirst($this->environment).($this->debug ? 'Debug' : '').'Container';

if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $class)) {
throw new InvalidArgumentException(sprintf('The environment "%s" contains invalid characters, it can only contain characters allowed in PHP class names.', $this->environment));
throw new InvalidArgumentException(
sprintf('The environment "%s" contains invalid characters, it can only contain characters allowed in PHP class names.', $this->environment)
);
}

return $class;
Expand Down Expand Up @@ -585,8 +594,7 @@ private function setDefaultParamsContainer() : void
->addTag('service.bootstrap')
->setAutoconfigured(true)
->setPublic(true)
->setArguments([$_ENV['DEBUG']])
;
->setArguments([$this->environment, $this->debug]);
}

/** @var array $kernelParams */
Expand Down
9 changes: 5 additions & 4 deletions src/Services/AppKernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,13 @@ class AppKernel extends Kernel
/**
* AppKernel constructor.
*
* @param string $debug Отладка? Это же определяет тип окружения.
* @param string $environment Окружение.
* @param boolean $debug Отладка.
*/
public function __construct(string $debug)
public function __construct(string $environment, bool $debug)
{
$this->debug = (bool)$debug;
$this->environment = $this->debug ? 'dev' : 'prod';
$this->debug = $debug;
$this->environment = $environment;
$this->projectDir = $_SERVER['DOCUMENT_ROOT'];

parent::__construct($this->environment, $this->debug);
Expand Down
133 changes: 133 additions & 0 deletions tests/Cases/LoadEnvironmentTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<?php

namespace Prokl\ServiceProvider\Tests\Cases;

use Prokl\ServiceProvider\LoadEnvironment;
use Prokl\TestingTools\Base\BaseTestCase;

/**
* Class LoadEnvironmentTest
* @package Prokl\ServiceProvider\Tests\Cases
*
* @since 04.07.2021
*/
class LoadEnvironmentTest extends BaseTestCase
{
/**
* @var LoadEnvironment $obTestObject
*/
protected $obTestObject;

/**
* @inheritDoc
*/
protected function setUp(): void
{
@unlink($_SERVER['DOCUMENT_ROOT'] . '/.env');
@unlink($_SERVER['DOCUMENT_ROOT'] . '/.env.prod');
@unlink($_SERVER['DOCUMENT_ROOT'] . '/.env.local');

parent::setUp();

$_SERVER['DOCUMENT_ROOT'] = __DIR__ . '/../fixtures/env';
$this->obTestObject = new LoadEnvironment(
$_SERVER['DOCUMENT_ROOT']
);
}

/**
* @inheritDoc
*/
protected function tearDown(): void
{
parent::tearDown();

unset($_ENV);
unset($_SERVER['APP_ENV'], $_SERVER['APP_DEBUG'], $_SERVER['DEBUG']);
}

/**
* @return void
*/
public function testProcess() : void
{
$this->obTestObject->process();

$this->assertFalse($_ENV['DEBUG']);
}

/**
* load(). Production.
*
* @return void
*/
public function testLoadProd() : void
{
file_put_contents(
$_SERVER['DOCUMENT_ROOT'] . '/.env',
'TEST=dev'
);

file_put_contents(
$_SERVER['DOCUMENT_ROOT'] . '/.env.prod',
'TEST=prod'
);

$this->obTestObject->load();

$this->assertSame($_ENV['TEST'], 'prod');

@unlink($_SERVER['DOCUMENT_ROOT'] . '/.env.prod');
@unlink($_SERVER['DOCUMENT_ROOT'] . '/.env');
}

/**
* load(). Local.
*
* @return void
*/
public function testLoadLocal() : void
{
file_put_contents(
$_SERVER['DOCUMENT_ROOT'] . '/.env',
'TEST=dev'
);

file_put_contents(
$_SERVER['DOCUMENT_ROOT'] . '/.env.prod',
'TEST=prod'
);

file_put_contents(
$_SERVER['DOCUMENT_ROOT'] . '/.env.local',
'TEST=local'
);

$this->obTestObject->load();

$this->assertSame($_ENV['TEST'], 'local');

@unlink($_SERVER['DOCUMENT_ROOT'] . '/.env');
@unlink($_SERVER['DOCUMENT_ROOT'] . '/.env.prod');
@unlink($_SERVER['DOCUMENT_ROOT'] . '/.env.local');
}

/**
* load(). .env.
*
* @return void
*/
public function testLoadEnv() : void
{
file_put_contents(
$_SERVER['DOCUMENT_ROOT'] . '/.env',
'TEST=dev'
);

$this->obTestObject->load();

$this->assertSame($_ENV['TEST'], 'dev');

@unlink($_SERVER['DOCUMENT_ROOT'] . '/.env');
}
}
61 changes: 61 additions & 0 deletions tests/Cases/ServiceProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Exception;
use Prokl\BitrixTestingTools\Base\BitrixableTestCase;
use Prokl\ServiceProvider\ServiceProvider;
use Prokl\ServiceProvider\Services\AppKernel;
use RuntimeException;

/**
Expand Down Expand Up @@ -42,6 +43,16 @@ protected function setUp() : void
$this->rrmdir($_SERVER['DOCUMENT_ROOT'] . '/bitrix/cache/s1/containers');
}

/**
* @inheritDoc
*/
protected function tearDown(): void
{
parent::tearDown();

unset($_ENV['DEBUG'], $_ENV['APP_DEBUG'], $_ENV['APP_ENV']);
}

/**
* @return void
* @throws Exception
Expand All @@ -63,6 +74,56 @@ public function testLoad() : void
$this->assertTrue($container->has('test_service'), 'Тестовый сервис не зарегистрировался');
}

/**
*
* Обработка переменных окружения.
*
* @param boolean $debug
* @param boolean $appDebug
* @param string $env
* @param string $expectedResult
*
* @return void
* @throws Exception
*
* @runInSeparateProcess
* @preserveGlobalState disabled
*
* @dataProvider dataProviderDebugEnv
*/
public function testEnvironments(bool $debug, bool $appDebug, string $env, string $expectedResult) : void
{
$_ENV['DEBUG'] = $debug;
$_ENV['APP_DEBUG'] = $appDebug;
$_ENV['APP_ENV'] = $env;

$this->obTestObject = new ServiceProvider($this->pathYamlConfig);

/** @var AppKernel $kernel */
$kernel = $this->obTestObject->get('kernel');
$kernelParams = $kernel->getKernelParameters();

$this->assertSame($appDebug, $kernelParams['kernel.debug'], 'kernel.debug установился неправильно.');
$this->assertSame(
$expectedResult,
$kernelParams['kernel.environment'],
'kernel.environment установился неправильно.'
);
}

/**
* @return array[]
*/
public function dataProviderDebugEnv() : array
{
return [
[false, true, 'dev', 'dev'],
[true, true, 'test', 'test'],
[false, true, 'test', 'test'],
[true, false, 'prod', 'prod'],
];
}

/**
* @return void
* @throws Exception
Expand Down

0 comments on commit 7d5c1d9

Please sign in to comment.