doge 9 godzin temu
rodzic
commit
fdc626518d

+ 1 - 8
app/Helpers/helpers.php

@@ -15,13 +15,6 @@ function create_password(string $plaintext, string $salt = 'likeadmin') : string
     return md5($salt . md5($plaintext . $salt));
 }
 
-if (!function_exists('env')) {
-    function env($key, $default = null)
-    {
-        return env($key, $default); // 直接使用 Laravel 全局 env() 函数
-    }
-}
-
 /**
  * 格式化小数:去掉末尾无用的0,但至少保留1位小数
  * @param float|string $number 要格式化的数字
@@ -46,7 +39,7 @@ function formatDecimal($number, $len = 1)
  */
 function create_token(string $extra = '')
 {
-    $salt = env('unique_identification', 'likeadmin');
+    $salt = config('app.unique_identification', 'likeadmin');
     $encryptSalt = md5( $salt . uniqid());
     return md5($salt . $extra . time() . $encryptSalt);
 }

+ 1 - 1
app/Http/Controllers/admin/Wallet.php

@@ -457,7 +457,7 @@ class Wallet extends Controller
             $result = RechargeService::paginate($search);
             foreach($result['data'] as &$item) {
                 if ($item['from'] == 2) {
-                    $item['image'] = str_replace(env('APP_URL'), env('FOOTBALL_APP_URL').'/', $item['image']);
+                    $item['image'] = str_replace(config('app.url'), config('app.football_url').'/', $item['image']);
                 }
             }
         } catch (ValidationException $e) {

+ 2 - 2
app/Services/BetService.php

@@ -1108,7 +1108,7 @@ class BetService extends BaseService
             }
 
             //根据环境变量配置是否发送电报
