Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[10.x] Optimize Laravel Configuration Loading Process #49313

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 109 additions & 3 deletions src/Illuminate/Config/Repository.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Illuminate\Config;

use ArrayAccess;
use Exception;
use Illuminate\Contracts\Config\Repository as ConfigContract;
use Illuminate\Support\Arr;
use Illuminate\Support\Traits\Macroable;
Expand All @@ -18,15 +19,40 @@ class Repository implements ArrayAccess, ConfigContract
*/
protected $items = [];

/**
* Configs loaded from cache.
*
* @var bool
*/
private bool $loadedFromCache = false;

/**
* Path of configuration files.
*
* @var string
*/
private string $configPath;

/**
* Create a new configuration repository.
*
* @param array $items
* @return void
* @param string $configPath
*
* @throws Exception
*/
public function __construct(array $items = [])
public function __construct(array $items = [], string $configPath = 'test')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a breaking change and would require targeting Laravel 11 (master branch)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is not considered a breaking change, and it could be integrated into Laravel 10 without causing fundamental issues. More substantial changes are feasible for Laravel 11 if needed.

{
$this->items = $items;
$this->configPath = $configPath;

if ($items) {
$this->items = $items;
$this->loadedFromCache = true;
}

if (! $configPath == 'test' && ! $this->get('app')) {
throw new Exception('Unable to load the "app" configuration file.');
}
}

/**
Expand All @@ -37,9 +63,34 @@ public function __construct(array $items = [])
*/
public function has($key)
{
if (is_array($key)) {
return $this->hasMany($key);
}

$this->load($key);

return Arr::has($this->items, $key);
}

/**
* Check many keys has on configuration items.
* this added for load file before checking.
*
* @param array $keys
* @return bool
*/
public function hasMany(array $keys): bool
{
foreach ($keys as $key) {
$this->load($key);
if (! Arr::has($this->items, $key)) {
return false;
}
}

return true;
}

/**
* Get the specified configuration value.
*
Expand All @@ -53,6 +104,8 @@ public function get($key, $default = null)
return $this->getMany($key);
}

$this->load($key);

return Arr::get($this->items, $key, $default);
}

Expand All @@ -71,6 +124,7 @@ public function getMany($keys)
[$key, $default] = [$default, null];
}

$this->load($key);
$config[$key] = Arr::get($this->items, $key, $default);
}

Expand All @@ -89,6 +143,7 @@ public function set($key, $value = null)
$keys = is_array($key) ? $key : [$key => $value];

foreach ($keys as $key => $value) {
$this->load($key);
Arr::set($this->items, $key, $value);
}
}
Expand Down Expand Up @@ -179,4 +234,55 @@ public function offsetUnset($key): void
{
$this->set($key, null);
}

/**
* Load config file when not loaded or cache not loaded.
*
* @param string|int $key
* @return void
*/
private function load($key): void
{
if (! $this->loadedFromCache && (is_string($key) || is_int($key)) && $file = $this->getConfigurationFile(''.$key)) {
if (! Arr::has($this->items, $file[0])) {
Arr::set($this->items, $file[0], require $file[1]);
}
}
}

/**
* Get config file key and file path.
*
* @param string $key
* @param string $fileKey
* @param string|null $configPath
* @return array
*/
private function getConfigurationFile(string $key, string $fileKey = '', string $configPath = null): array
{
$aKey = explode('.', $key, 2);

if (! $configPath) {
$configPath = realpath($this->configPath);
}

$fileKey .= $fileKey ? '.'.$aKey[0] : $aKey[0];
$directory = $configPath.DIRECTORY_SEPARATOR.$aKey[0];

//this for check on nests directories
if (count($aKey) > 1 && is_dir($directory) && $file = $this->getConfigurationFile($aKey[1], $fileKey, $directory)) {
//This part is for when we have a directory and a file
// with the same name, the file is loaded first and
// then the files inside the folder are loaded.
if (is_file($directory.'.php')) {
$this->load($fileKey);
}

return $file;
} elseif (is_file($directory.'.php')) {
return [$fileKey, $directory.'.php'];
}

return [];
}
}
39 changes: 22 additions & 17 deletions src/Illuminate/Foundation/Bootstrap/LoadConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ class LoadConfiguration
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @return void
*
* @throws \Exception
*/
public function bootstrap(Application $app)
{
Expand All @@ -27,17 +29,19 @@ public function bootstrap(Application $app)
if (file_exists($cached = $app->getCachedConfigPath())) {
$items = require $cached;

$loadedFromCache = true;
// $loadedFromCache = true;
}

// 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)) {
$this->loadConfigurationFiles($app, $config);
}
// ...
// Repository changed for load as needed configs
$app->instance('config', $config = new Repository($items, $app->configPath()));
// Load all config in boot removed, no need
// if (! isset($loadedFromCache)) {
// $this->loadConfigurationFiles($app, $config);
// }

// Finally, we will set the application's environment based on the configuration
// values that were loaded. We will pass a callback which will be used to get
Expand All @@ -55,20 +59,20 @@ public function bootstrap(Application $app)
* @param \Illuminate\Contracts\Foundation\Application $app
* @param \Illuminate\Contracts\Config\Repository $repository
* @return void
*
* @throws \Exception
*/
protected function loadConfigurationFiles(Application $app, RepositoryContract $repository)
public function loadConfigurationFiles(Application $app, RepositoryContract $repository)
{
$files = $this->getConfigurationFiles($app);

if (! isset($files['app'])) {
throw new Exception('Unable to load the "app" configuration file.');
}
// if (!isset($files['app'])) {
// throw new Exception('Unable to load the "app" configuration file.');
// }

foreach ($files as $key => $path) {
$repository->set($key, require $path);
}
// foreach ($files as $key => $path) {
// $repository->set($key, require $path);
// }

$repository->get($files);
}

/**
Expand All @@ -86,10 +90,11 @@ protected function getConfigurationFiles(Application $app)
foreach (Finder::create()->files()->name('*.php')->in($configPath) as $file) {
$directory = $this->getNestedDirectory($file, $configPath);

$files[$directory.basename($file->getRealPath(), '.php')] = $file->getRealPath();
//$files[$directory . basename($file->getRealPath(), '.php')] = $file->getRealPath();
$files[] = $directory.basename($file->getRealPath(), '.php');
}

ksort($files, SORT_NATURAL);
//ksort($files, SORT_NATURAL);

return $files;
}
Expand Down
6 changes: 5 additions & 1 deletion src/Illuminate/Foundation/Console/ConfigCacheCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
namespace Illuminate\Foundation\Console;

use Illuminate\Console\Command;
use Illuminate\Contracts\Config\Repository as RepositoryContract;
use Illuminate\Contracts\Console\Kernel as ConsoleKernelContract;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Foundation\Bootstrap\LoadConfiguration;
use LogicException;
use Symfony\Component\Console\Attribute\AsCommand;
use Throwable;
Expand Down Expand Up @@ -77,7 +79,7 @@ public function handle()
}

/**
* Boot a fresh copy of the application configuration.
* Boot a fresh copy all of the application configuration.
*
* @return array
*/
Expand All @@ -89,6 +91,8 @@ protected function getFreshConfiguration()

$app->make(ConsoleKernelContract::class)->bootstrap();

$app->make(LoadConfiguration::class)->loadConfigurationFiles($app, $app->make(RepositoryContract::class));

return $app['config']->all();
}
}