Skip to content

Commit 7d5c1d9

Browse files
committed
Обработка переменных окружения.
1 parent d87053c commit 7d5c1d9

File tree

6 files changed

+305
-8
lines changed

6 files changed

+305
-8
lines changed

readme.MD

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,29 @@ $serviceProvider = new ServiceProvider('local/configs/services.yaml');
3131
Для обеспечения "преемственности" (похожести) с оригиналом можно задать путь к файлу конфигурации (скажем, `bundles.php`)
3232
бандлов вторым (необязательным) параметром конструктора.
3333

34+
#### Переменные среды
35+
36+
Предполагается, что переменные среды к моменту инициализации контейнера уже загружены тем или иным способом.
37+
38+
Значимые переменные среды:
39+
40+
- `DEBUG` (булево значение - режим отладки), `APP_DEBUG` - алиас `DEBUG`, но с большим приоритетом
41+
(если одновременно присустствуют `DEBUG` и `APP_DEBUG`, то в дело пойдет значение `APP_DEBUG`).
42+
43+
- `APP_ENV` - код окружения. Если код не задан, то будет проинтерпретировано значение `DEBUG` в смысле - если в режиме отладки,
44+
то окружение `dev`, иначе `prod`.
45+
46+
Если переменные среды не заданы, то с помощью класса `Prokl\ServiceProvider\LoadEnvironment` их можно загрузить.
47+
48+
Скажем, в `init.php`, перед инициализацией контейнера:
49+
50+
```php
51+
// Параметр конструктора - путь, где лежат файлы .env
52+
$loader = new \Prokl\ServiceProvider\LoadEnvironment($_SERVER['DOCUMENT_ROOT'] . '/../..');
53+
$loader->load(); // Загрузка $_ENV
54+
$loader->process(); // Обработка переменных
55+
```
56+
3457
## Конфигурирование
3558

3659
1) Опция `compile.container` в подтягиваемом конфиге - компилировать ли контейнер в файл. Если не задана, то "нет, не компилировать".

src/LoadEnvironment.php

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
3+
namespace Prokl\ServiceProvider;
4+
5+
use Symfony\Component\Dotenv\Dotenv;
6+
7+
/**
8+
* Class LoadEnvironment
9+
* Хэлпер: загрузка окружения (dev или prod).
10+
* @package Prokl\ServiceProvider
11+
*/
12+
class LoadEnvironment
13+
{
14+
/**
15+
* @var string $pathEnvFile Путь к env файлам.
16+
*/
17+
private $pathEnvFile;
18+
19+
/**
20+
* LoadEnvironment constructor.
21+
*
22+
* @param string $pathEnvFile Путь к env файлам.
23+
*/
24+
public function __construct(string $pathEnvFile)
25+
{
26+
$this->pathEnvFile = $pathEnvFile;
27+
}
28+
29+
/**
30+
* Загрузка конфигурации окружения.
31+
*
32+
* @return void
33+
*/
34+
public function load() : void
35+
{
36+
/** Путь к конфигурации окружения. .env.prod - продакшен. */
37+
$pathEnvFile = @file_exists($this->pathEnvFile . '/.env.prod')
38+
? $this->pathEnvFile . '/.env.prod'
39+
:
40+
$_SERVER['DOCUMENT_ROOT'] . '/.env';
41+
42+
if (@file_exists($this->pathEnvFile . '/.env.local')) {
43+
$pathEnvFile = $this->pathEnvFile . '/.env.local';
44+
}
45+
46+
$dotenv = new Dotenv();
47+
48+
$dotenv->loadEnv($pathEnvFile);
49+
}
50+
51+
/**
52+
* Обработка переменных окружения.
53+
*
54+
* @return void
55+
*/
56+
public function process() : void
57+
{
58+
$_ENV['DEBUG'] = $_ENV['DEBUG'] ?? false;
59+
60+
if (array_key_exists('APP_DEBUG', $_ENV) && $_ENV['APP_DEBUG'] !== null) {
61+
$_ENV['DEBUG'] = (bool)$_ENV['APP_DEBUG'];
62+
}
63+
64+
$_SERVER = array_merge($_SERVER, $_ENV);
65+
66+
$_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? null) ?: 'dev';
67+
$_SERVER['APP_DEBUG'] = $_SERVER['APP_DEBUG'] ?? $_ENV['APP_DEBUG'] ?? 'prod' !== $_SERVER['APP_ENV'];
68+
$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = (int)$_SERVER['APP_DEBUG']
69+
|| filter_var($_SERVER['APP_DEBUG'], FILTER_VALIDATE_BOOLEAN) ? '1' : '0';
70+
}
71+
}

