Skip to content

[Yaml] Recommend using quotes instead of PARSE_KEYS_AS_STRINGS #22948

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
wants to merge 3 commits into from

Conversation

GuilhemN
Copy link
Contributor

@GuilhemN GuilhemN commented May 29, 2017

Q A
Branch? 3.4
Bug fix? no
New feature? no
BC breaks? no
Deprecations? yes
Tests pass? yes
Fixed tickets #...
License MIT
Doc PR

Sorry for opening this so lately... I just realized that we could get rid of Yaml::PARSE_KEYS_AS_STRINGS just by recommending using quotes...

This way we don't allow a behavior not respecting the spec and we won't need to deprecate PARSE_KEYS_AS_STRINGS later.

Is it too late for this to be merged in 3.3?

ping @xabbuh

@@ -490,11 +490,10 @@ private static function parseMapping($mapping, $flags, &$i = 0, $references = ar
@trigger_error('Omitting the key of a mapping is deprecated and will throw a ParseException in 4.0.', E_USER_DEPRECATED);
}

if (!(Yaml::PARSE_KEYS_AS_STRINGS & $flags)) {
if (!$isKeyQuoted) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added because quoted keys should not be evaluated


if ('' !== $key && $evaluatedKey !== $key && !is_string($evaluatedKey)) {
@trigger_error('Implicit casting of incompatible mapping keys to strings is deprecated since version 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0. Pass the PARSE_KEYS_AS_STRING flag to explicitly enable the type casts.', E_USER_DEPRECATED);
if ('' !== $key && $evaluatedKey !== $key && !is_string($evaluatedKey) && !is_int($evaluatedKey)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the is_int check because unquoted integers work fine

@xabbuh
Copy link
Member

xabbuh commented May 30, 2017

I do not think this really is an option in general. The reason is that you may not be able to influence how the YAML file is actually dumped (e.g. an external data source) and not having quotes around mapping keys is totally valid.

@nicolas-grekas nicolas-grekas added this to the 3.3 milestone May 30, 2017
@GuilhemN
Copy link
Contributor Author

Using PARSE_KEYS_AS_STRINGS in our loaders mean that they don't evaluate keys and so do not comply with the spec.
At the same time, I don't think we should be able to parse a yaml file using features not supported by the language because it loses its meaning (if you use false as a key it means something, if you use "false" it means something else).

The reason is that you may not be able to influence how the YAML file is actually dumped

Let's be pragmatic, I don't think someone will ever use false, true, or whatever as a mapping key so imo we should be protected against these cases, because php doesn't support them so you can't reflect these values in the result you get from the parse.
The php extension always evaluate mapping keys but objects are serialized, false is converted to "", true to 1, null to "". I think this is wrong because most do not know this and you can't know what was the exact original value.

not having quotes around mapping keys is totally valid

It shouldn't be for values that are not supported by php imo because you end up with a weird behavior for basically no gain (who would voluntarily ever use these values as keys?).

@GuilhemN GuilhemN changed the base branch from 3.3 to 3.4 May 30, 2017 17:07
@GuilhemN GuilhemN force-pushed the fix branch 2 times, most recently from 307c083 to c5210ad Compare May 30, 2017 17:10
@GuilhemN
Copy link
Contributor Author

Updated to target 3.4

@GuilhemN
Copy link
Contributor Author

GuilhemN commented Jun 7, 2017

Phpunit fails when using the 4.0 version of the Yaml component because of #22770, this exception must not be thrown when an integer is parsed (it is supported by php so there's no problem).

@xabbuh
Copy link
Member

xabbuh commented Jun 13, 2017

@GuilhemN That's fixed by #23108, right?

@GuilhemN
Copy link
Contributor Author

@xabbuh indeed, pr rebased. The build still fails but this is not caused by this PR.

Copy link
Member

@fabpot fabpot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xabbuh Is this one ok for you?

@@ -1843,27 +1818,13 @@ public function testPhpConstantTagMappingKey()
$this->assertSame($expected, $this->parser->parse($yaml, Yaml::PARSE_CONSTANT));
}

public function testPhpConstantTagMappingKeyWithKeysCastToStrings()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, this test should not disappear. We need to keep it to ensure this case keeps working in 3.4 (it should become a legacy test though)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't remember why i removed it so I guess we can revert this. However I won't be able to do it for the next 2 weeks, feel free to push on my repository if you have the time, otherwise I'll do the change ASAP.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -236,9 +240,9 @@ private function doParse($value, $flags)
throw $e;
}

if (!(Yaml::PARSE_KEYS_AS_STRINGS & $flags) && !is_string($key) && !is_int($key)) {
if (!is_string($key) && !is_int($key)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are you sure about this change ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, evaluable keys are no longer allowed unless they're quoted, even when using Yaml::PARSE_KEYS_AS_STRINGS.

$keyType = is_numeric($key) ? 'numeric key' : 'non-string key';
@trigger_error(sprintf('Implicit casting of %s to string is deprecated since version 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0. Pass the PARSE_KEYS_AS_STRINGS flag to explicitly enable the type casts.', $keyType), E_USER_DEPRECATED);
@trigger_error(sprintf('Implicit casting of %s to string is deprecated since version 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0. Quote your evaluable mapping keys instead.', $keyType), E_USER_DEPRECATED);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest changing this message in 3.3 already. People who have not yet migrated to 3.3 should get the advice of quoting directly, to avoid a double migration for them. Quoting should already be working in 3.3.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, I'll submit a pr if this is merged.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see #23635

@@ -59,7 +59,7 @@ public function load($file, $type = null)
}

try {
$parsedConfig = $this->yamlParser->parse(file_get_contents($path), Yaml::PARSE_KEYS_AS_STRINGS);
$parsedConfig = $this->yamlParser->parse(file_get_contents($path));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't this a BC break ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not more than when we added it in 3.3 (for instance !str foo in routing files was parsed as "foo" in 3.2 and is as "!str foo" since 3.3). Reverting this change is in fact more intuitive imo as it does make the parser always spec compliant.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we do this change in #23635 then?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer doing this in a minor but if you insist I can of course do it in 3.3.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use statement can be removed too?

@xabbuh
Copy link
Member

xabbuh commented Jul 19, 2017

Recommending to quote keys indeed looks like a good idea. However, I am not convinced we should deprecate the PARSE_KEYS_AS_STRINGS. It can still be useful when you try to parse some YAML files that you do not control.

@GuilhemN
Copy link
Contributor Author

@xabbuh imo it causes too many issues for what it's worth.
For instance !str true: foo should work fine but with the flag, you'll end up with a key you don't expect. We have the same problem with other syntax such as ! true and !str "foo".
Because of this you also won't be able to detect colliding keys (1 and 0x1 for example).

If the yaml file you try to parse uses features not supported by the sf parser nor by PHP, it looks normal and expectable to me that you can't parse this file.

Lastly, I don't think this fits something else than very edge cases that could probably also be fixed by altering the yaml file parsed.

@GuilhemN GuilhemN force-pushed the fix branch 2 times, most recently from 200c9b9 to 21ada49 Compare July 23, 2017 12:47
@@ -14,7 +14,6 @@
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Parser as YamlParser;
use Symfony\Component\Yaml\Yaml;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this must be reverted

UPGRADE-3.4.md Outdated
After:

```php

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the blank line can be removed

UPGRADE-4.0.md Outdated
After:

```php

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can be removed

@@ -59,7 +59,7 @@ public function load($file, $type = null)
}

try {
$parsedConfig = $this->yamlParser->parse(file_get_contents($path), Yaml::PARSE_KEYS_AS_STRINGS);
$parsedConfig = $this->yamlParser->parse(file_get_contents($path));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we do this change in #23635 then?

/**
* @dataProvider getNotPhpCompatibleMappingKeyData
*/
public function testExplicitStringCastingOfMappingKeys($yaml, $expected)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO the test should be kept but being flagged as legacy

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -71,19 +71,6 @@ public function getDataFormSpecifications()
}

/**
* @dataProvider getNonStringMappingKeysData
*/
public function testNonStringMappingKeys($expected, $yaml, $comment)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

@xabbuh
Copy link
Member

xabbuh commented Jul 24, 2017

@GuilhemN I would still expect floats to be used more frequently as keys than tags, but if noone else objects, I am fine with the proposed changes. I just left some minor comments.

@GuilhemN
Copy link
Contributor Author

GuilhemN commented Jul 24, 2017

@xabbuh maybe but people just have to quote the key if they want to use a float while we have no solution for tags. And still the same argument, the yaml file is invalid and could be rejected by another parser (at least the other parser won't produce the same result) :)

@@ -114,7 +114,7 @@ private function getClassesFromYaml()
$this->yamlParser = new Parser();
}

$classes = $this->yamlParser->parse(file_get_contents($this->file), Yaml::PARSE_KEYS_AS_STRINGS);
$classes = $this->yamlParser->parse(file_get_contents($this->file));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the use statement be removed too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indeed

@xabbuh
Copy link
Member

xabbuh commented Jul 26, 2017

@GuilhemN Can you rebase here? #23635 has been merged up.

@GuilhemN
Copy link
Contributor Author

@xabbuh done

Copy link
Member

@nicolas-grekas nicolas-grekas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't the @deprecated annotation be added to PARSE_KEYS_AS_STRINGS in Yaml.php?

@GuilhemN
Copy link
Contributor Author

GuilhemN commented Aug 1, 2017

@nicolas-grekas indeed.

@@ -31,6 +31,11 @@ class Yaml
const PARSE_CONSTANT = 256;
const PARSE_CUSTOM_TAGS = 512;
const DUMP_EMPTY_ARRAY_AS_SEQUENCE = 1024;

/**
* @deprecated since version 3.4, to be removed in 4.0. Quote your evaluable
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be on one line

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed :)

@xabbuh
Copy link
Member

xabbuh commented Aug 3, 2017

Thank you @GuilhemN.

@xabbuh xabbuh closed this Aug 3, 2017
xabbuh added a commit that referenced this pull request Aug 3, 2017
…TRINGS (GuilhemN)

This PR was squashed before being merged into the 3.4 branch (closes #22948).

Discussion
----------

[Yaml] Recommend using quotes instead of PARSE_KEYS_AS_STRINGS

| Q             | A
| ------------- | ---
| Branch?       | 3.4
| Bug fix?      | no
| New feature?  | no <!-- don't forget updating src/**/CHANGELOG.md files -->
| BC breaks?    | no
| Deprecations? | yes <!-- don't forget updating UPGRADE-*.md files -->
| Tests pass?   | yes
| Fixed tickets | #... <!-- #-prefixed issue number(s), if any -->
| License       | MIT
| Doc PR        |

Sorry for opening this so lately... I just realized that we could get rid of `Yaml::PARSE_KEYS_AS_STRINGS` just by recommending using quotes...

~This way we don't allow a behavior not respecting the spec and we won't need to deprecate `PARSE_KEYS_AS_STRINGS` later.~

~Is it too late for this to be merged in 3.3?~

ping @xabbuh

Commits
-------

b63c55c [Yaml] Recommend using quotes instead of PARSE_KEYS_AS_STRINGS
@GuilhemN GuilhemN deleted the fix branch November 1, 2020 14:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants