-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[DI][Yaml] Add the !yaml_file YAML tag to inject parsed YAML in a service #30446
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
Conversation
!yaml_file
YAML custom tag!yaml_file
YAML custom tag
!yaml_file
YAML custom tag
I like the idea 💡 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you provide a testcase with a json file or an invalid yaml file?
services: | ||
my_awesome_service_with_yaml_inside: | ||
arguments: | ||
- !yaml_file '%fixture_dir%/test_yaml_file.yaml' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a newline to remove the red icon
@@ -0,0 +1,3 @@ | |||
foo: | |||
bar: true | |||
baz: 42 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a newline to remove the red icon
@@ -748,6 +748,11 @@ private function resolveServices($value, $file, $isParameter = false) | |||
|
|||
return new Reference($id); | |||
} | |||
if ('yaml_file' === $value->getTag()) { | |||
$file = $this->container->resolveEnvPlaceholders($argument, true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should define a root for relative files. I suggest using the file where the tag is found when it makes sense (when parsing a file), and to throw an exception otherwise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also I don't think this should resolve env vars. Env vars are for runtime parameters, loading yaml is compile time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure if this makes sense to use it as root where the file is found, but maybe relative from project dir?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The component doesn't know what a project dir is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed. Tests are failing on Travis for PHP 7.3, but running on Docker it's working for me. Any idea what's going on?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO, this should be implemented as a special kind of Argument, that would be available for all configuration formats.
And this also misses defining the YAML file as a resource, to refresh the cached container automatically in dev when you edit the YAML file. This should be fixed, otherwise DX suffers.
throw new InvalidArgumentException("Unable to locate file \"$argument\". Please provide a path relative to \"$rootDir\" or an absolute path."); | ||
} | ||
|
||
return $this->yamlParser->parseFile($file, Yaml::PARSE_CONSTANT); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fact that the loader itself is parsing the file means that this feature is available only in the YamlFileLoader, not in other formats. That's quite unexpected (all other features can be configured in all formats).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@stof are you suggesting creating a new kind of argument implementing Symfony\Component\DependencyInjection\Argument\ArgumentInterface
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well in PHP this can be easily done by parsing thanks to the YAML component directly, but xml
would need a new argument type too I guess, something like:
<service id="my_awesome_service_with_yaml_argument" class="foo">
<argument type="yaml_file">%kernel_project_dir%/data/some_file.yaml</argument>
</service>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, using XML, my comment does not make sense anymore, yaml_file
is better 👍
@@ -748,6 +748,16 @@ private function resolveServices($value, $file, $isParameter = false) | |||
|
|||
return new Reference($id); | |||
} | |||
if ('yaml_file' === $value->getTag()) { | |||
$rootDir = \dirname($file); | |||
$file = \is_file($argument) ? $argument : "$rootDir/$argument"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this won't support using %kernel.project_dir%/some_file.yaml
, as it won't be resolved yet here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was the case before but @nicolas-grekas suggested that we should not resolve parameters (see above)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
he suggested not to resolve env placeholders. Resolving parameters is not the same.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I love this feature, thank you Gary!
Since the tag is meant to be used when writing YAML why not just call it !yaml
?
There should not be any confusion between passing a string or a path in this context.
@@ -209,6 +209,7 @@ | |||
<xsd:attribute name="name" type="xsd:string" /> | |||
<xsd:attribute name="on-invalid" type="invalid_sequence" /> | |||
<xsd:attribute name="tag" type="xsd:string" /> | |||
<xsd:attribute name="yaml_file" type="xsd:string" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In XML it should be yaml-file
(same below)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed!
If yes, please update the PR title accordingly 👍 |
throw new \InvalidArgumentException('You need to install the YAML component to parse YAML files.'); | ||
} | ||
|
||
$filePath = $this->container->getParameterBag()->resolveValue((string) $arg->nodeValue); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (!\is_file($filePath = $this->container->getParameterBag()->resolveValue((string) $arg->nodeValue))) {
$rootDir = \dirname($file);
if (!\is_file($filePath = "$rootDir/$filePath")) {
throw new InvalidArgumentException("Unable to locate file \"{$arg->nodeValue}\". Please provide a path relative to \"$rootDir\" or an absolute path.");
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shorter indeed
|
||
$this->container->addResource(new FileResource($filePath)); | ||
|
||
$arguments[$key] = Yaml::parseFile($filePath, Yaml::PARSE_CONSTANT); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about
$arguments[$key] = $this->container->getParameterBag()->resolveValue(
Yaml::parseFile($filePath, Yaml::PARSE_CONSTANT)
);
?
That would allow using nested parameters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice idea!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not needed. Parameters in arrays are already resolved, and at a better time (late enough that parameter overrides are already applied)
871eea1
to
34dc1e1
Compare
This should also be supported when using the PHP configurators (and saying that they can resolve the file path and parse it manually is not a good argument, as they would also have to track the resources, etc...) |
@stof are you suggesting to create a nezw argument impleting |
yes, this should be the way to go - and these should be resolved by an early compiler pass |
We discussed this with @GaryPEGEOT on Slack, and the conclusion is that we should save ourselves from this. 👎 from me. The reasoning is that this serves no use case that is not covered already by either:
But the added complexity is real (code+doc+teaching+maintaince+etc) |
Allow to inject the content of a YAML file to a service:
Or
The parsed YAML will here be injected as first argument