symfony
symfony copied to clipboard
[Config] Allow scalar configuration in PHP Configuration
Q | A |
---|---|
Branch? | 6.1 |
Bug fix? | no |
New feature? | yes |
Deprecations? | no |
Tickets | - |
License | MIT |
Doc PR | - |
By using beforeNormalization
hook in the ConfigBuilder developers could allow end-user to enter any value, and fix it to match the schema.
This is super powerful and provides a great DX for end users by providing "shortcuts" for configuration.
For instance, it allows users to declare
framework:
lock: flock
instead of
framework:
lock:
resources:
default:
- flock
On another hand, the new Php configuration generated from ConfigBuild to declare configuration via PHP files provides another great UX. But sadly lack the previous behavior. People have to enter the full configuration.
This PR relax (when needed) the type-hint on classes and methods generated by the ConfigBuilderGenerator to let people use the same shortCut in their PHP configuration:
For instance
return static function (FrameworkConfig $framework): void {
- $framework->lock()
- ->resource('default', ['%env(LOCK_DSN)%'])
+ $framework->lock('%env(LOCK_DSN)%');
};
or
return static function (FrameworkConfig $framework): void {
$subscriptionWorkflow = $framework->workflows()->workflows('subscription');
- $subscriptionWorkflow->place()->name(Subscription::STATUS_SUBMITTED);
- $subscriptionWorkflow->place()->name(Subscription::STATUS_CANCELED);
- $subscriptionWorkflow->place()->name(Subscription::STATUS_ACCEPTED);
- $subscriptionWorkflow->place()->name(Subscription::STATUS_VALIDATED);
+ $subscriptionWorkflow->place(Subscription::STATUS_SUBMITTED);
+ $subscriptionWorkflow->place(Subscription::STATUS_CANCELED);
+ $subscriptionWorkflow->place(Subscription::STATUS_ACCEPTED);
+ $subscriptionWorkflow->place(Subscription::STATUS_VALIDATED);
One last thing to take into account: When people configure an entry with a scalar value, then it does not make sense to configure the child object. ie.
$framework->lock('%env(LOCK_DSN)%')
->resource('default', ['%env(LOCK_DSN)%']); // !!! what does that mean ? It's even not possible in yaml nor XML
To solve the issue, we could throw an exception inside resource
if the child has been initialized with a scalar value.
But :bulb: I decided to NOT return the child in such a situation... In that case, the user could even chain the "shortcuts"
return static function (FrameworkConfig $framework): void {
$subscriptionWorkflow = $framework->workflows()->workflows('subscription');
$subscriptionWorkflow->place(Subscription::STATUS_SUBMITTED);
- $subscriptionWorkflow->place(Subscription::STATUS_CANCELED);
- $subscriptionWorkflow->place(Subscription::STATUS_ACCEPTED);
- $subscriptionWorkflow->place(Subscription::STATUS_VALIDATED);
+ ->place(Subscription::STATUS_CANCELED)
+ ->place(Subscription::STATUS_ACCEPTED)
+ ->place(Subscription::STATUS_VALIDATED);
Draw back is, the signature of the method place is now place(mixed $value = []): self|\Symfony\Config\Framework\Workflows\WorkflowsConfig\PlaceConfig
Is it an issue?
Related to #43164?
Draw back is, the signature of the method place is now place(mixed $value = []): self|\Symfony\Config\Framework\Workflows\WorkflowsConfig\PlaceConfig Is it an issue?
IMHO it's a step back yes.
Is shortcuts worth pursuing? Rather than fully qualified/explicit config?
But sadly lack the previous behavior. People have to enter the full configuration.
works for me :)
Actually, I converted a personal application to PHP configuration, and have to admit that I've been disappointed by the experience.
Some really simple YAML configuration framework.lock: flock
become obscure $framework->lock()->resource('default', ['flock'])
<= why resource
, why default
why flock
is wrapped into an array?
Some configurations short monolog.handler.main.excluded_http_codes: [403, 404]
become super verbose with intermediate varianbles
$mainHandler = $monolog->handler('main');
$mainHandler->excludedHttpCode()->code(403);
$mainHandler->excludedHttpCode()->code(404);
Moreover, when I switched my configuration, the symfony documentation was not-yet updated, and I had to dig into the Configuration.php
file to understand how to convert my yaml file into PHP... Now this will be easier for symfony (because most of config are now documented) but this is not the case for many other bundles.
If the issue is only about the double return signature xxx(): self|child
we could keep the current behavior, and throw an exception when people try to update a property inside the shortcut value
$framework->lock('redis://localhost')->resource(...); <== InvalidConfigurationException
Rebase needed, in case there is anything left after #46328
Friendly ping @jderusse /cc @HypeMC
Is this PR still needed after https://github.com/symfony/symfony/pull/46328?
@nicolas-grekas This PR provides some additional features that #46328 doesn't have, eg allowed type hints on generated methods: https://github.com/symfony/symfony/blob/962834b63066c1be04bed19cbc6762d3136bcfa3/src/Symfony/Component/Config/Tests/Builder/Fixtures/ScalarNormalizedTypes/Symfony/Config/ScalarNormalizedTypesConfig.php#L25
Currently mixed
is used in these situations:
https://github.com/symfony/symfony/blob/5bf31c57c3d07ab6a04bdeb8fdc2957e0591dcb5/src/Symfony/Component/Config/Tests/Builder/Fixtures/ScalarNormalizedTypes/Symfony/Config/ScalarNormalizedTypesConfig.php#L31
My PR only covers using scalars with the beforeNormalization
hook.
Would you be able to take over the PR @HypeMC? I feel like @jderusse would appreciate :)
This PR also adds an (opiniated) change in the returned object: When people configure an entry with a scalar value, then, the returned value is the object and not the child object. This allows chaining "aliases". ie
$subscriptionWorkflow = $framework->workflows()->workflows('subscription');
$subscriptionWorkflow->place(Subscription::STATUS_SUBMITTED);
- $subscriptionWorkflow->place(Subscription::STATUS_CANCELED);
- $subscriptionWorkflow->place(Subscription::STATUS_ACCEPTED);
- $subscriptionWorkflow->place(Subscription::STATUS_VALIDATED);
+ ->place(Subscription::STATUS_CANCELED)
+ ->place(Subscription::STATUS_ACCEPTED)
+ ->place(Subscription::STATUS_VALIDATED);
Would you be able to take over the PR @HypeMC? I feel like @jderusse would appreciate :)
Sure, if @jderusse doesn't mind, I'll take over.
if @jderusse doesn't mind,
no issue at all, thanks for your help
PR rebased and duplicated logic with #46328 removed
Thank you @jderusse.
@jderusse
Before in \Symfony\Config\Framework\HttpClient\ScopedClientConfig\RetryFailedConfig::httpCode
was:
public function httpCode(string $code, mixed $value = []): \Symfony\Config\Framework\HttpClient\ScopedClientConfig\RetryFailed\HttpCodeConfig|static
Now it generates:
public function httpCode(string $code, array $value = []): \Symfony\Config\Framework\HttpClient\ScopedClientConfig\RetryFailed\HttpCodeConfig|static
Is this a bug in the config generator or in the HttpClient?