8000 [DI][Yaml] Add the !yaml_file YAML tag to inject parsed YAML in a service by GaryPEGEOT · Pull Request #30446 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[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

Closed
wants to merge 10 commits into from

Conversation

GaryPEGEOT
Copy link
Contributor
@GaryPEGEOT GaryPEGEOT commented Mar 4, 2019
Q A
Branch? master
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets #30386
License MIT
Doc PR symfony/symfony-docs#11121

Allow to inject the content of a YAML file to a service:

services:
  App\AwesomeServiceWithYamlInside:
    arguments:
      - !yaml_file '%kernel.root_dir/some/dir/relative/file.yaml'

Or

<service id="my_service" class="App\ServiceWithYamlInside">
    <argument type="yaml_file">%kernel.root_dir%/some/file.yaml</argument>
</service>

The parsed YAML will here be injected as first argument

@GaryPEGEOT GaryPEGEOT changed the title Add the !yaml_file YAML custom tag [DI][Yaml] Add the !yaml_file YAML custom tag Mar 4, 2019
@GaryPEGEOT GaryPEGEOT changed the title [DI][Yaml] Add the !yaml_file YAML custom tag [DI][Yaml] Add the !yaml_file YAML tag to inject parsed YAML in a service Mar 4, 2019
@OskarStark
Copy link
Contributor

I like the idea 💡

Copy link
Contributor
@OskarStark OskarStark left a 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'
Copy link
Contributor

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
Copy link
Contributor

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);
Copy link
Member

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.

Copy link
Member

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.

Copy link
Contributor

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?

Copy link
Member
@nicolas-grekas nicolas-grekas Mar 5, 2019

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.

Copy link
Contributor

Choose a reason for hiding this comment

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

True

Copy link
Contributor Author

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?

Copy link
Member
@stof stof left a 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);
Copy link
Member

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).

Copy link
Contributor Author
@GaryPEGEOT GaryPEGEOT Mar 9, 2019

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?

Copy link
Contributor
@HeahDude HeahDude Mar 9, 2019

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>

Copy link
Contributor

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";
Copy link
Member

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.

Copy link
Contributor Author

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)

Copy link
Member

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed!

B41A
@nicolas-grekas nicolas-grekas added this to the next milestone Mar 7, 2019
Copy link
Contributor
@HeahDude HeahDude left a 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" />
Copy link
Contributor

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)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed!

@OskarStark
Copy link
Contributor

Since the tag is meant to be used when writing YAML why not just call it !yaml?

If yes, please update the PR title accordingly 👍

HeahDude added a commit to HeahDude/symfony that referenced this pull request Mar 22, 2019
throw new \InvalidArgumentException('You need to install the YAML component to parse YAML files.');
}

$filePath = $this->container->getParameterBag()->resolveValue((string) $arg->nodeValue);
Copy link
Contributor

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.");
    }
}

Copy link
Contributor Author

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);
Copy link
Contributor

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nice idea!

Copy link
Member

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)

@GaryPEGEOT GaryPEGEOT force-pushed the feature/yaml-file-tag branch from 871eea1 to 34dc1e1 Compare March 23, 2019 19:04
@stof
Copy link
Member
stof commented Mar 28, 2019

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...)

@GaryPEGEOT
Copy link
Contributor Author

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 Symfony\Component\DependencyInjection\Argument\ArgumentInterface, or do you have something else in mind?

@nicolas-grekas
Copy link
Member

create a nezw argument impleting Symfony\Component\DependencyInjection\Argument\ArgumentInterface

yes, this should be the way to go - and these should be resolved by an early compiler pass

@nicolas-grekas
Copy link
Member
nicolas-grekas commented May 24, 2019

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:

  • a parameter
  • an import statement
  • an edit to the Kernel of the app to load a specific file
  • a mix of the 3 above

But the added complexity is real (code+doc+teaching+maintaince+etc)

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.

7 participants
0