Skip to content

Use json env resolver in configurations #28137

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

Closed
ln-e opened this issue Aug 5, 2018 · 15 comments
Closed

Use json env resolver in configurations #28137

ln-e opened this issue Aug 5, 2018 · 15 comments

Comments

@ln-e
Copy link

ln-e commented Aug 5, 2018

Symfony version(s) affected: 4.1
Description
I want to be able to configure swiftmailer delivery_adresses via env var. In prod env on production server it should be null, in prod env on staging server it should have some value. Looks like work for env parameters.

I try to set it like

swiftmailer:
    delivery_addresses: '%env(json:MAILER_DELIVERY_ADDRESSES)%'

I specify json env processor, and in my env file

MAILER_DELIVERY_ADDRESSES='["test@test.test"]'
A dynamic value is not compatible with a "Symfony\Component\Config\Definition\PrototypedArrayNode" node type at path "swiftmailer.mailers.default.delivery_addresses".

Json processor return array, and so it should be valid to pass such value to PrototypedArrayNode.

@ro0NL
Copy link
Contributor

ro0NL commented Aug 6, 2018

This is by design. A prototyped array is still part of the semantic configuration tree.

The reason behind this is env vars can be any value during runtime, but the tree needs to be validated during compile time.

In this case it would be:

swiftmailer:
    delivery_addresses:
        - '%env(MAILER_DELIVERY_ADDRESS_1)%'
        - '%env(MAILER_DELIVERY_ADDRESS_2)%'

@xabbuh
Copy link
Member

xabbuh commented Aug 6, 2018

I am closing here as this is the expected behaviour.

@xabbuh xabbuh closed this as completed Aug 6, 2018
@ln-e
Copy link
Author

ln-e commented Aug 7, 2018

@ro0NL it wouldn't work. This is equal to [null], so count of delivery_addressess is bigger than 0.
See https://github.com/symfony/swiftmailer-bundle/blob/master/DependencyInjection/SwiftmailerExtension.php#L336

Looks like env should be convenient replacement of parameters.yml but in fact it is not.

@ro0NL
Copy link
Contributor

ro0NL commented Aug 7, 2018

environment variables and parameters have different usecases, so i wouldnt call it a replacement per se. Let alone to blindly update all parameters to env vars.

You say this doesnt work?

swiftmailer:
    delivery_addresses:
        - '%env(MAILER_DELIVERY_ADDRESS_1)%'
        - '%env(MAILER_DELIVERY_ADDRESS_2)%'

@ln-e
Copy link
Author

ln-e commented Aug 7, 2018

I try to say that when yours config will be converted to php array it become [null, null]. There is two members. null and null. Count of such array is 2 not 0.

Thus Swiftmailer will try to send all email not to real users, but to this two emails.

I should either pass null instead of array, or array with zero members. Only then swiftmailer will send email to real users.

On my production server config should be equals to:

swiftmailer:
    delivery_addresses: null
or
swiftmailer:
    delivery_addresses: []

On my staging server config should be equals to:

swiftmailer:
    delivery_addresses:
        - test@email

With env var it is impossible to do so.

@ro0NL
Copy link
Contributor

ro0NL commented Aug 7, 2018

@ln-e i got it :) thx. Currently this is impossible indeed, but it can be done by prepending a dynamic config in php ...

public function prependExtensionConfig($name, array $config)

@ro0NL
Copy link
Contributor

ro0NL commented Aug 7, 2018

A permanent solution could be to expand the env syntax, in an effort to expose more type information.

%env(string[]:json:MAILER_DELIVERY_ADDRESSES)%

Here string is an existing prefix and the special [] notation would tell us this is an array of strings, which is compatible with the swiftmailer.delivery_addresses node. Moreover, it would actually be validated as such during runtime.

cc @nicolas-grekas

@nicolas-grekas
Copy link
Member

Or we patch the bundle to make it accept an array and deal with it in a factory. I'd prefer this over adding more complexity.

