Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine
This tutorial has a new version, check it out!

Creating Services!

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 $10.00

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

Login Subscribe

Open ArticleController and find the show() action:

... lines 1 - 13
class ArticleController extends AbstractController
{
... lines 16 - 26
public function show($slug, MarkdownInterface $markdown, AdapterInterface $cache)
{
... lines 29 - 53
$item = $cache->getItem('markdown_'.md5($articleContent));
if (!$item->isHit()) {
$item->set($markdown->transform($articleContent));
$cache->save($item);
}
$articleContent = $item->get();
... lines 60 - 66
}
... lines 68 - 79
}

I think it's time to move our markdown & caching logic to a different file. Why? Two reasons. First, this method is getting a bit long and hard to read. And second, we can't re-use any of this code when it's stuck in our controller. And... bonus reason! If you're into unit testing, this code cannot be tested.

On the surface, this is the oldest trick in the programming book: if you want to re-use some code, move it into its own function. But, what we're about to do will form the cornerstone of almost everything else in Symfony.

Create the Service Class

Instead of moving this code to a function, we're going to create a new class and move into a new method. Inside src/, create a new directory called Service. And then a new PHP class called MarkdownHelper:

... lines 1 - 2
namespace App\Service;
class MarkdownHelper
{
... lines 7 - 16
}

The name of the directory - Service - and the name of the class are not important at all: you can put your code wherever you want. The power!

Inside, let's add a public function called, how about, parse(): with a string $source argument that will return a string:

... lines 1 - 4
class MarkdownHelper
{
public function parse(string $source): string
{
... lines 9 - 15
}
}

And... yea! Let's just copy our markdown code from the controller and paste it here!

... lines 1 - 4
class MarkdownHelper
{
public function parse(string $source): string
{
$item = $cache->getItem('markdown_'.md5($source));
if (!$item->isHit()) {
$item->set($markdown->transform($source));
$cache->save($item);
}
return $item->get();
}
}

I know, it's not going to work yet - we've got undefined variables. But, worry about that later. Return the string at the bottom:

... lines 1 - 4
class MarkdownHelper
{
public function parse(string $source): string
{
... lines 9 - 14
return $item->get();
}
}

And... congrats! We just created our first service! What? Remember, a service is just a class that does work! And yea, this class does work! The really cool part is that we can automatically autowire our new service.

Find your terminal and run:

Tip

Since Symfony 4.2 this command only shows service aliases. If you want to see all the services you can pass a --all option.

./bin/console debug:autowiring

Scroll up. Boom! There is MarkdownHelper. It already lives in the container, just like all the core services. That means, in ArticleController, instead of needing to say new MarkdownHelper(), we can autowire it: add another argument: MarkdownHelper $markdownHelper:

... lines 1 - 4
use App\Service\MarkdownHelper;
... lines 6 - 14
class ArticleController extends AbstractController
{
... lines 17 - 24
/**
* @Route("/news/{slug}", name="article_show")
*/
public function show($slug, MarkdownInterface $markdown, AdapterInterface $cache, MarkdownHelper $markdownHelper)
{
... lines 30 - 62
}
... lines 64 - 75
}

Below, simplify: $articleContent = $markdownHelper->parse($articleContent):

... lines 1 - 4
use App\Service\MarkdownHelper;
... lines 6 - 14
class ArticleController extends AbstractController
{
... lines 17 - 24
/**
* @Route("/news/{slug}", name="article_show")
*/
public function show($slug, MarkdownInterface $markdown, AdapterInterface $cache, MarkdownHelper $markdownHelper)
{
... lines 30 - 35
$articleContent = <<<EOF
... lines 37 - 52
EOF;
$articleContent = $markdownHelper->parse($articleContent);
... lines 56 - 62
}
... lines 64 - 75
}

Ok, let's try it! Refresh! We expected this:

Undefined variable $cache

Inside MarkdownHelper. But hold on! This proves that Symfony's container is instantiating the MarkdownHelper and then passing it to us. So cool!

Dependency Injection: The Wrong Way First

In MarkdownHelper, oh, update the code to use the $source variable:

