Skip to content

[DependencyInjection][Bug] Cryptic service name with anonymous service as argument #26630

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
dkarlovi opened this issue Mar 22, 2018 · 19 comments

Comments

@dkarlovi
Copy link
Contributor

dkarlovi commented Mar 22, 2018

Q A
Bug report? no
Feature request? no
BC Break report? no
RFC? no
Symfony version 4.0

While working around #26629, I moved my service into a separate file, like this:

    <services>
        <service parent="liip_imagine.imagick" id="image.imagine">
            <call method="setMetadataReader">
                <argument type="service">
                    <service id="App\Infrastructure\Imagine\Metadata\ExifMetadataReader" lazy="true"/>
                </argument>
            </call>
        </service>
    </services>

This produces a very cryptic error (note the name, also the class is not set, but the ID is):

The definition for "1_~t2jBfn7" has no class. If you intend to inject this service dynamically at runtime, please mark it as synthetic=true. If this is an abstract definition solely used by child definitions, please add abstract=true, otherwise specify a class to get rid of this error.
@stof
Copy link
Member

stof commented Mar 22, 2018

Can you provide a reproducing case ? The service definition you gave above does not trigger this for me (are you sure it refers to this service ? this cryptic service id looks like one generated by the XMLFileLoader when defining a service without an id)

@dkarlovi
Copy link
Contributor Author

@stof very sure, the error goes away if I change the ID attrib to class attrib.

@xabbuh
Copy link
Member

xabbuh commented Mar 22, 2018

@dkarlovi Can you create a small example application that allows to reproduce the error?

@dkarlovi
Copy link
Contributor Author

@xabbuh sure.

@mitridates
Copy link

Same error message with a malformed services.xml
Once deleted the tag from an incomplete deleted service, the error goes away.

@xabbuh
Copy link
Member

xabbuh commented Mar 28, 2018

@mitridates A reproducible project would ease helping you.

@dkarlovi
Copy link
Contributor Author

@xabbuh I haven't forgotten to do it, just waiting for the month to roll over to free up some time :)

@nicolas-grekas
Copy link
Member

The XML loader creates randomly named services for anonymous declarations. Generating inlined definitions would fix the issue. I don't think there is any other way.

@dkarlovi
Copy link
Contributor Author

@nicolas-grekas can't it use some better naming? Like anonymous.liip_imagine.imagick.setMetadataReader.argument0 or something? Check for ID / Class or some other identifier? Even origin XML file name would be somewhat helpful.

Backtracking from this error would have been mission impossible.

@stof
Copy link
Member

stof commented Mar 28, 2018

As inline definitions are now a first-class citizen in Symfony since 3.4 (rather than being things which are not guaranteed to work fine all the time), I think we might now refactor the XML loader to stop turning anonymous services into named ones (but it may have to wait for 4.2 due to the feature freeze depending on how we consider this refactoring).

@dkarlovi
Copy link
Contributor Author

So, do you even need a test case then if the issue is understood?

@mitridates
Copy link

mitridates commented Mar 28, 2018

My case is not about of an anonymous service, only a wrong tag. I deleted the code but this example of services.xml throws the message as RuntimeException The definition for "1_c4eemeg" has no class. If you intend to inject... instead of an validArgumentException Unable to parse file ....
The tag <service/> is parsed as a service.

<?xml version="1.0" encoding="UTF-8" ?> <container xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://symfony.com/schema/dic/services" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> <services> <service/> </services> </container>

@stof
Copy link
Member

stof commented Mar 28, 2018

Well, you still have an anonymous service (without any config here), as a <service> tag is precisely what defines a service in the XML file.

@nicolas-grekas here is my proposal for a next version (probably 4.2 due to the feature freeze):

  • keep inline services as actual inline definition instead of turning them into named private services in the XML loader). This could even allow us to perform a better validation as a few settings don't make sense on inline services (like the id in the snippet of the issue description)
  • deprecate the definition of top-level anonymous services (which is supported only in XML). Symfony 5.0 could then even mark the id attribute as required in the XSD for top-level services and forbidden for inline ones (using separate XSD types for them; even though they would share most things, they are different)

@nicolas-grekas
Copy link
Member

Good news, top level services with no "id" are forbidden since 4.0, see

throw new InvalidArgumentException(sprintf('Top-level services must have "id" attribute, none found in %s at line %d.', $file, $node->getLineNo()));

Keeping inline services as inline definition should be doable, maybe for 4.1 also.
Anyone willing to give it a try? @dkarlovi maybe?

@dkarlovi
Copy link
Contributor Author

I would, but haven't studied the DI component until now, could use some pointers

@nicolas-grekas
Copy link
Member

Everything is in

private function processAnonymousServices(\DOMDocument $xml, $file, $defaults)

@dkarlovi
Copy link
Contributor Author

Alright. I'll have some time tomorrow so will try it.

@dkarlovi
Copy link
Contributor Author

@stof @nicolas-grekas, looking at this a bit, I mostly understand how it works currently, but this is a bit puzzling:

keep inline services as actual inline definition

What does "inline definition" mean in this jargon? Do I create the Definition instance with parseDefinition and then assign it as the argument of its parent?

@nicolas-grekas
Copy link
Member

Yes, we mean Definition instances instead of Reference

fabpot added a commit that referenced this issue Apr 20, 2018
… a dot (nicolas-grekas)

This PR was merged into the 4.1-dev branch.

Discussion
----------

[DI][FrameworkBundle] Hide service ids that start with a dot

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | yes
| Tests pass?   | yes
| Fixed tickets | #26630
| License       | MIT
| Doc PR        | -

Now that services are private by default, `debug:container` should display them by default.
In fact, the public/private concept should not trigger a difference in visibility for this command.

Instead, I propose to handle service ids that start with a dot as hidden services.

PR should be ready.

(For reference, I tried using a tag instead in #26891, but that doesn't work in practice when working on the implementation.)

Commits
-------

cea051e [DI][FrameworkBundle] Hide service ids that start with a dot
@fabpot fabpot closed this as completed Apr 20, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants