diff --git a/src/Illuminate/Foundation/Bootstrap/LoadConfiguration.php b/src/Illuminate/Foundation/Bootstrap/LoadConfiguration.php index 4c5f00e9a2c0..37229ac41a6a 100644 --- a/src/Illuminate/Foundation/Bootstrap/LoadConfiguration.php +++ b/src/Illuminate/Foundation/Bootstrap/LoadConfiguration.php @@ -2,6 +2,7 @@ namespace Illuminate\Foundation\Bootstrap; +use Closure; use Illuminate\Config\Repository; use Illuminate\Contracts\Config\Repository as RepositoryContract; use Illuminate\Contracts\Foundation\Application; @@ -11,6 +12,13 @@ class LoadConfiguration { + /** + * The closure that resolves the permanent, static configuration if applicable. + * + * @var (Closure(Application): array)|null + */ + protected static ?Closure $alwaysUseConfig = null; + /** * Bootstrap the given application. * @@ -24,18 +32,26 @@ public function bootstrap(Application $app) // First we will see if we have a cache configuration file. If we do, we'll load // the configuration items from that file so that it is very quick. Otherwise // we will need to spin through every configuration file and load them all. - if (file_exists($cached = $app->getCachedConfigPath())) { + $loadedFromCache = false; + + if (self::$alwaysUseConfig !== null) { + $items = $app->call(self::$alwaysUseConfig); + + $loadedFromCache = true; + } elseif (file_exists($cached = $app->getCachedConfigPath())) { $items = require $cached; - $app->instance('config_loaded_from_cache', $loadedFromCache = true); + $loadedFromCache = true; } + $app->instance('config_loaded_from_cache', $loadedFromCache); + // Next we will spin through all of the configuration files in the configuration // directory and load each one into the repository. This will make all of the // options available to the developer for use in various parts of this app. $app->instance('config', $config = new Repository($items)); - if (! isset($loadedFromCache)) { + if (! $loadedFromCache) { $this->loadConfigurationFiles($app, $config); } @@ -195,4 +211,15 @@ protected function getBaseConfiguration() return $config; } + + /** + * Set a callback to return the permanent, static configuration values. + * + * @param (Closure(Application): array)|null $alwaysUseConfig + * @return void + */ + public static function alwaysUse(?Closure $alwaysUseConfig): void + { + static::$alwaysUseConfig = $alwaysUseConfig; + } } diff --git a/src/Illuminate/Foundation/Testing/CachedState.php b/src/Illuminate/Foundation/Testing/CachedState.php index 79cd3e0e906b..4ecb14cbb9b0 100644 --- a/src/Illuminate/Foundation/Testing/CachedState.php +++ b/src/Illuminate/Foundation/Testing/CachedState.php @@ -5,4 +5,5 @@ class CachedState { public static array $cachedRoutes; + public static array $cachedConfig; } diff --git a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithTestCaseLifecycle.php b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithTestCaseLifecycle.php index 0daabf1ce139..860c7a4b47f5 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithTestCaseLifecycle.php +++ b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithTestCaseLifecycle.php @@ -203,7 +203,7 @@ protected function tearDownTheTestEnvironment(): void */ protected function setUpTraits() { - $uses = array_flip(class_uses_recursive(static::class)); + $uses = $this->traitsUsedByTest ?? array_flip(class_uses_recursive(static::class)); if (isset($uses[RefreshDatabase::class])) { $this->refreshDatabase(); diff --git a/src/Illuminate/Foundation/Testing/TestCase.php b/src/Illuminate/Foundation/Testing/TestCase.php index dbf8bbd1a4ac..0b5acfd37662 100644 --- a/src/Illuminate/Foundation/Testing/TestCase.php +++ b/src/Illuminate/Foundation/Testing/TestCase.php @@ -20,6 +20,13 @@ abstract class TestCase extends BaseTestCase Concerns\InteractsWithTestCaseLifecycle, Concerns\InteractsWithViews; + /** + * The list of trait that this test uses, fetched recursively. + * + * @var array + */ + protected array $traitsUsedByTest; + /** * Creates the application. * @@ -29,8 +36,15 @@ public function createApplication() { $app = require Application::inferBasePath().'/bootstrap/app.php'; + $this->traitsUsedByTest = array_flip(class_uses_recursive(static::class)); + + if (isset(CachedState::$cachedConfig) && + isset($this->traitsUsedByTest[WithCachedConfig::class])) { + $this->markConfigCached($app); + } + if (isset(CachedState::$cachedRoutes) && - in_array(WithCachedRoutes::class, class_uses_recursive(static::class))) { + isset($this->traitsUsedByTest[WithCachedRoutes::class])) { $app->booting(fn () => $this->markRoutesCached($app)); } diff --git a/src/Illuminate/Foundation/Testing/WithCachedConfig.php b/src/Illuminate/Foundation/Testing/WithCachedConfig.php new file mode 100644 index 000000000000..41d0cdcae3ca --- /dev/null +++ b/src/Illuminate/Foundation/Testing/WithCachedConfig.php @@ -0,0 +1,41 @@ +app->make('config')->all(); + } + + $this->markConfigCached($this->app); + } + + /** + * Reset the cached configuration. + * + * This is helpful if some of the tests in the suite apply this trait while others do not. + */ + protected function tearDownWithCachedConfig(): void + { + LoadConfiguration::setAlwaysUseConfig(null); + } + + /** + * Inform the container that the configuration is cached. + */ + protected function markConfigCached(Application $app): void + { + $app->instance('config_loaded_from_cache', true); // I'm not sure this is actually needed + + LoadConfiguration::alwaysUse(static fn () => CachedState::$cachedConfig); + } +}