... lines 1 - 4
class MarkdownHelper
{
public function parse(string $source): string
{
$item = $cache->getItem('markdown_'.md5($source));
if (!$item->isHit()) {
$item->set($markdown->transform($source));
$cache->save($item);
}
return $item->get();
}
}

Here's the problem: MarkdownHelper needs the cache and markdown services. To say it differently, they're dependencies. So how can we get them from here?

Symfony follows object-orientated best practices... which means that there's no way to magically fetch them out of thin air. But that's no problem! If you ever need a service or some config, just pass them in.

The easiest way to do this is to add them as arguments to parse(). I'll show you a different solution in a minute - but let's get it working. Add AdapterInterface $cache and MarkdownInterface $markdown:

... lines 1 - 4
use Michelf\MarkdownInterface;
use Symfony\Component\Cache\Adapter\AdapterInterface;
class MarkdownHelper
{
public function parse(string $source, AdapterInterface $cache, MarkdownInterface $markdown): string
{
... lines 12 - 18
}
}

If you try it now... it fails:

Too few arguments passed to parse(): 1 passed, 3 expected.

This makes sense! In ArticleController, we are calling parse():

... lines 1 - 14
class ArticleController extends AbstractController
{
... lines 17 - 27
public function show($slug, MarkdownInterface $markdown, AdapterInterface $cache, MarkdownHelper $markdownHelper)
{
... lines 30 - 54
$articleContent = $markdownHelper->parse($articleContent);
... lines 56 - 62
}
... lines 64 - 75
}

This is important: that whole autowiring thing works for controller actions, because that is a unique time when Symfony is calling our method. But everywhere else, it's good old-fashioned object-oriented coding: if we call a method, we need to pass all the arguments.

No problem! Add $cache and $markdown:

... lines 1 - 14
class ArticleController extends AbstractController
{
... lines 17 - 27
public function show($slug, MarkdownInterface $markdown, AdapterInterface $cache, MarkdownHelper $markdownHelper)
{
... lines 30 - 54
$articleContent = $markdownHelper->parse(
$articleContent,
$cache,
$markdown
);
... lines 60 - 66
}
... lines 68 - 79
}

And... refresh! It works! We just isolated our code into a re-usable service. We rule. Go high-five some strangers!

Proper Dependency Injection

Then come back! Because there's a much better way to do all of this. Whenever you have a service that depends on other services, like $cache or $markdown, instead of passing those in as arguments to the individual method, you should pass them via a constructor.

Let me show you: create a public function __construct(). Next, move the two arguments into the constructor, and create properties for each: private $cache; and private $markdown:

... lines 1 - 7
class MarkdownHelper
{
private $cache;
private $markdown;
public function __construct(AdapterInterface $cache, MarkdownInterface $markdown)
{
... lines 15 - 16
}
public function parse(string $source): string
{
... lines 21 - 27
}
}

Inside the constructor, set these: $this->cache = $cache and $this->markdown = $markdown:

... lines 1 - 7
class MarkdownHelper
{
private $cache;
private $markdown;
public function __construct(AdapterInterface $cache, MarkdownInterface $markdown)
{
$this->cache = $cache;
$this->markdown = $markdown;
}
... lines 18 - 28
}

By putting this in the constructor, we're basically saying that whoever uses the MarkdownHelper is required to pass us a cache object and a markdown object. From the perspective of this class, we don't care who uses us, but we know that they will be forced to pass us our dependencies.

Thanks to that, in parse() we can safely use $this->cache and $this->markdown:

... lines 1 - 7
class MarkdownHelper
{
private $cache;
private $markdown;
public function __construct(AdapterInterface $cache, MarkdownInterface $markdown)
{
$this->cache = $cache;
$this->markdown = $markdown;
}
public function parse(string $source): string
{
$item = $this->cache->getItem('markdown_'.md5($source));
if (!$item->isHit()) {
$item->set($this->markdown->transform($source));
$this->cache->save($item);
}
... lines 26 - 27
}
}

One of the advantages of passing dependencies through the constructor is that it's easier to call our methods: we only need to pass arguments that are specific to that method - like the article content:

