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
|
||||
/phpstan.neon
|
||||
/phpunit.xml
|
||||
!/src/support/tests/envs/**/*.env
|
||||
|
@ -1,5 +1,9 @@
|
||||
# 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
|
||||
|
||||
## Fixed
|
||||
|
@ -21,6 +21,7 @@ use Hyperf\Di\LazyLoader\LazyLoader;
|
||||
use Hyperf\Di\ScanHandler\PcntlScanHandler;
|
||||
use Hyperf\Di\ScanHandler\ScanHandlerInterface;
|
||||
use Hyperf\Support\Composer;
|
||||
use Hyperf\Support\DotenvManager;
|
||||
|
||||
class ClassLoader
|
||||
{
|
||||
@ -43,7 +44,7 @@ class ClassLoader
|
||||
$composerLoader = Composer::getLoader();
|
||||
|
||||
if (file_exists(BASE_PATH . '/.env')) {
|
||||
static::loadDotenv();
|
||||
DotenvManager::load([BASE_PATH]);
|
||||
}
|
||||
|
||||
// Scan by ScanConfig to generate the reflection class map
|
||||
@ -59,6 +60,10 @@ class ClassLoader
|
||||
LazyLoader::bootstrap($configDir);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DotenvManager::load()
|
||||
* @deprecated use DotenvManager instead
|
||||
*/
|
||||
protected static function loadDotenv(): void
|
||||
{
|
||||
$repository = RepositoryBuilder::createWithNoAdapters()
|
||||
|
@ -24,10 +24,6 @@ use function Hyperf\Support\env;
|
||||
* @coversNothing
|
||||
*/
|
||||
#[CoversNothing]
|
||||
/**
|
||||
* @internal
|
||||
* @coversNothing
|
||||
*/
|
||||
class ClassLoaderTest extends TestCase
|
||||
{
|
||||
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;
|
||||
|
||||
use Hyperf\Watcher\Command\WatchCommand;
|
||||
use Hyperf\Watcher\Listener\ReloadDotenvAndConfigListener;
|
||||
|
||||
class ConfigProvider
|
||||
{
|
||||
@ -24,6 +25,9 @@ class ConfigProvider
|
||||
'commands' => [
|
||||
WatchCommand::class,
|
||||
],
|
||||
'listeners' => [
|
||||
ReloadDotenvAndConfigListener::class,
|
||||
],
|
||||
'publish' => [
|
||||
[
|
||||
'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\Filesystem;
|
||||
use Hyperf\Watcher\Driver\DriverInterface;
|
||||
use Hyperf\Watcher\Event\BeforeServerRestart;
|
||||
use PhpParser\PrettyPrinter\Standard;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Throwable;
|
||||
|
||||
@ -109,6 +111,8 @@ class Watcher
|
||||
$pid = $this->filesystem->get($file);
|
||||
try {
|
||||
$this->output->writeln('Stop server...');
|
||||
$this->container->get(EventDispatcherInterface::class)
|
||||
->dispatch(new BeforeServerRestart($pid));
|
||||
if (posix_kill((int) $pid, 0)) {
|
||||
posix_kill((int) $pid, SIGTERM);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user