src/ServiceProvider.php

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -176,11 +176,18 @@ public function __construct(
176176
) {
177177
// Buggy local fix.
178178
$_ENV['DEBUG'] = env('DEBUG', false);
179+
if (array_key_exists('APP_DEBUG', $_ENV) && $_ENV['APP_DEBUG'] !== null) {
180+
$_ENV['DEBUG'] = (bool)$_ENV['APP_DEBUG'];
181+
}
182+
179183
$this->environment = $_ENV['DEBUG'] ? 'dev' : 'prod';
184+
if (array_key_exists('APP_ENV', $_ENV) && $_ENV['APP_ENV'] !== null) {
185+
$this->environment = $_ENV['APP_ENV'];
186+
}
187+
180188
$this->debug = (bool)$_ENV['DEBUG'];
181189

182190
$this->errorHandler = new ErrorScreen(new CMain());
183-
184191
$this->filesystem = new Filesystem();
185192

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

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

435444
return $class;
@@ -585,8 +594,7 @@ private function setDefaultParamsContainer() : void
585594
->addTag('service.bootstrap')
586595
->setAutoconfigured(true)
587596
->setPublic(true)
588-
->setArguments([$_ENV['DEBUG']])
589-
;
597+
->setArguments([$this->environment, $this->debug]);
590598
}
591599

592600
/** @var array $kernelParams */