... lines 1 - 14
class ArticleController extends AbstractController
{
... lines 17 - 27
public function show($slug, MarkdownInterface $markdown, AdapterInterface $cache, MarkdownHelper $markdownHelper)
{
... lines 30 - 54
$articleContent = $markdownHelper->parse($articleContent);
... lines 56 - 62
}
... lines 64 - 75
}

And, hey! We can also remove the extra controller arguments. And, on top, we don't need to, but let's remove the old use statements:

... lines 1 - 4
use App\Service\MarkdownHelper;
use Psr\Log\LoggerInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Twig\Environment;
class ArticleController extends AbstractController
{
... lines 15 - 25
public function show($slug, MarkdownHelper $markdownHelper)
{
... lines 28 - 60
}
... lines 62 - 73
}

Configuring the Constructor Args?

But there's still one big question! How did nobody notice that there was a thermal exhaust pipe that would cause the whole Deathstar to explode? And also, because the container is responsible for instantiating MarkdownHelper, how will it know what values to pass? Don't we need to somehow tell it that it needs to pass the cache and markdown services as arguments?

Actually, no! Move over to your browser and refresh. It just works.

Black magic! Well, not really. When you create a service class, the arguments to its constructor are autowired. That means that we can use any of the classes or interfaces from debug:autowiring as type-hints. When Symfony creates our MarkdownHelper:

... lines 1 - 4
use App\Service\MarkdownHelper;
... lines 6 - 12
class ArticleController extends AbstractController
{
... lines 15 - 25
public function show($slug, MarkdownHelper $markdownHelper)
{
... lines 28 - 60
}
... lines 62 - 73
}

It knows what to do!

Yep, we just organized our code into a brand new service and touched zero config files. This is huge!

Next, let's get smarter, and find out how we can access core services that cannot be autowired.

Leave a comment!

55
Login or Register to join the conversation
Ad F. Avatar

./bin/console debug:autowiring

In DefinitionErrorExceptionPass.php line 54:

Cannot autowire service "App\Service\MarkdownHelper": argument "$isDebug" o
f method "__construct()" is type-hinted "bool", you should configure its value explicitly.

any idea ?

1 Reply
victor Avatar victor | SFCASTS | Ad F. | posted 4 years ago | edited

Hey Ad F. ,

The error make sense, Symfony unable to guess what exactly value to pass for $isDebug parameter, so just specify it obviously:


services:
App\Service\MarkdownHelper:
arguments:
$isDebug: 'your-value-here'

Cheers!

1 Reply
Default user avatar
Default user avatar Anna Filina | victor | posted 3 years ago

I did exactly that and I still see the error. Every reference online gives the same answer. It almost feels like I hit a bug or something.

Reply

Hey Anna,

Hm, looks like it helped Anna Filina :/ What Symfony version do you use? Could you clear the cache and try again?

Cheers!

Reply
Richard Avatar
Richard Avatar Richard | posted 2 years ago

Is there any benefit of somehow constructing with a singleton pattern so the services are statics?

Reply

Hey Richard

When you use Dependency injection in Symfony, it's like all your services were a Singleton. The container will give you always the same object (during the same request, of course)

Cheers!

Reply
Dung L. Avatar
Dung L. Avatar Dung L. | posted 2 years ago

Hello SymfonyCasts,

With your help thus far I can now even dive in deeper with Symfony 4. Thanks!

My story is. The way I collect data and store data in dbase for my application is not thru an input form, but from a web host json page like this tutorial (https://symfonycasts.com/sc....

I use file_get_contents() to read it, then in Controller/ I write (class ImportController extends AbstractController) to process the data and store data into the mysql database (I write entity classes for each db table and using Entity->setProperty() to persist data to database as normal standard Symfony routines). So when I want to import data to database I have to hit a url such as https://localhost:8000/import-data/community.json this will call to the route/import-data controller and everything works perfectly! Database and relations populated.

Now, I realized this can be a problem such as php execution timeout, security vulnerability and etc ... SO here is my question: Can I move this controller class with many functions in it to a Service or ConsoleCommand etc .. so that I can execute it internally and re-use it?

I have tried to moved this controller class ImportController to both Services and Command (console commands) but failed with errors such as:

In ControllerTrait.php line 333:
Call to a member function has() on null

In JsonImport.php line 80:
Attempted to call an undefined method named "getDoctrine" of class "App\Service\JsonImport".

Thank you so much for your guidance, please point me to a direction.

Dung.

Reply

Hey Dung L.

That's an interesting use case :)

What you can do is to extract all the logic for importing the data from the URL and just use such service from a Controller or a Command. You can inject your service by using normal dependency injection. I believe you are relying on the auto-config and auto-register functionality of Symfony4

Cheers!

Reply
Dung L. Avatar
Dung L. Avatar Dung L. | MolloKhan | posted 2 years ago | edited

Hello MolloKhan,

I am not sure you understood my question, so here is the entire class code, can you please take a closer look and guide me again since I did not understand what to do.

https://uofc-my.sharepoint....

the import call is from a url exactly like this:

https://localhost:8000/import-data/community2.json

I can also post the Repository/Services/Command/Entity and Templates if needed.

*** I am on the auto-config and auto-register functionality of Symfony4

Thanks so much!

Dung.

Reply
Dung L. Avatar
Dung L. Avatar Dung L. | Dung L. | posted 2 years ago | edited

Hi Dung L.,

So if I did understand your suggestion hence I tried to transform this controller class to a service class and it looks like this within Service folder.

https://uofc-my.sharepoint....

Now that the service above is created I use it in Command, in command I wrote it like this (please ignore codes from SymfonyCasts' tutorial) in Command folder. And just focus on method $jsonImport->importEstateDataAction.

https://uofc-my.sharepoint....

And finally I test it in Command line as described in this image and resulted in error as in image.

https://uofc-my.sharepoint....

I would like to ask you:

Changing to this implementation in order to import data from Json file to database is proper way to import json data to database? Can you see how to fix this error? Is there a better way to achieve what I want to do. If you can please point me to the right direction I very much appreciate!

Dung.

Reply

Hey Dung L.

Oh, I see what you did. You need to be aware of when you are working out of a controller you don't have access to any of its methods, or access to the container. What you need to do is to inject the EntityManager into your service, and replace all calls to $this->getDoctrine()
E.G.


// YourService.php

use Doctrine\ORM\EntityManagerInterface;

class SomeService
{
// This is how you inject the EntityManager into your service
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
}

Cheers!

Reply
Dung L. Avatar
Dung L. Avatar Dung L. | MolloKhan | posted 2 years ago | edited

Hi MolloKhan ,

how do I instantiate this service class in console/command class? true are not the right args


protected function execute(InputInterface $input, OutputInterface $output): int
{
$jsonImport = new JsonImport(true, true);

Thanks!
D.

Reply
Dung L. Avatar
Dung L. Avatar Dung L. | Dung L. | posted 2 years ago | edited

Hi Dung L.

- so i changed service class to - see link

https://uofc-my.sharepoint....

- then initialized this service class in console/command class - see link

https://uofc-my.sharepoint....

- finally ran this command resulted in error - see link

https://uofc-my.sharepoint....

I know that I am confused and not knowing how to use the service class, where to make call, but I am not sure how to overcome it. Thanks for any help!

Dung.

Reply
Dung L. Avatar

Uhm, may be I can not call/use it within console commands?

Reply
Dung L. Avatar

I found this doc https://symfony.com/doc/cur... will try it out :)

Reply
Dung L. Avatar

updated code for ImportDataCommand.php in Command dir:
https://uofc-my.sharepoint....

new error but better error I believe:
https://uofc-my.sharepoint....

I think i am closer

Reply
Dung L. Avatar
Dung L. Avatar Dung L. | Dung L. | posted 2 years ago | edited

yes, got it. The problem is exact what we see in the error message :), great job Symfony! So in Service's JsonImport class, I changed the constructor method type-hint to class interface instead of class type as seen below and it works :) (replaced EntityManager type to EntityManagerInterface type)

public function __construct(bool $isDebug, EntityManagerInterface $entityManager)
{
$this->isDebug = $isDebug;
$this->entityManager = $entityManager; // EntityManagerInterface $entityManager
}

Thank you Dung L. for your pointer. KnpUniversity you are awesome :)

Dung.

Reply

Hey Dung L.

I'm so glad to hear that you could fix your problem. Nice job man and thanks for the kind words :)

Reply
Benoit L. Avatar
Benoit L. Avatar Benoit L. | posted 3 years ago

Hi,$cache and $markdown are passed when instantiating the MarkdownHelper, but imagine that $cache and $markdown need to be configured, how is it done?

Reply

Hey Benoit L.

If you need to configure a service because the autowiring feature can't do it for you (like injecting a string value), there are a couple of ways to do it. I'll point you to the documentation, so you can get a better understanding of what's going on but if you have more doubts let us know :)
https://symfony.com/doc/cur...

Cheers!

Reply
Lijana Z. Avatar
Lijana Z. Avatar Lijana Z. | posted 3 years ago

Autowiring is super awesome feature, it shouold have been existing earlier. I think in Laravel 4 when I was injecting, I did not need setting configs for each class, and when I went to symfony for me it was weird to have so much manual work.

Reply

Hey Coder,

Thank you for your feedback about autowiring! Agree, it's a great feature!

Cheers!

Reply
Saruulbuyan O. Avatar
Saruulbuyan O. Avatar Saruulbuyan O. | posted 3 years ago

For some reason, i always need to restart my server to see the change after i edited and saved my file. Or after waiting a minute and then hitting refresh, only then i can see the changes. Doing a cache:clear, then hitting refresh crashes my server with the following error:
- [ERROR] Server terminated unexpectedly.
I'm in dev environment. Can someone please help?

Reply

Hey Saruulbuyan,

That's weird :) Can you tell me on which Symfony version are you and how are you starting your web server? Also double check that you are running on dev environment by running bin/console - at the top of the output you will see the environment

Cheers!

Reply
Saruulbuyan O. Avatar
Saruulbuyan O. Avatar Saruulbuyan O. | MolloKhan | posted 3 years ago

Hi Diego,
Sorry for not answering quickly.
- I'm using Symfony version 4.2.4.
- I'm starting the server by running the following command:
php bin/console server:run
- Running the command bin/console, I get this:
"Symfony 4.2.4 (env: dev, debug: true)"

In later tutorials I downloaded the source codes and I didn't have problem like this. Until tutorial "Symfony 4 Forms: Build, Render & Conquer!". I'm back to this issue. But in this tutorial("Symfony 4 Forms") I'm using Symfony version 4.1.6.

Reply

Interesting... I'm not sure what's causing it but at least you can try deleting your vendor directory and run composer install && composer update
If it's still failing, please reply to my following questions:
On what OS are you?
What's your PHP version?
Did you modify public/index.php file?
Double check file permissions under var/ folder

Reply
Saruulbuyan O. Avatar
Saruulbuyan O. Avatar Saruulbuyan O. | MolloKhan | posted 3 years ago

I tried deleting vendor dir and ran the following commands:
- composer install
- composer update
Still the same... Answering your questions:
- My OS: Windows 10 Home 1803
- PHP version: 7.1.27
- I didn't modify public/index file
- I don't know how to check file permissions under var/ folder or any folder('I'm still new to this... Sorry')

