Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Aliases & When Autowiring Fails

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $6.00

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

Let's talk more about what happens when autowiring goes wrong. Right now, the MarkdownTransformer class has two arguments, type-hinted with MarkdownParserInterface and Cache from Doctrine:

... lines 1 - 4
use Doctrine\Common\Cache\Cache;
use Knp\Bundle\MarkdownBundle\MarkdownParserInterface;
class MarkdownTransformer
{
... lines 10 - 12
public function __construct(MarkdownParserInterface $markdownParser, Cache $cache)
{
... lines 15 - 16
}
... lines 18 - 33
}

But, these are not being autowired: we're explicitly specifying each argument:

... lines 1 - 5
services:
... lines 7 - 26
AppBundle\Service\MarkdownTransformer:
arguments: ['@markdown.parser', '@doctrine_cache.providers.my_markdown_cache']
... lines 29 - 42

Letting Symfony tell you about Autowiring Failures

If I were creating this service today, I actually wouldn't specify any configuration at first. Nope, I'd just create the class, add the type-hints, and let Symfony tell me if it had any problems autowiring my arguments.

To show off one of the ways autowiring can fail, I'm going to remove the first argument and set it to an empty string:

... lines 1 - 5
services:
... lines 7 - 26
AppBundle\Service\MarkdownTransformer:
arguments: ['', '@doctrine_cache.providers.my_markdown_cache']
... lines 29 - 41

When you do this, it means that you do want Symfony to try to autowire it. Symfony will try to autowire the first argument, but not the second. Actually, if this looks ugly to you, I agree! In a few minutes, I'll show you a cleaner way of explicitly wiring only some arguments.

Anyways, let's see if the MarkdownParserInterface type-hint can be autowired. Refresh the page... or any page.

Explosion!

Cannot autowire service AppBundle\Service\MarkdownTransformer: argument $markdownParser.

It's very clearly saying that there is a problem with this specific argument.

The error continues:

... it references interface MarkdownParserInterface but no such service exists.

This is because it's looking for a service with exactly this id. But, none was found! So, it tries to help out:

You should maybe alias this interface to one of these existing services.

and it lists one, two, three, four, five services in the container that implement MarkdownParserInterface. This is autowiring the Symfony way: there's no guess work.

Using Aliases to add Valid Autowiring Types

Previously, we were using a service called markdown.parser. Find your terminal and get some information about this service:

php bin/console debug:container markdown.parser

Interesting! This is actually an alias to markdown.parser.max. This service comes from KnpMarkdownBundle, and it ships with a few different markdown parsers. It then creates an alias from markdown.parser to whatever parser we configured as the default.

So to fix the error, we have two options. First, we could of course explicitly specify the argument, just like we were doing before. Or, as the error suggests, we can create an alias. Let's do that: alias Knp\Bundle\MarkdownBundle\MarkdownParserInterface to @markdown.parser:

... lines 1 - 5
services:
... lines 7 - 26
# alias to allow this type to be autowired
Knp\Bundle\MarkdownBundle\MarkdownParserInterface: '@markdown.parser'
... lines 29 - 44

We just told Symfony exactly what service to autowire when it sees the MarkdownParserInterface type-hint. In theory, KnpMarkdownBundle would come with this alias already, and it probably will in the future.

Try the page! It works!

Leave a comment!

0
Login or Register to join the conversation
Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=5.5.9",
        "symfony/symfony": "3.3.0-RC1", // v3.3.0-RC1
        "doctrine/orm": "^2.5", // 2.7.5
        "doctrine/doctrine-bundle": "^1.6", // 1.10.3
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.3.5
        "symfony/swiftmailer-bundle": "^2.3", // v2.6.7
        "symfony/monolog-bundle": "^3.1", // v3.2.0
        "symfony/polyfill-apcu": "^1.0", // v1.23.0
        "sensio/distribution-bundle": "^5.0", // v5.0.25
        "sensio/framework-extra-bundle": "^3.0.2", // v3.0.29
        "incenteev/composer-parameter-handler": "^2.0", // v2.1.4
        "composer/package-versions-deprecated": "^1.11", // 1.11.99.4
        "knplabs/knp-markdown-bundle": "^1.4", // 1.7.1
        "doctrine/doctrine-migrations-bundle": "^1.1", // v1.3.2
        "stof/doctrine-extensions-bundle": "^1.2" // v1.3.0
    },
    "require-dev": {
        "sensio/generator-bundle": "^3.0", // v3.1.7
        "symfony/phpunit-bridge": "^3.0", // v3.4.47
        "nelmio/alice": "^2.1", // v2.3.6
        "doctrine/doctrine-fixtures-bundle": "^2.3" // v2.4.1
    }
}
userVoice