-
-
Notifications
You must be signed in to change notification settings - Fork 9.8k
[Config][DependencyInjection] Add configuration builder for writing PHP config #40600
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
Conversation
|
Hm.. I don't understand the psalm error.. |
d3a8e3b to
c2f9a74
Compare
|
I really love this feature that remind me the work from @HeahDude . I worry about edge cases that will not be handled (ie. all our A small detail, I would remove the |
Seems like an issue with psalm: https://psalm.dev/r/c97a88395d |
How about removing the |
no, the code contains a bug :) you are switching see: https://psalm.dev/r/92bdc7be90 however, psalm should probably provide a better trace for this scenario. |
|
Just note about the method names. We have a few different scenarios.
EDIT: This is updated, we have dropped all |
It actually cannot when |
|
This is brilliant :) IIUC the generated types are problematic for env values (aka string placeholders in Config) |
|
Using environment variables are fine. Just remember: Correct /** @var \Config\Framework\FrameworkConfig $framework */
$framework = $container->extensionBuilder('framework');
$framework->addLock()
->addResource('acme', ['%env(LOCK_DSN)%']);Wrong way /** @var \Config\Framework\FrameworkConfig $framework */
$framework = $container->extensionBuilder('framework');
$framework->addLock()
// This shows the wrong way. Dont do this.
->addResource('acme', [getenv('LOCK_DSN')]);
|
|
@Nyholm also for |
|
See I think it needs eg. |
nicolas-grekas
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sure
return static function (ContainerConfigurator $container) {
/** @var \Config\Security\SecurityConfig $security */
could be turned into
return static function (SecurityConfig $security) {
by hooking into the FileLoader, that'd be neat :)
I didn't read the code in Generator yet and I won't be able to do so before the feat freeze for 5.3 unfortunately.
But this looks promising!
707dd68 to
e7d5a78
Compare
|
I've updated the PR with a lot of tests and docs. The PR description is updated. I would like to have a final round of reviews, merge and then follow up with PRs for specific features like cache warmer. This PR is large and complex enough as it is. |
e0937fa to
106826c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you very much for this PR, I really like how it brings PHP configuration to the end-user without asking the maintainer to creates these Config classes. ❤️
I played with it on a demo project and faced few issues:
-
class does not exist (and IDE is not aware of it) until cache generates theme. BUT cache generates the classes only when you create a config that uses it. So you have to know that the class will exist (and have to know the FQDN), to create a file that uses it, let the IDE report error, warm the cache, and then you can use it.
It's didn't experimented a great DX on this part :( -
Because of our normalizers, (and because there is no chain/fluent parent/end methods), simple config became complex to setup.
ie.excluded_http_codesin monolog
monolog:
handlers:
main:
type: fingers_crossed
excluded_http_codes: [404, 405] $handler = $monolog->handler('main')
->type('fingers_crossed')
;
$handler->excludedHttpCode()->code('404');
$handler->excludedHttpCode()->code('405');I don't think this should be implemented in this PR, but we should find a way to provide an "alias" in this new Config
- I tried to migrate my monolog.yaml to PHP, but failed
$handler = $monolog->handler('main')
->type('fingers_crossed')
->acceptedLevel(['error'])
->handler('nested')
->bufferSize(50)
;
$handler->excludedHttpCode()->code('404');
$handler->excludedHttpCode()->code('405');
leads to
Invalid configuration for path "monolog.handlers.main": You can only use excluded_http_codes/excluded_404s with a FingersCrossedHandler definition
I didn't digged into it, but when dumping config->toArray() I well have type=fingers_crossed
But the validate node of the extension (that trigger the exception) see type=stream
- Deprecations are not leverage. We should, at least, annotate the methods
@deprecated(ieframework.profiler.only_master_requests)
src/Symfony/Component/Config/Builder/ConfigBuilderGenerator.php
Outdated
Show resolved
Hide resolved
| } | ||
|
|
||
| if ($node instanceof EnumNode) { | ||
| $comment .= sprintf(' * @param %s $value', implode('|', array_map(function ($a) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/Symfony/Component/Config/Builder/ConfigBuilderGenerator.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Config/Builder/ConfigBuilderGenerator.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Config/Builder/ConfigBuilderGenerator.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Config/Builder/ConfigBuilderGenerator.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Config/Builder/ConfigBuilderGenerator.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php
Outdated
Show resolved
Hide resolved
|
Awesome. Thank you.
return static function (ContainerBuilder $container) {
$container->loadFromExtension('monolog', [
'handlers' => [
'main' => [
'type' => 'fingers_crossed',
'excluded_http_codes' => [404, 404],
],
],
]);
};
|
|
Thank you for the review. I really appreciate you taking the time to test and experiment with this. I'll double check the monolog config thing later. |
nicolas-grekas
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just realized one more thing: following #40214, the generated builders should have a when() method, for the same purpose.
f883c6a to
e2c9f25
Compare
I agree. I will be happy to work on this as soon as this PR is merged. Not adding that feature in this PR would allow to quicker move forward. I've update the PR. It is ready for a review. status: need review |
c80564c to
463940b
Compare
nicolas-grekas
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All good on my side, thanks for the quick changes!
c338646 to
460b46f
Compare
|
Thank you @Nyholm. |
|
Wohoo! Excellent. Thank you for all the reviews. |
This PR was squashed before being merged into the 5.3-dev branch. Discussion ---------- [Config] Add docs for ConfigBuilders This is config for symfony/symfony#40600 We should wait for the code merge Commits ------- 5b427af [Config] Add docs for ConfigBuilders
|
Hi, I'm trying to find or generate these classes in loca This is the full Thanks |
|
@TomasVotruba |
|
@Guuzen Thanks, I'll try to remember when I'm debugging again. bin/console dump:configs |
… format for semantic configuration (nicolas-grekas) This PR was merged into the 7.4 branch. Discussion ---------- [Config][DependencyInjection] Deprecate the fluent PHP format for semantic configuration | Q | A | ------------- | --- | Branch? | 7.4 | Bug fix? | no | New feature? | yes | Deprecations? | no | Issues | - | License | MIT This PR deprecates the fluent PHP format for semantic configuration introduced in Symfony 5.4 by `@Nyholm` (see #40600). It aims to replace it with the new array-based PHP config format (see #61490). The fluent PHP config format was a great experiment: - It helped us improve the Config component and the code generation of fluent config builders. - It confirmed the community’s interest in PHP-based configuration. - And it showed us its limits. Those limits are structural. Writing fluent config is difficult and full of edge cases. Its rigidity comes from having to match one canonical interpretation of the semantic config tree. Automatic code generation can’t capture the custom logic that before-normalizers introduce, yet those normalizers are essential for flexibility and backward compatibility. This rigidity makes fluent config fragile. How do we deal with this fragility as config tree authors? At the moment, we don't care. Maybe this format is too niche for you to have experienced this issue, but we cannot guarantee that simple upgrades won't break your fluent PHP config. The new array-based PHP format builds directly on the same code used for loading YAML configs. That means: - trivial conversion between YAML and PHP arrays, - identical flexibility and behavior, - and support for auto-completion and static analysis through generated array shapes. The generated array shapes are rigid too, but that rigidity is non-breaking: even if your config no longer matches the canonical shape, your app keeps working. Static analyzers might warn you: that’s an invitation to update, not a failure. I'm submitting this PR a bit l late for 7.4 but I think it's important to merge now. Deprecating the fluent PHP config format will: - prevent new code from relying on a fragile approach, - make room in the documentation for the array-based format, - and consolidate Symfony’s configuration story around a robust PHP-based format. Fluent PHP for semantic config served us well but it's time to retire it. ```diff -return function (AcmeConfig $config) { - $config->color('red'); -} +return new AcmeConfig([ + 'color' => 'red', +]); ``` PS: there's another fluent config format for services and routes (see #23834 and #24180). This other format is handwritten. It doesn't have the issues listed above and it is *not* deprecated. It's actually the recommended way *for bundles* to declare their config (instead of XML, see #60568). Commits ------- 332b4ac [Config][DependencyInjection] Deprecate the fluent PHP format for semantic configuration

I've spent most part of today to generate this PR. It is far from complete but it is ready for review.
This PR will build classes and store them in the build_dir. The classes will help you write PHP config. It will basically generate an array for you.
Before
After
About autogeneration
This PR is generating the extension's
ConfigBuilders when they are first used. Since the PR is already very large, I prefer to follow up with additional PRs to include a cache warmer and command to rebuild theConfigBuilders.The generated
ConfigBuilderuses a "ucfirst() camelCased" extension alias. If the alias isacme_foothe rootConfigBuilderwill beSymfony\Config\AcmeFooConfig.The recommended way of using this class is:
One may also init the class directly, But this will not help you with generation or autoloading
I do think we should only talk about the first way
If a third party bundle like this idea and want to provide their own
ConfigBuilder, they have two options:Create the class
Symfony\Config\TheBundleConfigthemselves and make sure they configure composer to autoload that file and that the class implementsConfigBuilderInterface. We will never regenerate a file that already exists.Create any class implementing
ConfigBuilderInterfaceand ask their users to use that class in their config in the same way they would useSymfony\Config\TheBundleConfig.The first way is obviously the smoothest way of doing things.
BC
There is a great discussion about backwards compatibility for the generated files. We can assure that the class generator don't introduce a BC break with our tests. However, if the bundle changes their configuration definition it may break BC. Things like renaming, changing type or changing a single value to array is obvious BC breaks, however, these can be fixed in the config definition with normalisation.
The generator does not support normalisation. It is way way more complicated to reverse engineer that. I think a future update could fix this in one of two ways:
I hate BC breaks as much as the next person, but all the BC breaks in the generated classes will be caught when building the container (not at runtime), so I am fine with not having a 100% complete solution for this issue in the initial PR.
Other limitations
If a bundle is using a custom extension alias, then we cannot guess it.. so a user have to use a cache warmer because we cannot generate the
ConfigBuilderon the fly.TODO
The generated code can be found in this example app: https://github.com/Nyholm/sf-issue-40600/tree/main/var/cache/dev/Symfony/Config