@dtfafard
Copy link

Is there any proposed solution that would allow the use of the json processor?

Using :

swiftmailer:
    delivery_addresses:
        - '%env(MAILER_DELIVERY_ADDRESS_1)%'
        - '%env(MAILER_DELIVERY_ADDRESS_2)%'

Is actually unusable if I wish to have 2 emails in one environment and 4 in another one. The dynamism allowed by the arrayNode is broken.

Thank you!

@dtfafard
Copy link

Hi guys,

I've managed to make the code work manually overwriting :

// In Symfony\Component\Config\Definition\ArrayNode
    /**
     * {@inheritdoc}
     */
    protected function allowPlaceholders(): bool
    {
        return false;
    }

// to 


    /**
     * {@inheritdoc}
     */
    protected function allowPlaceholders(): bool
    {
        return true;
    }

No errors were thrown.

Can anyone shed some light on why was it set to false and, maybe, the negative repercussions to setting it to "true"?

@ro0NL
Copy link
Contributor

ro0NL commented Nov 22, 2018

because it would only work "by chance", e.g. if the env is set correctly. At this point you can change the env to any value and it would always pass config validation.

See #29270 for a different approach.

@shtumi
Copy link

shtumi commented Sep 4, 2019

is there any progress with this issue?

@fritzmg
Copy link
Contributor

fritzmg commented Jun 6, 2020

Regardless of how the configuration tree of the swiftmailer bundle is set up: what is the correct way to allow dynamic values for a scalar array node in the configuration tree of your own bundle? I am unable to figure out the correct way to do this.

@toby-griffiths
Copy link
Contributor

I've just spent ages trying to work out why the example in the docs isn't working. Has anything changed in the past 2 years to allow this to work somehow? If not, might be worth updating the docs to remove this as a bad example to save others time?

@sshymko-promenade
Copy link

sshymko-promenade commented Jun 17, 2022

Being new to Symfony, initially got excited by the power of the config syntax only to run into completely artificial limitations on where in the config structure said syntax is allowed and where it is arbitrarily not.

Use Case

The intent is to pass driver options to Doctrine DBAL:

doctrine:
    dbal:
        url: '%env(resolve:DATABASE_URL)%'
        driver: '%env(string:DATABASE_DRIVER)%'
        options: '%env(json:DATABASE_DRIVER_OPTIONS)%'

By design, each driver comes with a unique set of options of virtually arbitrary format: key-value pairs mixed with flags.

Unfortunately, this syntax is not allowed in such completely reasonable situations:

A dynamic value is not compatible with a "Symfony\Component\Config\Definition\PrototypedArrayNode" node type at path "doctrine.dbal.connections.default.options".

Workaround

A patch proposed by @dtfafard can be used as a workaround:

composer require cweagans/composer-patches

composer.json

{
    "extra": {
        "patches": {
            "symfony/config": {
                "Dynamic config values": "patches/symfony-config.patch"
            }
        }
    }
}

patches/symfony-config.patch

diff --git a/vendor/symfony/config/Definition/ArrayNode.php b/vendor/symfony/config/Definition/ArrayNode.php
index 76b811c..14d4565 100644
--- a/vendor/symfony/config/Definition/ArrayNode.php
+++ b/vendor/symfony/config/Definition/ArrayNode.php
@@ -397,6 +397,6 @@ class ArrayNode extends BaseNode implements PrototypeNodeInterface
      */
     protected function allowPlaceholders(): bool
     {
-        return false;
+        return true;
     }
 }
composer install

Proposal

How about extending the env() syntax to explicitly allow misc data structure?

%env(mixed:json:DATABASE_DRIVER_OPTIONS)%

There're numerous reports of this config inflexibility closed as "explained" or "by design" citing compile-time validation of the config format. While the validation is valuable, it's a pity to artificially restrict applications of such a powerful syntax.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants