Symfony YAML format conversion

2019-07-13 08:04发布

问题:

I have some service definition that looks like this:

MyService:
    class: Some\Class\Here
    factory:
        - SomeFactoryHere
        - method
    calls:
        - [add, ["@=service('AnotherService1').create(service('AnotherService2'), service('AnotherService3'), service('AnotherService3'))"]]

IMHO, this can be more readable if converted to something like this:

MyService:
    class: Some\Class\Here
    factory:
        - SomeFactoryHere
        - method
    calls:
        -
          add,
          "@=service('AnotherService1').create(
              service('AnotherService2'),
              service('AnotherService3'),
              service('AnotherService3')
          )"

But, this is not valid YAML (Symfony parser fails), and my question is how this config can be converted to something like above?

UPD#1

Look at Symfony YAML format conversion: "calls" with string params - important nuances are there.

回答1:

The best way to break up your string

"@=service('AnotherService1').create(service('AnotherService2'), service('AnotherService3'), service('AnotherService3'))"

is by using a stripped folded block scalar. The limitation for this is that you cannot escape any special characters with backslashes, but those are not in your example (the reason you need "" around your scalar is because it starts with an @ which is a reserved character).

Then you also have to correctly re-represent the structure that you have, as @flyx already indicated: the value for calls is a sequence, the first element of which is a list of the scalar add and sequence consisting of the aforementioned long scalar that you want to break up for readability:

import yaml

yaml_str = """\
MyService:
    class: Some\Class\Here
    factory:
        - SomeFactoryHere
        - method
    calls:
        - - add
          - - >-
              @=service('AnotherService1').create(
              service('AnotherService2'),
              service('AnotherService3'),
              service('AnotherService3'))
"""

data = yaml.safe_load(yaml_str)
print(data)

gives:

"@=service('AnotherService1').create( service('AnotherService2'), service('AnotherService3'), service('AnotherService3'))"

Please note that this gives an extra space between .create( and service(.

The YAML parser that Symphony uses seems not to be able to parse the above (although it is correct). You can alternatively try:

MyService:
    class: Some\Class\Here
    factory:
        - SomeFactoryHere
        - method
    calls:
        - 
          - add
          - 
            - >-
              @=service('AnotherService1').create(
              service('AnotherService2'),
              service('AnotherService3'),
              service('AnotherService3'))


回答2:

What you wrote is valid YAML. If the Symfony parser fails, it has a bug. But anyway, the second YAML does not represent the same structure as the first YAML.

In the first YAML, calls is a sequence. The first sequence item of calls is also a sequence, which contains the scalar add and yet another sequence. In the second YAML, calls is also a sequence, but the item it contains is a scalar which contains everything from add, to )". The comma is content here, because you did not start a flow sequence (with [). Here is block-style YAML which is equivalent to the first YAML:

MyService:
    class: Some\Class\Here
    factory:
        - SomeFactoryHere
        - method
    calls:
        - - add
          - - "@=service('AnotherService1').create(\
                 service('AnotherService2'),
                 service('AnotherService3'),
                 service('AnotherService3')\
              )"

The backslashes at the end of the string's lines cause no whitespace to be inserted. By default, YAML inserts one space character for each newline in a double-quoted string it encounters. This YAML scalar yield exactly the same string as your first YAML contains.

- - is compact style, which starts two nested sequence items at once. So now, calls is a sequence again with a sequence as first item. that nested sequence contains a scalar add as first item, and another sequence as second item. And that sequence contains the double-quoted scalar.