mirror of
https://gitee.com/hyperf/hyperf.git
synced 2024-11-29 18:27:44 +08:00
Support to reload .env
when using hyperf/watcher
. (#6936)
Co-authored-by: 李铭昕 <715557344@qq.com>
This commit is contained in:
parent
2bacaf3233
commit
3bca85b652
1
.gitignore
vendored
1
.gitignore
vendored
@ -18,3 +18,4 @@ node_modules/*
|
|||||||
.bashrc
|
.bashrc
|
||||||
/phpstan.neon
|
/phpstan.neon
|
||||||
/phpunit.xml
|
/phpunit.xml
|
||||||
|
!/src/support/tests/envs/**/*.env
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
# v3.1.31 - TBD
|
# v3.1.31 - TBD
|
||||||
|
|
||||||
|
## Added
|
||||||
|
|
||||||
|
- [#6936](https://github.com/hyperf/hyperf/pull/6936) Support to reload `.env` when using `hyperf/watcher`.
|
||||||
|
|
||||||
# v3.1.30 - 2024-07-05
|
# v3.1.30 - 2024-07-05
|
||||||
|
|
||||||
## Fixed
|
## Fixed
|
||||||
|
@ -21,6 +21,7 @@ use Hyperf\Di\LazyLoader\LazyLoader;
|
|||||||
use Hyperf\Di\ScanHandler\PcntlScanHandler;
|
use Hyperf\Di\ScanHandler\PcntlScanHandler;
|
||||||
use Hyperf\Di\ScanHandler\ScanHandlerInterface;
|
use Hyperf\Di\ScanHandler\ScanHandlerInterface;
|
||||||
use Hyperf\Support\Composer;
|
use Hyperf\Support\Composer;
|
||||||
|
use Hyperf\Support\DotenvManager;
|
||||||
|
|
||||||
class ClassLoader
|
class ClassLoader
|
||||||
{
|
{
|
||||||
@ -43,7 +44,7 @@ class ClassLoader
|
|||||||
$composerLoader = Composer::getLoader();
|
$composerLoader = Composer::getLoader();
|
||||||
|
|
||||||
if (file_exists(BASE_PATH . '/.env')) {
|
if (file_exists(BASE_PATH . '/.env')) {
|
||||||
static::loadDotenv();
|
DotenvManager::load([BASE_PATH]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan by ScanConfig to generate the reflection class map
|
// Scan by ScanConfig to generate the reflection class map
|
||||||
@ -59,6 +60,10 @@ class ClassLoader
|
|||||||
LazyLoader::bootstrap($configDir);
|
LazyLoader::bootstrap($configDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DotenvManager::load()
|
||||||
|
* @deprecated use DotenvManager instead
|
||||||
|
*/
|
||||||
protected static function loadDotenv(): void
|
protected static function loadDotenv(): void
|
||||||
{
|
{
|
||||||
$repository = RepositoryBuilder::createWithNoAdapters()
|
$repository = RepositoryBuilder::createWithNoAdapters()
|
||||||
|
@ -24,10 +24,6 @@ use function Hyperf\Support\env;
|
|||||||
* @coversNothing
|
* @coversNothing
|
||||||
*/
|
*/
|
||||||
#[CoversNothing]
|
#[CoversNothing]
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
* @coversNothing
|
|
||||||
*/
|
|
||||||
class ClassLoaderTest extends TestCase
|
class ClassLoaderTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testDotEnv()
|
public function testDotEnv()
|
||||||
|
75
src/support/src/DotenvManager.php
Normal file
75
src/support/src/DotenvManager.php
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* This file is part of Hyperf.
|
||||||
|
*
|
||||||
|
* @link https://www.hyperf.io
|
||||||
|
* @document https://hyperf.wiki
|
||||||
|
* @contact group@hyperf.io
|
||||||
|
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Hyperf\Support;
|
||||||
|
|
||||||
|
use Dotenv\Dotenv;
|
||||||
|
use Dotenv\Repository\Adapter\AdapterInterface;
|
||||||
|
use Dotenv\Repository\Adapter\PutenvAdapter;
|
||||||
|
use Dotenv\Repository\RepositoryBuilder;
|
||||||
|
|
||||||
|
class DotenvManager
|
||||||
|
{
|
||||||
|
protected static AdapterInterface $adapter;
|
||||||
|
|
||||||
|
protected static Dotenv $dotenv;
|
||||||
|
|
||||||
|
protected static array $cachedValues;
|
||||||
|
|
||||||
|
public static function load(array $paths): void
|
||||||
|
{
|
||||||
|
if (isset(static::$cachedValues)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static::$cachedValues = static::getDotenv($paths)->load();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function reload(array $paths, bool $force = false): void
|
||||||
|
{
|
||||||
|
if (! isset(static::$cachedValues)) {
|
||||||
|
static::load($paths);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (static::$cachedValues as $deletedEntry => $value) {
|
||||||
|
static::getAdapter()->delete($deletedEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static::$cachedValues = static::getDotenv($paths, $force)->load();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function getDotenv(array $paths, bool $force = false): Dotenv
|
||||||
|
{
|
||||||
|
if (isset(static::$dotenv) && ! $force) {
|
||||||
|
return static::$dotenv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return static::$dotenv = Dotenv::create(
|
||||||
|
RepositoryBuilder::createWithNoAdapters()
|
||||||
|
->addAdapter(static::getAdapter($force))
|
||||||
|
->immutable()
|
||||||
|
->make(),
|
||||||
|
$paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function getAdapter(bool $force = false): AdapterInterface
|
||||||
|
{
|
||||||
|
if (isset(static::$adapter) && ! $force) {
|
||||||
|
return static::$adapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
return static::$adapter = PutenvAdapter::create()->get();
|
||||||
|
}
|
||||||
|
}
|
54
src/support/tests/DotenvManagerTest.php
Normal file
54
src/support/tests/DotenvManagerTest.php
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* This file is part of Hyperf.
|
||||||
|
*
|
||||||
|
* @link https://www.hyperf.io
|
||||||
|
* @document https://hyperf.wiki
|
||||||
|
* @contact group@hyperf.io
|
||||||
|
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace HyperfTest\Support;
|
||||||
|
|
||||||
|
use Hyperf\Support\DotenvManager;
|
||||||
|
use PHPUnit\Framework\Attributes\CoversNothing;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
use function Hyperf\Support\env;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* @coversNothing
|
||||||
|
*/
|
||||||
|
#[CoversNothing]
|
||||||
|
class DotenvManagerTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testLoad()
|
||||||
|
{
|
||||||
|
DotenvManager::load([__DIR__ . '/envs/oldEnv']);
|
||||||
|
|
||||||
|
$this->assertEquals('1.0', env('TEST_VERSION'));
|
||||||
|
$this->assertTrue(env('OLD_FLAG'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testReload()
|
||||||
|
{
|
||||||
|
DotenvManager::load([__DIR__ . '/envs/oldEnv']);
|
||||||
|
$this->assertEquals('1.0', env('TEST_VERSION'));
|
||||||
|
$this->assertTrue(env('OLD_FLAG'));
|
||||||
|
|
||||||
|
DotenvManager::reload([__DIR__ . '/envs/newEnv'], true);
|
||||||
|
$this->assertEquals('2.0', env('TEST_VERSION'));
|
||||||
|
$this->assertNull(env('OLD_FLAG'));
|
||||||
|
$this->assertTrue(env('NEW_FLAG'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetEnvFromEnvironment()
|
||||||
|
{
|
||||||
|
DotenvManager::load([__DIR__ . '/envs/oldEnv']);
|
||||||
|
|
||||||
|
$this->assertNotEquals('0.0.0', env('SW_VERSION'));
|
||||||
|
}
|
||||||
|
}
|
3
src/support/tests/envs/newEnv/.env
Normal file
3
src/support/tests/envs/newEnv/.env
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
TEST_VERSION=2.0
|
||||||
|
NEW_FLAG=true
|
||||||
|
SW_VERSION="0.0.0"
|
3
src/support/tests/envs/oldEnv/.env
Normal file
3
src/support/tests/envs/oldEnv/.env
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
TEST_VERSION=1.0
|
||||||
|
OLD_FLAG=true
|
||||||
|
SW_VERSION="0.0.0"
|
@ -13,6 +13,7 @@ declare(strict_types=1);
|
|||||||
namespace Hyperf\Watcher;
|
namespace Hyperf\Watcher;
|
||||||
|
|
||||||
use Hyperf\Watcher\Command\WatchCommand;
|
use Hyperf\Watcher\Command\WatchCommand;
|
||||||
|
use Hyperf\Watcher\Listener\ReloadDotenvAndConfigListener;
|
||||||
|
|
||||||
class ConfigProvider
|
class ConfigProvider
|
||||||
{
|
{
|
||||||
@ -24,6 +25,9 @@ class ConfigProvider
|
|||||||
'commands' => [
|
'commands' => [
|
||||||
WatchCommand::class,
|
WatchCommand::class,
|
||||||
],
|
],
|
||||||
|
'listeners' => [
|
||||||
|
ReloadDotenvAndConfigListener::class,
|
||||||
|
],
|
||||||
'publish' => [
|
'publish' => [
|
||||||
[
|
[
|
||||||
'id' => 'config',
|
'id' => 'config',
|
||||||
|
20
src/watcher/src/Event/BeforeServerRestart.php
Normal file
20
src/watcher/src/Event/BeforeServerRestart.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* This file is part of Hyperf.
|
||||||
|
*
|
||||||
|
* @link https://www.hyperf.io
|
||||||
|
* @document https://hyperf.wiki
|
||||||
|
* @contact group@hyperf.io
|
||||||
|
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Hyperf\Watcher\Event;
|
||||||
|
|
||||||
|
class BeforeServerRestart
|
||||||
|
{
|
||||||
|
public function __construct(public string $pid)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
69
src/watcher/src/Listener/ReloadDotenvAndConfigListener.php
Normal file
69
src/watcher/src/Listener/ReloadDotenvAndConfigListener.php
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* This file is part of Hyperf.
|
||||||
|
*
|
||||||
|
* @link https://www.hyperf.io
|
||||||
|
* @document https://hyperf.wiki
|
||||||
|
* @contact group@hyperf.io
|
||||||
|
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Hyperf\Watcher\Listener;
|
||||||
|
|
||||||
|
use Hyperf\Contract\ConfigInterface;
|
||||||
|
use Hyperf\Event\Contract\ListenerInterface;
|
||||||
|
use Hyperf\Framework\Event\BeforeWorkerStart;
|
||||||
|
use Hyperf\Support\DotenvManager;
|
||||||
|
use Hyperf\Watcher\Event\BeforeServerRestart;
|
||||||
|
use Psr\Container\ContainerInterface;
|
||||||
|
use Swoole\Atomic;
|
||||||
|
|
||||||
|
class ReloadDotenvAndConfigListener implements ListenerInterface
|
||||||
|
{
|
||||||
|
protected static Atomic $restartCounter;
|
||||||
|
|
||||||
|
public function __construct(protected ContainerInterface $container)
|
||||||
|
{
|
||||||
|
static::$restartCounter = new Atomic(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function listen(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
BeforeWorkerStart::class,
|
||||||
|
BeforeServerRestart::class,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function process(object $event): void
|
||||||
|
{
|
||||||
|
if ($event instanceof BeforeWorkerStart
|
||||||
|
&& $event->workerId === 0
|
||||||
|
&& static::$restartCounter->get() === 0
|
||||||
|
) {
|
||||||
|
static::$restartCounter->add();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static::$restartCounter->add();
|
||||||
|
|
||||||
|
$this->reloadDotenv();
|
||||||
|
$this->reloadConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function reloadConfig(): void
|
||||||
|
{
|
||||||
|
if (! method_exists($this->container, 'unbind')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->container->unbind(ConfigInterface::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function reloadDotenv(): void
|
||||||
|
{
|
||||||
|
DotenvManager::reload([BASE_PATH]);
|
||||||
|
}
|
||||||
|
}
|
@ -20,8 +20,10 @@ use Hyperf\Support\Exception\InvalidArgumentException;
|
|||||||
use Hyperf\Support\Filesystem\FileNotFoundException;
|
use Hyperf\Support\Filesystem\FileNotFoundException;
|
||||||
use Hyperf\Support\Filesystem\Filesystem;
|
use Hyperf\Support\Filesystem\Filesystem;
|
||||||
use Hyperf\Watcher\Driver\DriverInterface;
|
use Hyperf\Watcher\Driver\DriverInterface;
|
||||||
|
use Hyperf\Watcher\Event\BeforeServerRestart;
|
||||||
use PhpParser\PrettyPrinter\Standard;
|
use PhpParser\PrettyPrinter\Standard;
|
||||||
use Psr\Container\ContainerInterface;
|
use Psr\Container\ContainerInterface;
|
||||||
|
use Psr\EventDispatcher\EventDispatcherInterface;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
|
||||||
@ -109,6 +111,8 @@ class Watcher
|
|||||||
$pid = $this->filesystem->get($file);
|
$pid = $this->filesystem->get($file);
|
||||||
try {
|
try {
|
||||||
$this->output->writeln('Stop server...');
|
$this->output->writeln('Stop server...');
|
||||||
|
$this->container->get(EventDispatcherInterface::class)
|
||||||
|
->dispatch(new BeforeServerRestart($pid));
|
||||||
if (posix_kill((int) $pid, 0)) {
|
if (posix_kill((int) $pid, 0)) {
|
||||||
posix_kill((int) $pid, SIGTERM);
|
posix_kill((int) $pid, SIGTERM);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user