Reply

Hey Saruulbuyan O.

Try to run php -S localhost:8000 -t public/ and look if it fails again. If it will have same issues, than we will need to check php extensions and configuration. First try to disable all non-standard dlls for example xdebug, apcu, opcache and than repeat your test. Better to disable one by one to guess what exactly cause the issue.

Cheers!

Reply
Saruulbuyan O. Avatar
Saruulbuyan O. Avatar Saruulbuyan O. | sadikoff | posted 3 years ago

Hi Vladimir,
I tried running php -S localhost:8000 -t public/. Still the same.
As for extensions i've only installed acpu, but never used in symfony. But I still tried disabling acpu extension but no change...
I tried it in chrome, firefox, opera and even edge browsers... I still always have to restart the server to see the changes on my browser. It's not a major issue, but still annoying. Thanks anyways for the help guys :)

Reply

Hm this is interesting. What about php_opchache.dll? It's installed in php be default. Have you installed php manually? Oh and could you please re-install vendors
1. Delete vendor/ directory
2. run composer install (now without update just install)
And last question, could you please share complete php -v output?

Reply
Saruulbuyan O. Avatar
Saruulbuyan O. Avatar Saruulbuyan O. | sadikoff | posted 3 years ago

It works!!!! I disabled php_opcache.dll And now Its working normally. I can see my changes immediately. Thank you sir! :) In case you need my php -v ouptput:
PHP 7.1.27 (cli) (built: Mar 6 2019 20:51:04) ( ZTS MSVC14 (Visual C++ 2015) x64 )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.1.27, Copyright (c) 1999-2018, by Zend Technologies

Reply
Med karim G. Avatar
Med karim G. Avatar Med karim G. | posted 3 years ago

Hi, Why When I do bin/console debug:autowiring | grep "cache" -B 1, there is 2 alias to cache.app; result:
--
Psr\Cache\CacheItemPoolInterface
alias to cache.app
--
Symfony\Component\Cache\Adapter\AdapterInterface
alias to cache.app
---
And Why did u shoose the second One ?

Reply

Hey Med,

Actually, it's not too much important, you can chose any of those two. But CacheItemPoolInterface is more low-level, i.e. AdapterInterface "extends" CacheItemPoolInterface. There are technical reasons behind of it, most probably AdapterInterface has been existed before CacheItemPoolInterface and I think it might be that AdapterInterface will be deprecated in the future, or maybe not, I'm not sure. But since you use Symfony - it makes sense to typehint with AdapterInterface I think.

Cheers!

Reply
Abelardo L. Avatar
Abelardo L. Avatar Abelardo L. | posted 3 years ago

Hi everyone,

I have created a new class src\Service\EmailSender and I created a public function called sendEmail.
Then, I run ./bin/console debug:autowiring but it doesn't appear in the output list.

What's wrong when I created this class as service?

Brs.

Reply

Hey Abelardo L.!

Don't worry - it should work :). There was a change in Symfony 4.2 - debug:autowiring no longer shows YOUR services - it only shows third-party services. We will soon be adding a note to this tutorial to make sure people know - it's confusing if you're not expecting it.

Cheers!

1 Reply

Actually, let me be a bit more accurate. Check out my other comment below: https://symfonycasts.com/sc...

Cheers!

1 Reply
Abelardo L. Avatar

Thanks so much for your quick reply!

Happy days!

Reply
akincer Avatar
akincer Avatar akincer | posted 3 years ago

So bin/console debug:autowiring doesn't show my custom service (neither does --show-private) but I can still autowire the service just fine as shown in the tutorial. Is this some kind of change from when this video was made?

Reply

Hey Aaron,

Do you see your service if you run bin/console debug:container?

Reply
akincer Avatar

Yes, it's there.

Reply

Hey Aaron!

No worries - you are FINE. We need to add a note to this tutorial for a change in Symfony 4.2. Starting in Symfony 4.2, debug:autowiring ONLY shows 3rd-party autowireable services - it does not show your OWN services that are autowirable (the idea is that you already know about this stuff). Sorry if that confused you - we're going to add it to our list to add a note!

Cheers!

Reply

Actually, let me be a bit more accurate. It now only shows service "aliases", and by default, the services that you create are not aliases, so they don't show up. If that doesn't make sense to you, don't worry :). You can also pass a --all option to see everything.

1 Reply
Sarah V. Avatar
Sarah V. Avatar Sarah V. | posted 3 years ago

I get following error:

Cannot resolve argument $markdownHelper of "App\Controller\ArticleController::show()": Cannot autowire service "App\Service\MarkdownHelper": argument "$cache" of method "__construct()" has type "App\Service\AdapterInterface" but this class was not found.

In the logging:

CRITICAL
17:31:11
request Uncaught PHP Exception Symfony\Component\DependencyInjection\Exception\RuntimeException: "Cannot resolve argument $markdownHelper of "App\Controller\ArticleController::show()": Cannot autowire service "App\Service\MarkdownHelper": argument "$cache" of method "__construct()" has type "App\Service\AdapterInterface" but this class was not found." at /Users/sarah/Sites/the_spacebar/var/cache/dev/ContainerKfYMbmx/getMarkdownHelperService.php line 9

Any idea?

Does it have to do with this when I do ./bin/console debug:autowiring
Symfony\Component\Cache\Adapter\AdapterInterface
alias to cache.app

Reply

Hey Sarah V.!

Ah! This is a tricky one! Ok, look at this part of the error message closely:

> $cache" of method "__construct()" has type "App\Service\AdapterInterface" but this class was not found.

The clue is that, for some reason, PHP thinks that you have type-hinted your argument with App\Service\AdapterInterface. But of course, you intended this to be Symfony\Component\Cache\Adapter\AdapterInterface.

The problem is that you're missing the use statement for the AdapterInterface class at the top of your MarkdownHelper service. Because of this, PHP assumes that the AdapterInterface must live in the *current* namespace (App\Service) not the one you want.

Add the use statement and this will all work instantly! Missing use statements are one of the most annoying, but common issues. You'll quickly learn to spot them and fix them :).

Cheers!

Reply
Abelardo L. Avatar
Abelardo L. Avatar Abelardo L. | posted 4 years ago

Hi everyone,

Why does this message appear after to write "php bin/console debug:autowiring"?

In ContainerBuilder.php line 1011:

You have requested a non-existent Service "session.storage.native".

What's wrong?

Best regards.

Reply

Hey Abelardo L.

That's odd, are you requesting that service in your "services.yaml" file?
Can you tell me which Symfony version are you using?

If you haven't done anything interesting, probably is just an unexpected error, try clearing the cache and/or reinstalling your vendors

Cheers!

Reply
Abelardo L. Avatar

Hi @Diego Aguiar,

"services.yaml" file? Where is it explained during the video?

Symfony 4.

You meant to delete the vendor dir and execute composer install ...or what another command should I use to reinstall my vendors?

Best regards.

Reply

Hey Abelardo,

Did you download the code for this course? I just tried to download the code and run "bin/console debug:autowiring" and I do not see this error. Yes, Diego means deleting vendor/ dir and re-installing dependencies, i.e:
$ rm -rf vendor/
$ composer install

I don't see we're talking about "session.storage.native" service in this course, or tell me if I'm wrong. So probably this error does not relates to some changes we're doing in this screencast.

So try to clear the cache before running "bin/console debug:autowiring". Does it helps? Or you still see this error?

And yeah, we understand that you're on Symfony 4, but could you tell us more precise version, like v4.0.14 that we're using in this course. You can see it in the Symfony web debug toolbar in the right bottom cornet.

Cheers!

Reply
Abelardo L. Avatar

Anybody here?

Reply

Hey Abelardo!

Yeah, we're here! Sorry for the delay. I answered your previous comment, hope this helps you, if not - let us know.

Cheers!

Reply
Cat in space

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

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": "^7.1.3",
        "ext-iconv": "*",
        "knplabs/knp-markdown-bundle": "^1.7", // 1.7.0
        "nexylan/slack-bundle": "^2.0,<2.2.0", // v2.0.0
        "php-http/guzzle6-adapter": "^1.1", // v1.1.1
        "sensio/framework-extra-bundle": "^5.1", // v5.1.4
        "symfony/asset": "^4.0", // v4.0.4
        "symfony/console": "^4.0", // v4.0.14
        "symfony/flex": "^1.0", // v1.17.6
        "symfony/framework-bundle": "^4.0", // v4.0.14
        "symfony/lts": "^4@dev", // dev-master
        "symfony/twig-bundle": "^4.0", // v4.0.4
        "symfony/web-server-bundle": "^4.0", // v4.0.4
        "symfony/yaml": "^4.0" // v4.0.14
    },
    "require-dev": {
        "easycorp/easy-log-handler": "^1.0.2", // v1.0.4
        "symfony/debug-bundle": "^3.3|^4.0", // v4.0.4
        "symfony/dotenv": "^4.0", // v4.0.14
        "symfony/maker-bundle": "^1.0", // v1.0.2
        "symfony/monolog-bundle": "^3.0", // v3.1.2
        "symfony/phpunit-bridge": "^3.3|^4.0", // v4.0.4
        "symfony/profiler-pack": "^1.0", // v1.0.3
        "symfony/var-dumper": "^3.3|^4.0" // v4.0.4
    }
}