src/Services/AppKernel.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,13 @@ class AppKernel extends Kernel
4040
/**
4141
* AppKernel constructor.
4242
*
43-
* @param string $debug Отладка? Это же определяет тип окружения.
43+
* @param string $environment Окружение.
44+
* @param boolean $debug Отладка.
4445
*/
45-
public function __construct(string $debug)
46+
public function __construct(string $environment, bool $debug)
4647
{
47-
$this->debug = (bool)$debug;
48-
$this->environment = $this->debug ? 'dev' : 'prod';
48+
$this->debug = $debug;
49+
$this->environment = $environment;
4950
$this->projectDir = $_SERVER['DOCUMENT_ROOT'];
5051

5152
parent::__construct($this->environment, $this->debug);
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
<?php
2+
3+
namespace Prokl\ServiceProvider\Tests\Cases;
4+
5+
use Prokl\ServiceProvider\LoadEnvironment;
6+
use Prokl\TestingTools\Base\BaseTestCase;
7+
8+
/**
9+
* Class LoadEnvironmentTest
10+
* @package Prokl\ServiceProvider\Tests\Cases
11+
*
12+
* @since 04.07.2021
13+
*/
14+
class LoadEnvironmentTest extends BaseTestCase
15+
{
16+
/**
17+
* @var LoadEnvironment $obTestObject
18+
*/
19+
protected $obTestObject;
20+
21+
/**
22+
* @inheritDoc
23+
*/
24+
protected function setUp(): void
25+
{
26+
@unlink($_SERVER['DOCUMENT_ROOT'] . '/.env');
27+
@unlink($_SERVER['DOCUMENT_ROOT'] . '/.env.prod');
28+
@unlink($_SERVER['DOCUMENT_ROOT'] . '/.env.local');
29+
30+
parent::setUp();
31+
32+
$_SERVER['DOCUMENT_ROOT'] = __DIR__ . '/../fixtures/env';
33+
$this->obTestObject = new LoadEnvironment(
34+
$_SERVER['DOCUMENT_ROOT']
35+
);
36+
}
37+
38+
/**
39+
* @inheritDoc
40+
*/
41+
protected function tearDown(): void
42+
{
43+
parent::tearDown();
44+
45+
unset($_ENV);
46+
unset($_SERVER['APP_ENV'], $_SERVER['APP_DEBUG'], $_SERVER['DEBUG']);
47+
}
48+
49+
/**
50+
* @return void
51+
*/
52+
public function testProcess() : void
53+
{
54+
$this->obTestObject->process();
55+
56+
$this->assertFalse($_ENV['DEBUG']);
57+
}
58+
59+
/**
60+
* load(). Production.
61+
*
62+
* @return void
63+
*/
64+
public function testLoadProd() : void
65+
{
66+
file_put_contents(
67+
$_SERVER['DOCUMENT_ROOT'] . '/.env',
68+
'TEST=dev'
69+
);
70+
71+
file_put_contents(
72+
$_SERVER['DOCUMENT_ROOT'] . '/.env.prod',
73+
'TEST=prod'
74+
);
75+
76+
$this->obTestObject->load();
77+
78+
$this->assertSame($_ENV['TEST'], 'prod');
79+
80+
@unlink($_SERVER['DOCUMENT_ROOT'] . '/.env.prod');
81+
@unlink($_SERVER['DOCUMENT_ROOT'] . '/.env');
82+
}
83+
84+
/**
85+
* load(). Local.
86+
*
87+
* @return void
88+
*/
89+
public function testLoadLocal() : void
90+
{
91+
file_put_contents(
92+
$_SERVER['DOCUMENT_ROOT'] . '/.env',
93+
'TEST=dev'
94+
);
95+
96+
file_put_contents(
97+
$_SERVER['DOCUMENT_ROOT'] . '/.env.prod',
98+
'TEST=prod'
99+
);
100+
101+
file_put_contents(
102+
$_SERVER['DOCUMENT_ROOT'] . '/.env.local',
103+
'TEST=local'
104+
);
105+
106+
$this->obTestObject->load();
107+
108+
$this->assertSame($_ENV['TEST'], 'local');
109+
110+
@unlink($_SERVER['DOCUMENT_ROOT'] . '/.env');
111+
@unlink($_SERVER['DOCUMENT_ROOT'] . '/.env.prod');
112+
@unlink($_SERVER['DOCUMENT_ROOT'] . '/.env.local');
113+
}
114+
115+
/**
116+
* load(). .env.
117+
*
118+
* @return void
119+
*/
120+
public function testLoadEnv() : void
121+
{
122+
file_put_contents(
123+
$_SERVER['DOCUMENT_ROOT'] . '/.env',
124+
'TEST=dev'
125+
);
126+
127+
$this->obTestObject->load();
128+
129+
$this->assertSame($_ENV['TEST'], 'dev');
130+
131+
@unlink($_SERVER['DOCUMENT_ROOT'] . '/.env');
132+
}
133+
}

tests/Cases/ServiceProviderTest.php

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Exception;
66
use Prokl\BitrixTestingTools\Base\BitrixableTestCase;
77
use Prokl\ServiceProvider\ServiceProvider;
8+
use Prokl\ServiceProvider\Services\AppKernel;
89
use RuntimeException;
910

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

46+
/**
47+
* @inheritDoc
48+
*/
49+
protected function tearDown(): void
50+
{
51+
parent::tearDown();
52+
53+
unset($_ENV['DEBUG'], $_ENV['APP_DEBUG'], $_ENV['APP_ENV']);
54+
}
55+
4556
/**
4657
* @return void
4758
* @throws Exception
@@ -63,6 +74,56 @@ public function testLoad() : void
6374
$this->assertTrue($container->has('test_service'), 'Тестовый сервис не зарегистрировался');
6475
}
6576

77+
/**
78+
*
79+
* Обработка переменных окружения.
80+
*
81+
* @param boolean $debug
82+
* @param boolean $appDebug
83+
* @param string $env
84+
* @param string $expectedResult
85+
*
86+
* @return void
87+
* @throws Exception
88+
*
89+
* @runInSeparateProcess
90+
* @preserveGlobalState disabled
91+
*
92+
* @dataProvider dataProviderDebugEnv
93+
*/
94+
public function testEnvironments(bool $debug, bool $appDebug, string $env, string $expectedResult) : void
95+
{
96+
$_ENV['DEBUG'] = $debug;
97+
$_ENV['APP_DEBUG'] = $appDebug;
98+
$_ENV['APP_ENV'] = $env;
99+
100+
$this->obTestObject = new ServiceProvider($this->pathYamlConfig);
101+
102+
/** @var AppKernel $kernel */
103+
$kernel = $this->obTestObject->get('kernel');
104+
$kernelParams = $kernel->getKernelParameters();
105+
106+
$this->assertSame($appDebug, $kernelParams['kernel.debug'], 'kernel.debug установился неправильно.');
107+
$this->assertSame(
108+
$expectedResult,
109+
$kernelParams['kernel.environment'],
110+
'kernel.environment установился неправильно.'
111+
);
112+
}
113+
114+
/**
115+
* @return array[]
116+
*/
117+
public function dataProviderDebugEnv() : array
118+
{
119+
return [
120+
[false, true, 'dev', 'dev'],
121+
[true, true, 'test', 'test'],
122+
[false, true, 'test', 'test'],
123+
[true, false, 'prod', 'prod'],
124+
];
125+
}
126+
66127
/**
67128
* @return void
68129
* @throws Exception

0 commit comments

Comments
 (0)