-            if ($v['is_send'] && env('SEND_TELEGRAM')) {
+            if ($v['is_send'] && config('services.telegram.send_enabled', false)) {
                 $language = User::where('member_id', $v['member_id'])->first()->language;
                 $wallet = WalletService::findOne(['member_id' => $v['member_id']]);
                 App::setLocale($language);
@@ -1137,7 +1137,7 @@ class BetService extends BaseService
         $inlineButton = self::getOperateButton();
         
         //根据环境变量配置是否发送电报
-        if (env('SEND_TELEGRAM')) {
+        if (config('services.telegram.send_enabled', false)) {
             // 群通知
             $pc28Switch = Config::where('field', 'pc28_switch')->first()->val;
             if (($pc28Switch == 0 && is_numeric($issue_no)) || $pc28Switch == 1 && !is_numeric($issue_no)) {

+ 2 - 2
app/Services/PcIssueService.php

@@ -229,7 +229,7 @@ class PcIssueService extends BaseService
             }
 
             //开发环境不生成开奖图片
-            if (env('APP_ENV') != 'local') {
+            if (config('app.env') != 'local') {
                 $recordImage = self::lotteryImage($info->issue_no);
                 if ($recordImage) {
                     if ($pc28Switch == 1) SendTelegramGroupMessageJob::dispatch('', [], url($recordImage), false);
@@ -419,4 +419,4 @@ class PcIssueService extends BaseService
         // TODO: Implement getWhere() method.
         return [];
     }
-}
+}

+ 8 - 8
app/Services/SportClientService.php

@@ -12,11 +12,11 @@ class SportClientService
     public static function get($type, $endpoint, $params = [])
     {
         if ($type == 1) {
-            $host = env('API_FOOTBALL_HOST');
-            $key = env('API_FOOTBALL_KEY');
+            $host = config('services.sport.football.host');
+            $key = config('services.sport.football.key');
         } elseif ($type == 2) {
-            $host = env('API_BASKETBALL_HOST');
-            $key = env('API_BASKETBALL_KEY');
+            $host = config('services.sport.basketball.host');
+            $key = config('services.sport.basketball.key');
         } else {
             throw new \Exception("Invalid sport type");
         }
@@ -37,11 +37,11 @@ class SportClientService
     public static function post($type, $endpoint, $data = [])
     {
         if ($type == 1) {
-            $host = env('API_FOOTBALL_HOST');
-            $key = env('API_FOOTBALL_KEY');
+            $host = config('services.sport.football.host');
+            $key = config('services.sport.football.key');
         } elseif ($type == 2) {
-            $host = env('API_BASKETBALL_HOST');
-            $key = env('API_BASKETBALL_KEY');
+            $host = config('services.sport.basketball.host');
+            $key = config('services.sport.basketball.key');
         } else {
             throw new \Exception("Invalid sport type");
         }

+ 2 - 0
config/app.php

@@ -98,11 +98,13 @@ return [
 
 //    'url' => (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http') . '://' . (isset($_SERVER['HTTP_HOST'])?$_SERVER['HTTP_HOST']:'localhost'),
     'url' => env('APP_URL', ''),
+    'football_url' => env('FOOTBALL_APP_URL', ''),
     'asset_url' => env('ASSET_URL'),
 
 
     'jwt_secret' => env('JWT_SECRET', '881FrcXs'),
     'jwt_exp' => env('JWT_EXP', 86400),
+    'unique_identification' => env('unique_identification', 'likeadmin'),
 
     /*
     |--------------------------------------------------------------------------

+ 12 - 0
config/services.php

@@ -9,6 +9,7 @@ return [
     ],
 
     'telegram' => [
+        'send_enabled' => env('SEND_TELEGRAM', false),
         'token' => env('TELEGRAM_BOT_TOKEN'),
         'username' => env('TELEGRAM_BOT_USERNAME'),
         'retry_attempts' => env('TELEGRAM_RETRY_ATTEMPTS', 2),
@@ -71,6 +72,17 @@ return [
         'verify_receipt_uri' => env('APPLE_VERIFY_RECEIPT_URI', ''),
     ],
 
+    'sport' => [
+        'football' => [
+            'host' => env('API_FOOTBALL_HOST'),
+            'key' => env('API_FOOTBALL_KEY'),
+        ],
+        'basketball' => [
+            'host' => env('API_BASKETBALL_HOST'),
+            'key' => env('API_BASKETBALL_KEY'),
+        ],
+    ],
+
     'lottery_image' => [
         'binary' => env('LOTTERY_IMAGE_BINARY', 'wkhtmltoimage'),
         'timeout' => env('LOTTERY_IMAGE_TIMEOUT', 20),

+ 134 - 0
tests/Unit/RuntimeConfigurationCacheTest.php

@@ -0,0 +1,134 @@
+<?php
+
+namespace Tests\Unit;
+
+use App\Services\SportClientService;
+use Illuminate\Container\Container;
+use Illuminate\Filesystem\Filesystem;
+use Illuminate\Foundation\Application;
+use Illuminate\Foundation\Bootstrap\LoadConfiguration;
+use Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables;
+use Illuminate\Http\Client\Factory;
+use Illuminate\Http\Client\Request;
+use Illuminate\Support\Env;
+use Illuminate\Support\Facades\Facade;
+use Illuminate\Support\Facades\Http;
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\PreserveGlobalState;
+use PHPUnit\Framework\Attributes\RunInSeparateProcess;
+use PHPUnit\Framework\TestCase;
+
+class RuntimeConfigurationCacheTest extends TestCase
+{
+    private string $temporaryRoot;
+
+    private const ENVIRONMENT = [
+        'APP_ENV' => 'local',
+        'APP_URL' => 'https://app.example.test',
+        'FOOTBALL_APP_URL' => 'https://football-app.example.test',
+        'API_FOOTBALL_HOST' => 'https://football.example.test',
+        'API_FOOTBALL_KEY' => 'football-test-key',
+        'API_BASKETBALL_HOST' => 'https://basketball.example.test',
+        'API_BASKETBALL_KEY' => 'basketball-test-key',
+        'SEND_TELEGRAM' => 'true',
+        'unique_identification' => 'custom-test-salt',
+    ];
+
+    protected function tearDown(): void
+    {
+        Facade::clearResolvedInstances();
+        Facade::setFacadeApplication(null);
+        Container::setInstance(null);
+        if (isset($this->temporaryRoot)) {
+            (new Filesystem())->deleteDirectory($this->temporaryRoot);
+        }
+        parent::tearDown();
+    }
+
+    public static function configurationModes(): array
+    {
+        return [
+            'uncached, telegram enabled' => [false, true],
+            'cached, telegram enabled' => [true, true],
+            'cached, telegram disabled' => [true, false],
+        ];
+    }
+
+    #[DataProvider('configurationModes')]
+    #[RunInSeparateProcess]
+    #[PreserveGlobalState(false)]
+    public function test_runtime_configuration_survives_caching(bool $cached, bool $sendTelegram): void
+    {
+        // Bootstrap only configuration in a temporary application, without project providers or .env.
+        $this->temporaryRoot = sys_get_temp_dir() . '/runtime-config-test-' . bin2hex(random_bytes(8));
+        mkdir($this->temporaryRoot . '/config', 0700, true);
+        mkdir($this->temporaryRoot . '/bootstrap/cache', 0700, true);
+        foreach (['app', 'services'] as $file) {
+            copy(dirname(__DIR__, 2) . '/config/' . $file . '.php', $this->temporaryRoot . '/config/' . $file . '.php');
+        }
+        $environment = array_replace(self::ENVIRONMENT, ['SEND_TELEGRAM' => $sendTelegram ? 'true' : 'false']);
+        $contents = '';
+        foreach ($environment as $key => $value) {
+            $contents .= $key . '=' . $value . PHP_EOL;
+        }
+        file_put_contents($this->temporaryRoot . '/.env', $contents);
+        $this->clearEnvironment();
+        $app = $this->bootConfiguration();
+
+        if ($cached) {
+            // Use the same serialized config format as config:cache, then start with a fresh environment.
+            file_put_contents($app->getCachedConfigPath(), '<?php return ' . var_export($app['config']->all(), true) . ';');
+            $this->clearEnvironment();
+            $app = $this->bootConfiguration();
+            foreach (array_keys(self::ENVIRONMENT) as $key) {
+                $this->assertNull(env($key), 'Cached bootstrap must skip loading ' . $key . ' from .env');
+            }
+        }
+
+        $this->assertSame($cached, $app['config_loaded_from_cache']);
+        $this->assertSame('local', config('app.env'));
+        $this->assertSame('https://app.example.test', config('app.url'));
+        $this->assertSame('https://football-app.example.test', config('app.football_url'));
+        $this->assertSame('custom-test-salt', config('app.unique_identification'));
+        $this->assertSame($sendTelegram, config('services.telegram.send_enabled'));
+
+        $app->instance(Factory::class, new Factory());
+        Facade::clearResolvedInstances();
+        Facade::setFacadeApplication($app);
+        Http::preventStrayRequests();
+        Http::fake(['*' => Http::response(['response' => []])]);
+
+        foreach ([1 => 'football', 2 => 'basketball'] as $type => $sport) {
+            $endpoint = $type === 1 ? 'fixtures' : 'games';
+            foreach (['get', 'post'] as $method) {
+                $params = ['live' => 'all'];
+                $this->assertSame(['response' => []], SportClientService::$method($type, $endpoint, $params));
+                Http::assertSent(fn (Request $request) =>
+                    $request->method() === strtoupper($method)
+                    && strtok($request->url(), '?') === 'https://' . $sport . '.example.test/' . $endpoint
+                    && $request->hasHeader('x-apisports-key', $sport . '-test-key')
+                    && $request->data() === $params
+                );
+            }
+        }
+        Http::assertSentCount(4);
+    }
+
+    private function bootConfiguration(): Application
+    {
+        $app = new Application($this->temporaryRoot);
+        (new LoadEnvironmentVariables())->bootstrap($app);
+        (new LoadConfiguration())->bootstrap($app);
+
+        return $app;
+    }
+
+    private function clearEnvironment(): void
+    {
+        foreach (array_merge(array_keys(self::ENVIRONMENT), ['APP_CONFIG_CACHE']) as $key) {
+            unset($_ENV[$key], $_SERVER[$key]);
+            putenv($key);
+        }
+        Env::enablePutenv();
+    }
+}