2

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.

Community
  • 1
  • 1
Alex
  • 571
  • 1
  • 8
  • 26

2 Answers2

2

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'))
Anthon
  • 69,918
  • 32
  • 186
  • 246
  • My answer does not add any whitespace to the resulting string. How do you get that idea? – flyx Aug 08 '16 at 08:22
  • @flyx Load it and then dump it, just like I did. – Anthon Aug 08 '16 at 08:24
  • 1
    If the YAML implementation of your choice adds spaces to the scalar in my answer, it is not a correct YAML implementation. The spec says that [All leading and trailing white space characters are excluded from the content.](http://www.yaml.org/spec/1.2/spec.html#id2787839). – flyx Aug 08 '16 at 08:27
  • @flyx You might be right, I'll have to look into that why PyYAML does that. – Anthon Aug 08 '16 at 08:41
  • 1
    I see you use PyYAML. Python supports backslash escapes inside long string literals, so make sure you *escape the backslashes in the YAML* to get proper output. – flyx Aug 08 '16 at 08:43
  • @flyx I just realise that I should use \\ in the yaml_str, sorry for that, and thanks for pointing out. – Anthon Aug 08 '16 at 08:44
  • Sorry for being annoying, but there still is an error in your answer. Your YAML actually adds a newline to the end of the string. To avoid that, start the folded scalar with `>-` instead of just `>`. – flyx Aug 08 '16 at 08:48
  • That is not annoying. I added that to my example code after I copy-and-pasted the code in, but before I copy-pasted the example. I should get some more coffee before answering on SO in the morning. – Anthon Aug 08 '16 at 08:51
  • In symfony, this fails with: Unable to parse at line 616 (near " - - >-"). – Alex Aug 11 '16 at 09:41
  • 1
    The parser that symphony uses is non-compliant. You can test this at http://yaml-online-parser.appspot.com/ or http://www.yamllint.com/. I'll update the example with something symphony with this defect might be able to understand. – Anthon Aug 11 '16 at 10:37
  • Can you update your post with suggestion how to format almost same YAML, but with string params? Current method not working for this: "calls: - [create, ["%param1%", "%param2%"]]" – Alex Aug 12 '16 at 06:54
  • Compiled container loks like " $instance->create('param1, param2');" - two params are concatenated to one string, but create() method expects two args. – Alex Aug 12 '16 at 07:02
  • @alex I'm not sure why it doesn't, but I have difficulty to visualise what you did. You probably missed some '-'. Can make a new question (refer to this one), in that first show what works, and then adding what makes it break? – Anthon Aug 12 '16 at 07:06
  • @Anthon, ok, Iam post a new question here: http://stackoverflow.com/questions/38912122/symfony-yaml-format-conversion-calls-with-string-params – Alex Aug 12 '16 at 07:20
  • Also, please look and UPD#1 in the new question, there is a part related to this question. – Alex Aug 12 '16 at 07:30
  • @alex I answered, you were missing a `-` in the rewrite – Anthon Aug 12 '16 at 07:36
1

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.

flyx
  • 35,506
  • 7
  • 89
  • 126
  • If you insert a space between the commas and backslashes then the quoted scalar will get two spaces, just like in the example (in the middle two lines) – Anthon Aug 08 '16 at 08:54
  • Ah yes, I overlooked those. Updated the answer to not include backslashes where spaces are wanted - which is simpler than adding a space before the backslash. – flyx Aug 08 '16 at 09:13
  • In Symfony, this fails with: Unable to parse at line 619 (near " - - "@=service('AnotherService1').create(\"). – Alex Aug 11 '16 at 09:43