Symfony cannot autowire service no such service exists - php

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

Related

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?

UserPasswordEncoderInterface Autowiring Not Working Symfony 4.4

I have a super basic API endpoint with a fresh install of symfony 4.4 and I'm getting the following error:
Cannot autowire argument $passwordEncoder of
"App\Controller\AuthenticationController::authenticateAction()": it
references interface
"Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface"
but no such service exists.
My Controller:
<?php
namespace App\Controller;
use App\Entity\User;
use FOS\RestBundle\Controller\AbstractFOSRestController;
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\Controller\Annotations\Route;
use Lexik\Bundle\JWTAuthenticationBundle\Encoder\JWTEncoderInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
/**
* Class AuthenticationController
*
* #package App\Controller
* #Route("/api/authentication")
*/
class AuthenticationController extends AbstractFOSRestController {
/**
* #Rest\Get("/authenticate")
*
* #param Request $request
* #param UserPasswordEncoderInterface $passwordEncoder
* #param JWTEncoderInterface $JWTEncoder
*
* #return Response
*/
public function authenticateAction (Request $request, UserPasswordEncoderInterface $passwordEncoder, JWTEncoderInterface $JWTEncoder) {
exit;
}
}
If I remove UserPasswordEncoderInterface $passwordEncoder I get a successful nothing (expected for now). My User Entity is nothing special, and extends UserInterface correctly.
services.yaml
# This file is the entry point to configure your own services.
# Files in the packages/ subdirectory configure your dependencies.
# 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.
# 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/DependencyInjection/'
- '../src/Entity/'
- '../src/Kernel.php'
- '../src/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
Using Symfony 4.4 and php 7.2.20
Almost certain this is some sort of configuration issue, but I'm not following what I did wrong.
Man am I smart, it was a config issue!
My security.yaml file was in main /config directory and not in the /config/packages directory. Ok maybe I'm not that smart...
Not sure how it got there. I think some out-dated package couldn't find it in the config/packages directory.
There goes 48 hours of my life...

Autowiring services in Symfony 4 (Too few arguments)

I do have simple command with constructor requiring LoggerInterface as dependency.
<?php
namespace App\Command;
// use (...)
class ProcessReportCommand extends Command
{
/** #var LoggerInterface */
private $logger;
public function __construct(LoggerInterface $logger)
{
parent::__construct();
$this->logger = $logger;
}
// (...)
}
My configuration in services.yml looks pretty default:
parameters:
services:
_defaults:
autowire: true
autoconfigure: true
public: false
App\:
resource: '../src/*'
exclude: '../src/{Entity,Migrations,Exception,Tests,Kernel.php}'
App\Controller\:
resource: '../src/Controller'
tags: ['controller.service_arguments']
Unfortunately I am getting PHP Error saying that dependency was not injected.
PHP Fatal error: Uncaught
Symfony\Component\Debug\Exception\FatalThrowableError: Type error: Too
few arguments to function
App\Command\ProcessReportCommand::__construct(), 0 passed in
/home/tomasz/project/bin/console on line 40 and exactly 1 expected in
/home/tomasz/project/src/Command/ProcessReportCommand.php:17
Even if I will switch this dependency to any other class which I have under App\ it behaves always like that.
I literally have no idea what should I do more to make it works, all ways even the one with including explicitly the service inside services.yml does not work for me. Any clues?
Did you clear the chache? php bin/console cache:clear.
If that does not work, what are the outputs of php bin/console debug:container Process?

Autowire not working in Symfony's Dependency Injection component

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

Autowire symfony CacheInterface depending on environment

I am trying to use different cache system on my environments. I would like to have, for example, Filesystem for dev and memcached for prod.
I am using symfony 3.3.10.
To achieve this, I would like to autowire the CacheInterface as follow:
use Psr\SimpleCache\CacheInterface;
class Api {
public function __construct(CacheInterface $cache)
{
$this->cache = $cache;
}
}
Here are my configuration files:
config_dev.yml:
framework:
cache:
app: cache.adapter.filesystem
config_prod.yml:
framework:
cache:
app: cache.adapter.memcached
...
Here is the error I get:
The error disappears when the FilesystemCache is declared as a service:
services:
Symfony\Component\Cache\Simple\FilesystemCache: ~
But now I cannot have another cache system for the test environment like NullCache. In fact, I have to declare only one service inheriting from CacheInterface. It is not possible as config_test is using config_dev too.
This is the beginning of services.yml if it can help:
services:
_defaults:
autowire: true
autoconfigure: true
public: false
Any idea on how to autowire different cache system depending on the environment?
EDIT:
Here is the working configuration:
use Psr\Cache\CacheItemPoolInterface;
class MyApi
{
/**
* #var CacheItemPoolInterface
*/
private $cache;
public function __construct(CacheItemPoolInterface $cache)
{
$this->cache = $cache;
}
}
config.yml:
framework:
# ...
cache:
pools:
app.cache.api:
default_lifetime: 3600
services.yml:
# ...
Psr\Cache\CacheItemPoolInterface:
alias: 'app.cache.api'
Even though factory pattern is a good option to solve this kind of problem, normally you don't need to do that for Symfony cache system. Typehints CacheItemPoolInterface instead:
use Psr\Cache\CacheItemPoolInterface;
public function __construct(CacheItemPoolInterface $cache)
It automatically injects the current cache.app service depending on the active environment, so Symfony does the job for you!
Just make sure to configure the framework.cache.app for each environment config file:
# app/config/config_test.yml
imports:
- { resource: config_dev.yml }
framework:
#...
cache:
app: cache.adapter.null
services:
cache.adapter.null:
class: Symfony\Component\Cache\Adapter\NullAdapter
arguments: [~] # small trick to avoid arguments errors on compile-time.
As cache.adapter.null service isn't available by default, you might need to define it manually.
In Symfony 3.3+/4 and 2017/2019 you can omit any config dependency and keep full control of the behavior with factory pattern:
// AppBundle/Cache/CacheFactory.php
namespace AppBundle\Cache;
final class CacheFactory
{
public function create(string $environment): CacheInterface
{
if ($environment === 'prod') {
// do this
return new ...;
}
// default
return new ...;
}
}
And services.yml of course:
# app/config/services.yml
services:
Psr\SimpleCache\CacheInterface:
factory: 'AppBundle\Cache\CacheFactory:create'
arguments: ['%kernel.environment%']
See more about service factory in Symfony Documentation.
You can read more about this in my Why Config Coding Sucks post.

Categories