-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[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. |
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_codes
in 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. |
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.
this looks super nice :)
src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php
Outdated
Show resolved
Hide resolved
* @param string $namespace example extension alias ("framework") or FQCN string | ||
* for a class implementing ConfigBuilderInterface | ||
*/ | ||
final public function configBuilder(string $namespace): ConfigBuilderInterface |
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.
do we need this method? what about allowing only passing via arguments as resolved by the loader?
using this method doesn't work this autocompletion anyway
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.
You are correct. Thank you.
src/Symfony/Component/Config/Builder/ConfigBuilderGenerator.php
Outdated
Show resolved
Hide resolved
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
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 |
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
ConfigBuilder
s 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 theConfigBuilder
s.The generated
ConfigBuilder
uses a "ucfirst() camelCased" extension alias. If the alias isacme_foo
the rootConfigBuilder
will 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\TheBundleConfig
themselves 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
ConfigBuilderInterface
and 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
ConfigBuilder
on 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