-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
What are Config Files and how do we improve Config? #7388
Comments
What if I want to use a value in the database for a config value? |
I don't think this is a bug, so shouldn't it be discussed in the forums? |
Config files are typically loaded before a database would be, so you hit issues there. |
I don't think most maintainers see the forum. And the source code is hard to read on the forum, and we can't just link to it and see the code like you can on GitHub. It's hard to have detailed discussions. |
Database seems working in |
IIRC it will work for some config files but not others. Whichever ones that the database layer might grab will cause an issue, and that's more than just the database config file. I've ran into this in the past and I don't remember which specific ones caused the issue.
The I recommending using CodeIgniter's official solution - Settings. :)
They will see it on Slack, though. We've always told people Issues are for bug reports, forum was for feature requests. |
First, I will give an example of Laravel.
There is an application ServiceProvider like AppServiceProvider. And in the AppServiceProvider::boot() method, you can add some logic that will definitely be called after the configs and before the request is processed. I want to say that for the problem you described, there are several ways to solve it. We need a class that will work in the same way as AppServiceProvider::boot() |
From my experience, I can say that the feedback from the CI team on the forum is close to zero. The only maintainer who is active is @kenjis . But as you can see, even he does not rely on the forum as a place for discussion. |
@iRedds My question is like this if using Laravel. |
I think it is better to use GitHub Discussions if you don't like to use GitHub IIssues. |
@kenjis I am not using Laravel. I look at its code base to understand how these or those solutions are implemented. // config myconfig.php
return [
'key' => 'default',
'key2' => 'default2'
];
// AppServiceProvider
public function boot(): void
{
// Here we override the config values, for example, by taking the values from the database.
config(['myconfig.key' => 'new value']);
// or for multiple keys
config(['myconfig' => ['key' => 'new ', 'key2' => 'new 2']]);
}
// using
Route::get('/', function () {
dd(config('myconfig'));
}); Now, by referring to the config, in the route we will receive the following data.
|
You can't, they are just simple arrays. You would need to do a separate layer, much like Settings does currently. f
That's why we have a Slack channel for the core team. Discussions could happen there and if there was a need for input on the forums we could be pointed that way with a Slack message. I just feel that if we have been telling users that Issues are for bugs, we should listen to that advice ourselves. |
Back to the original discussion, though:
We don't. There is no need for session with a config file, as a config file is intended to hold the settings that configure how the application works and not respond to each user's individual session settings.
I'm not opposed to going back to this for v5. We obviously cannot do it earlier. It would be lighter than the class-based configuration we currently use, and better for memory as optimized as PHPs arrays are now. I don't know how much the performance gains would be, compared to the database layer, which is our slowest part of the framework now, I believe. There are a few config classes that provide methods that would have to be moved elsewhere. To be honest, though, I've only ever heard a couple people mentioning it being an issue, so we would need to consider the pros/cons/cost in manpower, and I think it would be good to get a bigger set of opinions on the forums. There's probably several topics we should do that about so we can start actually planning for v5 more.
IIRC the loading of environment vars only happens once, and would still need to happen with an array-based config. I haven't measured the cost of looping over the class vars in each class, but I would be surprised if it was too onerous. Would be interesting to see benchmarking on that. |
It is possible to cache the database loaded configs? Edit: |
Sessions as an example. |
Why? This is my main question. After all, what is a config item and what is not? This is an example, but I don't think the requirement that if a locale is stored in the session and you want to set the locale based on that is so odd. And |
Supported locales is a static value. The current locale in the session is a dynamic value. Config files are typically for static values that don't depend on the current running state of the app. |
What is a static value and what is not? Then And even if |
@iRedds Thank you for showing. I want to do something like this. Then I can see what the value is just by looking at the config file. // config myconfig.php
$values = db_connect()->query()->...
return [
'key' => $values['key']',
'key2' => $values['key2']',
]; If |
Why does a database config solution have to be at the "config" level or even system level? As mentioned, we already provide a solution to this in the Settings library. @kenjis your examples are correct - and they would typically be handled by some other piece in the app layer, not in the config. I'm not aware of any framework that has dynamic config values like you're discussing here. it seems like most of this would be something that likely gets processed either in an Event, or a Filter (which can modify the request as needed). |
@kenjis In your example, you don't see values, only variables. Having access only to the project code, without a database, it will be difficult to understand what data the code operates on. In addition, it already looks more like some kind of library than a config. config without config file. It looks like some kind of perversion ) |
Simple benchmark to CI4 default Welcome page on my MacBook Air. Results:
Disable to load environment variables: --- a/system/Config/BaseConfig.php
+++ b/system/Config/BaseConfig.php
@@ -63,24 +63,24 @@ class BaseConfig
$this->registerProperties();
- $properties = array_keys(get_object_vars($this));
- $prefix = static::class;
- $slashAt = strrpos($prefix, '\\');
- $shortPrefix = strtolower(substr($prefix, $slashAt === false ? 0 : $slashAt + 1));
-
- foreach ($properties as $property) {
- $this->initEnvValue($this->{$property}, $property, $prefix, $shortPrefix);
-
- if ($this instanceof Encryption && $property === 'key') {
- if (strpos($this->{$property}, 'hex2bin:') === 0) {
- // Handle hex2bin prefix
- $this->{$property} = hex2bin(substr($this->{$property}, 8));
- } elseif (strpos($this->{$property}, 'base64:') === 0) {
- // Handle base64 prefix
- $this->{$property} = base64_decode(substr($this->{$property}, 7), true);
- }
- }
- }
+// $properties = array_keys(get_object_vars($this));
+// $prefix = static::class;
+// $slashAt = strrpos($prefix, '\\');
+// $shortPrefix = strtolower(substr($prefix, $slashAt === false ? 0 : $slashAt + 1));
+//
+// foreach ($properties as $property) {
+// $this->initEnvValue($this->{$property}, $property, $prefix, $shortPrefix);
+//
+// if ($this instanceof Encryption && $property === 'key') {
+// if (strpos($this->{$property}, 'hex2bin:') === 0) {
+// // Handle hex2bin prefix
+// $this->{$property} = hex2bin(substr($this->{$property}, 8));
+// } elseif (strpos($this->{$property}, 'base64:') === 0) {
+// // Handle base64 prefix
+// $this->{$property} = base64_decode(substr($this->{$property}, 7), true);
+// }
+// }
+// }
}
/**
|
My opinion:
|
How do you propose to handle per-environment values then? Adding them to the code itself is a non-starter. Best practices and security say you should never commit a number of your environment variables to a repo. It's likely that, if we were doing a major overhaul of the config system that we could refactor the env var use with config files to be faster. Likely by being less "automatic" and doing it something a little more reliant on the environment variables themselves, instead of looping over them at instantiation and assigning them within the class. This would also likely allow us to not have to extend the BaseConfig class anymore. |
arrays 😆 |
@lonnieezell My English may not be correct, but I mean the handling per-environment values is not changed. What I wanted to say by "not be personalized" is that the Config value is the value for the system, not for the site visitor. |
The proposal to change to arrays is not yet clear on how to implement it concretely. Assuming that the Config values are written in an array, how do we pass the values to the class? And with a Config class, we can jump from the property code to the source class in the IDE. |
Pass an array instead of a class. By the way, Laravel has an interesting approach. It is not the config that is passed to the classes (services), but the application instance, which is inherited from the service container class that implements the ArrayAccess interface. class Some
{
/**
* @var Application
*/
protected $app;
/**
* @param Application $app
*/
public function __construct($app)
{
// Here the `config` key is the name of the service in the container.
$this->app['config']['config_name.config_var'];
}
}
// And in tests it is enough to create an array.
new Some([
'config' => ['config_name' => ['config_var' =>'value']]
]) Since our configs are classes, in order to temporarily change the value, you have to use an alternative class, since objects are passed by reference. d(config(App::class)->baseURL); // config(...)->baseURL string (22) "http://localhost:8080/"
$config = config(App::class);
$config->baseURL = 'sss';
d(config(App::class)->baseURL); // config(...)->baseURL string (3) "sss" When migrating from 3.x to 4.x, a soft transition was announced, although configs from arrays were replaced with classes.
Weak advantage. |
Laravel approach makes the design worse. All classes depends on the service container (Application). I don't think a hard transition from classes to arrays is desirable. By the way, what is the benefit of changing to arrays? |
return ['key1' => 'value1', 'key2' => include 'some_config.php'];
return ['key1' => 'value1'] + include 'some_config.php';
ps: It surprises me what garbage they came up with with configs. More precisely with access to them. Some strange factory. |
If the Config class is immutable, the problem does not arise.
Even if our Config will be arrays, we need to refect the following .env value to the config value.
Yes, exactly. However, I now believe that using Session in Config\App is a misuse. This means using personalized values in Config.
Why do you need to include another config? A Config class can have a another Config instance in a property.
What do you mean? "forcing third-party library config files to be moved to the config directory"
What is the benefit of it?
Have you measured it? |
This is logical. But here a problem arises. If we need to change one or more values in the config for some one-time functionality, then we are forced to add an alternative config.
Due to the fact that we are using classes, the keys in .env must follow the scheme class.property[.key[.key]] return [
'default.connection' => env('DB.connection', 'default'),
'driver' => [
'mysql' => \DB\Mysql\Driver::class,
'oracle' => \DB\Oracle\Driver::class,
],
'connections' => [
'default' => env('foo'),
'another_connection' => env('bar'),
]
]; DB.connection = default
foo = oracle://user:pass@host:port/database?option_name=option_value&failover=another_connection
bar = mysql://user:pass@host:port/database?option_name=option_value
Don't know. Maybe I'm a pervert) For example, logically separate parts of the config.
Application config directory public function load(string $conf)
{
return include $this->path . $conf . '.php';
} And here is the link how we load the configs now in CI. CodeIgniter4/system/Config/Factories.php Line 125 in 70eade0
Dot notation is simpler and shorter. config(Config::class)->property['key'];
// vs
config('config.property.key')
No, I didn't measure. This assumption is based on the fact that the array does not need to implement the __set_state() method to work after being restored from the cache. |
If it changes at runtime, it is not a Config value. We should remove it from the Config file. |
Honestly, I do not know. For example, to create a link to a subdomain, we now need an alternative config, otherwise the link will be generated to the current domain. Or the |
In my opinion, If you want to create a link to a subdomain (not the current domain), the subdomain URL should be passed to helpers. But the current site_url() needs an alternate Config\App object... |
// base_url()
$config = clone config(App::class); // We clone the object because the line below would change the global state.
// ...
$config->indexPage = ''; But these are only special cases and the conversation was about the benefits of the array. |
By the way, in Yii2 config includes logical configs, for example, database configuration. |
Yii2 seems to have global config files for web and console, so it includes database configuration. |
My point is that compound configs are possible and used. |
We don't use global config file or global config object, so it seems we don't need compound configs. What do you mean by "generated configs"? |
When installing/removing dynamic modules, a config is generated by scanning the directory with modules. The resulting config in the autoload config constructor is merged with the namespaces property. And I don't know any other ways to connect such modules. Our configuration classes include logic in the form of class methods. That is, these are no longer configs (that is, key = value), but configuration scripts.
In fact, we are already loading the main configs and storing them in a global object just to start the application. |
Did you find a solution in the discussion? I agree that the config should remain non-editable. But, for changes like
For env, we will have to make duplicate properties and get them first instead of the initial config. This means that for this behavior, you need to additionally have values from config. Right? |
My suggestion is to make all Config classes However, to actually do so would require PHP 8.2 or above, and this would be a breaking change.
Env variables can override the config values. But it changes the value when instantiating the Config class. |
I also thought about
Yes, we need to start using new versions. Heh, is there an option to somehow jump into the 4.5/5.0 branch? |
If we really make Config classes |
The Contextual Settings in Settings library is a misuse of Config, or it makes Config confusing. |
I sent a PR to update the user guide: #8563 |
I have questions about Config.
Then, what are Config Files? or what are Config items?
Config items should be immutable or mutable?
We should use array for Config instead of class? What is the advantage of array-config?
App\Config
causes infinite loop now (See #7308). How do we solve it?Checking the environment variables for all properties when instantiating the Config class is too heavy.
This is one of the reasons why CI4 is slower than CI3. I want to improve this too.
The text was updated successfully, but these errors were encountered: