Autowire not working in Symfony's Dependency Injection component - php

I am using Symfony's Dependency Injection component version 3.4 in my custom PHP project. My project is running on PHP 5.6
"symfony/dependency-injection": "^3.4"
I have defined my services.yaml file to contain following service definitions
logger:
class: Monolog\Logger
arguments: ["application"]
autowire: true
public: true
Monolog\Logger: '#logger'
plugin_context:
class: MyProject\PluginContext
autowire: true
public: true
I can confirm that the autoloading is working and the instance of both classes are present in the definition, but the Logger class is not autowired in PluginContext constructor. the class is defined in the following code
use Monolog\Logger;
class PluginContext
{
private $logger;
function __construct(Logger $logger) {
$this->logger = $logger;
}
}
When the following code is run, PHP throws an exception
$container->get("plugin_context");
Catchable fatal error: Argument 1 passed to MyProject\PluginContext::__construct() must be an instance of Monolog\Logger, none given

Change your FQCN $logger and use this one use Psr\Log\LoggerInterface instead Monolog\Logger
Another thing, thanks to autowiring you don't need to specify anything in service.yaml except this (the default configuration):
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
public: false # Allows optimizing the container by removing unused services; this also means
# fetching services directly from the container via $container->get() won't work.
# The best practice is to be explicit about your dependencies anyway.
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../src/*'
exclude: '../src/{Entity,Migrations,Tests,Kernel.php}'
The Doc said : « Aliases are used by the core bundles to allow services to be autowired. For example, MonologBundle creates a service whose id is logger. But it also adds an alias: Psr\Log\LoggerInterface that points to the logger service. This is why arguments type-hinted with Psr\Log\LoggerInterface can be autowired » so in your case the Psr\Log\LoggerInterface is an alias for Monolog https://symfony.com/doc/current/service_container/autowiring.html#using-aliases-to-enable-autowiring

It seems that the either the contents of services.yaml are not full.
Your services file should be like this
services:
logger:
class: Monolog\Logger
arguments: ["application"]
autowire: true
public: true
Monolog\Logger: '#logger'
plugin_context:
class: MyProject\PluginContext
autowire: true
public: true

Related

Symfony 6 - Class declared in services.yaml not found

I have a problem with registering a class as a service in services.yaml.
I have created a class MenuBuilder.php in Symfony 6 that looks somewhat like this.
src/Menu/MenuBuilder.php
namespace App\Menu;
class MenuBuilder
{
public function createMainMenu(array $options)
{
// method logic
}
}
Now, when I want to register it as a service: (and use it in twig with KnpMenuBundle)
config/services.yaml
parameters:
services:
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
App\:
resource: '../src/'
exclude:
- '../src/DependencyInjection/'
- '../src/Entity/'
- '../src/Kernel.php'
app.menu_builder:
class: App\Menu\MenuBuilder
arguments: [ "#knp_menu.factory" ]
tags:
- { name: knp_menu.menu_builder, method: createMainMenu, alias: main }
I get an error Class "App\Menu\MenuBuilder" not found.
I tried making some other classes (ex. Test/TestClass) and namespaces and it doesn't work with freshly created classes.
On the other hand it i fiddled around with the naming and it recognized my entities and factories.
I tried clearing the cache
I am in development mode
I am getting this message when calling {{ knp_menu_render('main') }} in twig.
My composer autoload:
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
symfony console debug:container app.menubuilder gives me this:
Information for Service "app.menu_builder"
==========================================
---------------- -------------------------------------------------------------
Option Value
---------------- -------------------------------------------------------------
Service ID app.menu_builder
Class App\Menu\MenuBuilder
Tags knp_menu.menu_builder (method: createMainMenu, alias: main)
Public no
Synthetic no
Lazy no
Shared yes
Abstract no
Autowired yes
Autoconfigured yes
Usages knp_menu.menu_provider.lazy
---------------- -------------------------------------------------------------
! [NOTE] The "app.menu_builder" service or alias has been removed or inlined when the container was compiled.
How do i get Symfony to recognize my classses?

Inject Symfony Service in a Bundle for Akeneo Pim

I am trying to inject a service from Akeneo to my selfwritten Bundle.
To be exact, i want to use the service defined here in my bundle instead of an Processor.
services:
_defaults:
autowire: true
autoconfigure: true
Acme\CategoryBuilder:
class: Acme\CategoryBuilder\CategoryBuilder
arguments:
- '#pim_catalog.repository.category'
tags:
- { name: kernel.event_listener, event: akeneo.storage.post_save, method: onPostSave }
and this constructor:
public function __construct(CategoryRepositoryInterface
$categoryRepositoryInterface){
$this->categoryRepositoryInterface = $categoryRepositoryInterface;
}
in a Class called CategoryBuilder.
This setup does not work and if i try to clear & warmup the cache, i get the Error Response that 0 arguments are passed but 1 was expected.
How can i pass this service to my Bundle?
Edit:
if i run: php bin/console debug:container pim_catalog.repository.category i get the following output:
Information for Service "pim_catalog.repository.category"
=========================================================
Category repository
----------------- ------------------------------------------------------------------------------------
Option Value
----------------- ------------------------------------------------------------------------------------
Service ID pim_catalog.repository.category
Class Akeneo\Tool\Bundle\ClassificationBundle\Doctrine\ORM\Repository\CategoryRepository
Tags pim_repository
Public no
Synthetic no
Lazy no
Shared yes
Abstract no
Autowired no
Autoconfigured no
Factory Service doctrine.orm.default_entity_manager
Factory Method getRepository
----------------- ------------------------------------------------------------------------------------
! [NOTE] The "pim_catalog.repository.category" service or alias has been removed or inlined when the container was
! compiled.
Does the Note mean i just cant get this Service? If so, how can i restore it?

Symfony cannot autowire service no such service exists

UPDATE
I moved a Command from CoreBundle to AssetBundle and forgot to change the namespace path. Simply renamed /CoreBundle/Command to /AssetBundle/Command and everything worked again.
I am getting an Symfony 4.4 autowire issue that i can not resolve.
This error is about a service being injected in a helper. The helper is for the the Exporter service. The exporter service is being build by dependency injection file and there is where the helpers are getting added.
This is the defaults in my Bundle service file
services:
_defaults:
autowire: true
autoconfigure: true
public: false
This is the helper with the tag that i use
X\ExportBundle\Service\Exporter\ExportColumn\Helper\AttributeHelper:
tags:
- { name: column_helper, alias: attribute_helper }
This is the interface for the helper
class AttributeHelper implements ExportColumnHelperInterface
This is the constructor of the helper
/**
* #param EntityManagerInterface $entityManager
* #param AssetManager $assetManager
*/
public function __construct(EntityManagerInterface $entityManager, AssetManager $assetManager)
{
$this->assetManager = $assetManager;
$this->entityManager = $entityManager;
}
This is the error i get
Cannot autowire service "X\ExportBundle\Service\Exporter\ExportColumn\Helper\AttributeHelper": argument "$assetManager" of method "__construct()" references class "X\AssetBundle\Service\Asset\AssetManager" but no such service exists.
Help is very much appreciated!
Add autowire: true to the service config in yaml

Symfony combine yaml and php configuration files

In Symfony 4, I would like to combine different configuration files for services. In the following scenario, my attempt is to import services from php configuration named services.php and then perform the other services configurations in the yaml file that imports the others services..
services.yaml
imports:
- { resource: services.php }
services:
_defaults:
autowire: true
autoconfigure: true
public: false
App\:
resource: '../src/*'
exclude: '../src/{Entity,Migrations,Tests,Kernel.php}'
services.php
<?php
use Symfony\Component\DependencyInjection\Definition;
$definition = new Definition();
$definition
->setAutowired(true)
->setAutoconfigured(true)
->setPublic(false)
;
$this->registerClasses($definition, 'App\\', '../src/*', '../src/{Entity,Migrations,Tests}');
$container->getDefinition(\App\SomeClass::class)
->setArgument('$param', 'someValue');
Class file
class SomeClass
{
public function __construct(string $param)
{
...
}
I get the following error:
Cannot autowire service
"App\SomeClass": argument "$param"
of method "__construct()" is type-hinted "string", you should
configure its value explicitly.
Also, I'm wondering if I have to necessary to overwrite the initial _defaults definition (or others already done in by the files that imports) from the yaml or I can inherit. Not sure how these files are all merged.
The problem is that you registering the classes in src/* twice, once in your services.php and once in your services.yaml.
So in the first run with services.php you correctly define the class and the required argument, then, in the second run with services.yaml the definition is being overwritten and it loses the argument again.
The minimal solution would be to exclude the SomeClass.php in the services.yaml so it won't be registered a second time:
App\:
resource: '../src/*'
exclude: '../src/{Entity,Migrations,Tests,Kernel.php,SomeClass.php}' # <- here I added SomeClass.php
It would be better though to create a separate namespace and exclude the directory in the YAML and only register this directory in the PHP-config.

Symfony 4 - The autoloader expected class […] to be defined in file

I'm trying to add an old Bundle that I have built on Symfony 3.* to Symfony 4 but I get this error:
The autoloader expected class
"App\SBC\TiersBundle\Controller\ChantierController" to be defined in
file
"/Applications/MAMP/htdocs/Projects/HelloSymfony4/vendor/composer/../../src/SBC/TiersBundle/Controller/ChantierController.php".
The file was found but the class was not in it, the class name or
namespace probably has a typo in
/Applications/MAMP/htdocs/Projects/HelloSymfony4/config/services.yaml
(which is loaded in resource
"/Applications/MAMP/htdocs/Projects/HelloSymfony4/config/services.yaml").
It seems like the framework did not recognise the namespace of the bundle so I did these steps:
In config/bundle.php I added the third line:
return [
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
\SBC\TiersBundle\TiersBundle::class => ['all' => true], // this one
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
];
And in composer.json I added the first line in autoload section:
"autoload": {
"psr-4": {
"SBC\\": "src/SBC/",
"App\\": "src/"
}
},
Because the namespace of my Bundle starts with SBC\, and I have launched composer dump-autoload in the console.
<?php
namespace SBC\TiersBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class TiersBundle extends Bundle
{
}
ChantierController.php:
namespace SBC\TiersBundle\Controller;
use SBC\TiersBundle\Entity\Chantier;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
class ChantierController extends Controller
{
...
}
And this is my Bundle under /src:
Unfortunately still facing the same error, how can I fix it and thanks in advance.
UPDATE: config/services.yaml:
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
public: false # Allows optimizing the container by removing unused services; this also means
# fetching services directly from the container via $container->get() won't work.
# The best practice is to be explicit about your dependencies anyway.
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
SBC\:
resource: '../src/SBC/*'
exclude: '../src/SBC/TiersBundle/{Entity,Migrations,Tests}'
SBC\TiersBundle\Controller\:
resource: '../src/SBC/TiersBundle/Controller'
tags: ['controller.service_arguments']
App\:
resource: '../src/*'
exclude: '../src/{Entity,Migrations,Tests}'
# controllers are imported separately to make sure services can be injected
# as action arguments even if you don't extend any base controller class
App\Controller\:
resource: '../src/Controller'
tags: ['controller.service_arguments']
# add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones
The problem is most likely caused by Symfony configuration and conflict in namespaces. First you need to adjust your config/services.yaml:
SBC\:
resource: '../src/SBC/*'
exclude: '../src/SBC/TiersBundle/{Entity,Migrations,Tests,Kernel.php}'
SBC\TiersBundle\Controller\:
resource: '../src/SBC/TiersBundle/Controller'
tags: ['controller.service_arguments']
App\:
resource: '../src/*'
exclude: '../src/{SBC,Entity,Migrations,Tests,Kernel.php}'
This way you'll define defaults for your namespace and prevent the default namespace App to include your directory when generating autoload classes. Note that if you are using annotation routes, you also need to adjust config/routes/annotations.yaml:
sbc_controllers:
resource: ../../src/SBC/TiersBundle/Controller/
type: annotation
so the routes are generated correctly. After performing these steps run composer dump-autoload again and clear Symfony's cache.
This might be helpful in the future if you run into another problems: https://github.com/symfony/symfony/blob/master/UPGRADE-4.0.md

Categories